Posts: 245
Threads: 79
Joined: Feb 2013
01-03-2014, 17:50
(This post was last modified: 01-03-2014, 17:50 by [HARD] Tony..)
sorry I didn't know. it very much a lot of work, but I thought it is possible to use bots from a survival.
by the way why when I made 17 bots and I my friends couldn't be connected to me with a mistake the server is overflowed .
As I wanted to give to bots or the similar weapon, it is possible?
Posts: 299
Threads: 1
Joined: Aug 2013
Reputation:
10
Thanks @ master131 for all your hard work.
Posts: 539
Threads: 39
Joined: Dec 2010
Reputation:
49
(01-03-2014, 17:50)[HARD] Tony. Wrote: sorry I didn't know. it very much a lot of work, but I thought it is possible to use bots from a survival.
by the way why when I made 17 bots and I my friends couldn't be connected to me with a mistake the server is overflowed .
As I wanted to give to bots or the similar weapon, it is possible?
Why wouldn't it? Just search around...
Thanks Barata...
Don't worry if things aren't the way you planned, in the end everything will solve itself...
Posts: 299
Threads: 1
Joined: Aug 2013
Reputation:
10
Because they act like clients and take up your slots.
Posts: 719
Threads: 69
Joined: Nov 2010
Reputation:
76
Just kick the bots in the console then?
A casual conversation between barata and I about Nukem.
Posts: 245
Threads: 79
Joined: Feb 2013
01-04-2014, 17:19
@ master131 , you couldn't add function killplayer() and playersuicede?
it would be the invaluable help, very great, @addon414 crash each 30 minutes...
Posts: 245
Threads: 79
Joined: Feb 2013
(01-04-2014, 01:37)master131 Wrote: Just kick the bots in the console then?
don't work
Posts: 836
Threads: 48
Joined: Feb 2012
Reputation:
11
01-13-2014, 12:44
(This post was last modified: 01-13-2014, 12:48 by hillbilly.)
@ master131
could you possibly add an option so that a set amount can be forced to go on a certain side ie: Axis
Posts: 299
Threads: 1
Joined: Aug 2013
Reputation:
10
@ master131 is there a way you could add a remove clients for those bots, cause kicking them just kicks them it doesn't free slots up in the server
Like: TestClients.RemoveBot(client); for on like map change so they don't stay and you can get people in the server next round.
Anyways Thanks..
Posts: 273
Threads: 14
Joined: Aug 2012
Reputation:
17
(01-21-2014, 03:17)Casper Wrote: @master131 is there a way you could add a remove clients for those bots, cause kicking them just kicks them it doesn't free slots up in the server
Like: TestClients.RemoveBot(client); for on like map change so they don't stay and you can get people in the server next round.
Anyways Thanks..
Code: using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Addon;
namespace Addon
{
public static class TestClients
{
#region Hooking Functions
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
private const uint MEM_COMMIT = 0x1000;
private const uint MEM_RESERVE = 0x2000;
private const uint PAGE_EXECUTE_READWRITE = 0x40;
private static readonly List<GCHandle> GCHandles = new List<GCHandle>();
private static void PerformJmpHook(IntPtr original, byte[] destinationStub)
{
var stubAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)destinationStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Marshal.Copy(destinationStub, 0, stubAddress, destinationStub.Length);
PerformJmpHook(original, stubAddress);
}
private static void PerformJmpHook(IntPtr original, IntPtr destination)
{
uint oldProtect;
VirtualProtect(original, (UIntPtr)5, PAGE_EXECUTE_READWRITE, out oldProtect);
var hook = new byte[5];
hook[0] = 0xE9;
BitConverter.GetBytes((destination.ToInt32() - original.ToInt32()) - 5).CopyTo(hook, 1);
Marshal.Copy(hook, 0, original, hook.Length);
VirtualProtect(original, (UIntPtr)5, oldProtect, out oldProtect);
}
private static IntPtr GetUnmanagedFunctionPointerFromDelegate(Delegate d)
{
GCHandles.Add(GCHandle.Alloc(d));
return Marshal.GetFunctionPointerForDelegate(d);
}
#endregion
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool SvCheckClientDelegate(IntPtr clientPart);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int FuncIntDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate void SvCmdTokenizeStringDelegate(string str);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SvDirectConnectDelegate(netaddr_t adr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SvSendClientGameStateDelegate(IntPtr client);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SvClientEnterWorldDelegate(IntPtr client, byte[] userCmd);
private static readonly IntPtr SvCheckTimeoutAddress = (IntPtr)0x4FE8A0;
private static readonly IntPtr SteamCheckSvAuthAddress = (IntPtr)0x599D20;
private static readonly IntPtr ResetReliableCmdAddress = (IntPtr)0x5029DB;
private static readonly IntPtr SvMaxClientsDvarPtr = (IntPtr)0x5787780;
private static readonly IntPtr ClientAddress = (IntPtr)0x4A0FE90;
private static readonly IntPtr GetStatMajorAddress = (IntPtr)0x4D0560;
private static readonly IntPtr GetStatMinorAddress = (IntPtr)0x4D05A0;
private static readonly IntPtr GetChecksumAddress = (IntPtr)0x40C8C0;
private static readonly IntPtr SvDirectConnectAddress = (IntPtr)0x4F7670;
private static readonly IntPtr SvCmdArgsAddress = (IntPtr)0x1B5B7D8;
private static readonly FuncIntDelegate GetStatMajor;
private static readonly FuncIntDelegate GetStatMinor;
private static readonly FuncIntDelegate GetChecksum;
private static readonly SvCmdTokenizeStringDelegate SvCmdTokenizeString;
private static readonly SvDirectConnectDelegate SvDirectConnect;
private static readonly SvSendClientGameStateDelegate SvSendClientGameState;
private static readonly SvClientEnterWorldDelegate SvClientEnterWorld;
private static ushort BotPort;
private static byte[] SvCheckTimeoutHookStub = new byte[]
{
0x56, // push esi
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <handler>
0xFF, 0xD0, // call eax
0x83, 0xC4, 0x04, // add esp, 4
0x84, 0xC0, // test al, al
0x68, 0xA7, 0xE8, 0x4F, 0x00, // push 4FE8A7h
0xC3, // retn
};
private static byte[] SteamCheckSvAuthHookStub = new byte[]
{
0x56, // push esi
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <handler>
0xFF, 0xD0, // call eax
0x83, 0xC4, 0x04, // add esp, 4
0x84, 0xC0, // test al, al
0x75, 0x06, // jnz short continueSteamCheck
0x68, 0xBC, 0x9D, 0x59, 0x00, // push 599DBCh
0xC3, // retn
// continueSteamCheck:
0x68, 0x2D, 0x9D, 0x59, 0x00, // push 599D2Dh
0xC3, // retn
};
private static byte[] ResetReliableCmdHookStub = new byte[]
{
0x80, 0xBE, 0xC0, 0x52, 0x04, 0x00, 0xFF, // cmp byte ptr [esi+452C0h], 0FFh
0x75, 0x0C, // jnz short doReturn
0x8B, 0x86, 0x70, 0x0E, 0x02, 0x00, // mov eax, [esi+20E70h]
0x89, 0x86, 0x74, 0x0E, 0x02, 0x00, // mov [esi+20E74h], eax
// doReturn:
0x83, 0x3D, 0x9C, 0x1F, 0x2F, 0x06, 0x00, // cmp dword ptr [62F1F9C], 0
0x68, 0xE2, 0x29, 0x50, 0x00, // push 5029E2h
0xC3 // retn
};
private static byte[] SvCmdTokenizeStringStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x56, // push esi
0x51, // push ecx
0xB8, 0x00, 0x02, 0x00, 0x00, // mov eax, 200
0x2B, 0x05, 0xD0, 0xAF, 0xB4, 0x01, // sub eax, dword ptr [1B4AFD0]
0x50, // push eax
0xFF, 0x75, 0x08, // push [ebp+8]
0xB9, 0xB0, 0x87, 0xB4, 0x01, // mov ecx, 1B487B0
0xBE, 0xD8, 0xB7, 0xB5, 0x01, // mov esi, 1B5B7D8
0xB8, 0x00, 0xC1, 0x4C, 0x00, // mov eax, 4CC100
0xFF, 0xD0, // call eax
0x83, 0xC4, 0x08, // add esp, 8
0x59, // pop ecx
0x5E, // pop esi
0x5D, // pop ebp
0xC3 // retn
};
private static readonly byte[] SvSendClientGameStateStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x51, // push ecx
0xB9, 0x40, 0x8D, 0x4F, 0x00, // mov ecx, 4F8D40
0x8B, 0x45, 0x08, // mov eax, [ebp+8]
0xFF, 0xD1, // call ecx
0x59, // pop ecx
0x5D, // pop ebp
0xC3 // retn
};
private static readonly byte[] SvClientEnterWorldStub = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x52, // push edx
0xB8, 0xC0, 0x8F, 0x4F, 0x00, // mov eax, 4F8FC0
0xFF, 0x75, 0x08, // push [ebp+8]
0x8B, 0x55, 0x0C, // mov edx, [ebp+C]
0xFF, 0xD0, // call eax
0x83, 0xC4, 0x04, // add esp, 4
0x5A, // pop edx
0x5D, // pop ebp
0xC3 // retn
};
[StructLayout(LayoutKind.Sequential)]
struct netaddr_t
{
public int type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] ip;
public ushort port;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] ipx;
}
static TestClients()
{
// Hook required methods.
var svCheckTimeoutFuncAddress = GetUnmanagedFunctionPointerFromDelegate(
new SvCheckClientDelegate(SvCheckTimeoutFunc));
BitConverter.GetBytes(svCheckTimeoutFuncAddress.ToInt32()).CopyTo(SvCheckTimeoutHookStub, 2);
PerformJmpHook(SvCheckTimeoutAddress, SvCheckTimeoutHookStub);
var steamCheckSvAuthFuncAddress = GetUnmanagedFunctionPointerFromDelegate(
new SvCheckClientDelegate(SteamCheckSvAuthFunc));
BitConverter.GetBytes(steamCheckSvAuthFuncAddress.ToInt32()).CopyTo(SteamCheckSvAuthHookStub, 2);
PerformJmpHook(SteamCheckSvAuthAddress, SteamCheckSvAuthHookStub);
PerformJmpHook(ResetReliableCmdAddress, ResetReliableCmdHookStub);
// Prepare function delegates.
GetStatMajor = (FuncIntDelegate)Marshal.GetDelegateForFunctionPointer(GetStatMajorAddress, typeof(FuncIntDelegate));
GetStatMinor = (FuncIntDelegate)Marshal.GetDelegateForFunctionPointer(GetStatMinorAddress, typeof(FuncIntDelegate));
GetChecksum = (FuncIntDelegate)Marshal.GetDelegateForFunctionPointer(GetChecksumAddress, typeof(FuncIntDelegate));
SvDirectConnect = (SvDirectConnectDelegate)Marshal.GetDelegateForFunctionPointer(SvDirectConnectAddress, typeof(SvDirectConnectDelegate));
var svCmdTokenizeStringAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)SvCmdTokenizeStringStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Marshal.Copy(SvCmdTokenizeStringStub, 0, svCmdTokenizeStringAddress, SvCmdTokenizeStringStub.Length);
SvCmdTokenizeString = (SvCmdTokenizeStringDelegate)Marshal.GetDelegateForFunctionPointer(svCmdTokenizeStringAddress, typeof(SvCmdTokenizeStringDelegate));
var svSendClientGameStateAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)SvSendClientGameStateStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Marshal.Copy(SvSendClientGameStateStub, 0, svSendClientGameStateAddress, SvSendClientGameStateStub.Length);
SvSendClientGameState = (SvSendClientGameStateDelegate)Marshal.GetDelegateForFunctionPointer(svSendClientGameStateAddress, typeof(SvSendClientGameStateDelegate));
var svClientEnterWorldAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)SvClientEnterWorldStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Marshal.Copy(SvClientEnterWorldStub, 0, svClientEnterWorldAddress, SvClientEnterWorldStub.Length);
SvClientEnterWorld = (SvClientEnterWorldDelegate)Marshal.GetDelegateForFunctionPointer(svClientEnterWorldAddress, typeof(SvClientEnterWorldDelegate));
}
private static bool SvCheckTimeoutFunc(IntPtr clientPart)
{
var client = (IntPtr)(clientPart.ToInt32() - 136300);
return Marshal.ReadInt32(client, -136260) != 2 &&
(Marshal.ReadInt32(client) == 1 || Marshal.ReadInt32(client, 283328) != -1);
}
private static bool SteamCheckSvAuthFunc(IntPtr clientPart)
{
var client = (IntPtr)(clientPart.ToInt32() - 283325);
return Marshal.ReadInt32(client) >= 5 && Marshal.ReadInt32(client, 283328) != -1;
}
private static IntPtr GetClientFromNum(int clientNum)
{
return (IntPtr)(ClientAddress.ToInt32() + clientNum * 0x78690);
}
private static void SvCmdEndTokenizedString()
{
var argsIndex = Marshal.ReadInt32(SvCmdArgsAddress);
var addr = (IntPtr)0x1B4AFD0;
var value = Marshal.ReadInt32(addr);
var arrValue = Marshal.ReadInt32((IntPtr)0x1B5B81C, argsIndex * 4);
Marshal.WriteInt32(addr, value - arrValue);
addr = (IntPtr)0x1B4AFD4;
value = Marshal.ReadInt32(addr);
arrValue = Marshal.ReadInt32((IntPtr)0x1B4AFB0, argsIndex * 4);
argsIndex--;
Marshal.WriteInt32(SvCmdArgsAddress, argsIndex);
}
private static void Memset(IntPtr ptr, int value, int length)
{
var b = (byte)value;
for (int i = 0; i < length; i++)
Marshal.WriteByte(ptr, i, b);
}
public static void ConnectBot(ServerClient client)
{
if (!IsBot(client))
return;
ConnectBot(GetClientFromNum(client.ClientNum));
}
private static void ConnectBot(IntPtr clientAddress)
{
// Call SV_SendClientGameState
SvSendClientGameState(clientAddress);
// SV_ClientEnterWorld
SvClientEnterWorld(clientAddress, new byte[44]);
}
public static void RemoveBot(int ClientNum)
{
Marshal.WriteInt32((IntPtr)(0x4A0FE90 + ClientNum * 0x78690), 0);
}
public static bool IsBot(ServerClient client)
{
var clientAddress = GetClientFromNum(client.ClientNum);
return Marshal.ReadInt32(clientAddress, 283328) == -1;
}
public static int AddTestClient()
{
// Read the sv_maxclients dvar value.
var maxClients = Marshal.ReadInt32(Marshal.ReadIntPtr(SvMaxClientsDvarPtr), 0xC);
// Look for a free slot.
int index = 0;
for (index = 0; index < maxClients; index++)
{
if (Marshal.ReadInt32(GetClientFromNum(index)) == 0)
break;
}
// No slots available.
if (index == maxClients)
return -1;
// Prepare connection string.
const int protocol = 20601; // as of 1.9.461
var connectString = string.Format(
"connect bot{0} \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\bot{0}\\protocol\\{1}\\checksum\\{2}\\statver\\{3} {4}\\qport\\{5}\"",
BotPort, protocol, GetChecksum(),
GetStatMajor(), (uint)GetStatMinor(),
BotPort + 1);
// Handle client connection.
var botAdr = new netaddr_t { port = BotPort };
SvCmdTokenizeString(connectString.PadRight(1023, '\0'));
SvDirectConnect(botAdr);
SvCmdEndTokenizedString();
BotPort++;
// Get the bot's client number and client address.
index = 0;
IntPtr botClient = IntPtr.Zero;
for (index = 0; index < maxClients; index++)
{
if (Marshal.ReadInt32(botClient = GetClientFromNum(index)) == 0)
continue;
var clientAdr = (netaddr_t)Marshal.PtrToStructure((IntPtr)(botClient.ToInt32() + 40), typeof(netaddr_t));
if (clientAdr.type == botAdr.type && clientAdr.port == botAdr.port)
break;
}
// Failed for some reason.
if (index == maxClients)
return -1;
// Set the "bot" flag (actually the lower dword of the steam id)
Marshal.WriteInt32(botClient, 283328, -1);
// Set stat flags to "already set"
Marshal.WriteInt16(botClient, 283322, 0x3FF);
Memset((IntPtr)(botClient.ToInt32() + 269497), 0, 0x2FFC);
Memset((IntPtr)(botClient.ToInt32() + 281785), 0, 0x600);
// Connect the bots as spectators.
ConnectBot(botClient);
// Return client num.
return index;
}
}
}
I'm not quite sure if it will work for normal clients, I only tested it with bots.
Try to first kick the bot (ServerCommand("kickclient " + clientnum)) and then TestClient.RemoveBot(clientNum). If there is a better solution (I'm pretty sure there is) please let me know.
the code is obviously by @ master131 , I only added the RemoveBot function.
|