Posts: 245
Threads: 79
Joined: Feb 2013
01-02-2014, 08:57
(This post was last modified: 01-02-2014, 08:57 by [HARD] Tony..)
(01-02-2014, 08:46)master131 Wrote: (01-02-2014, 08:38)[HARD] Tony. Wrote: I think would be cheerful if to add bots. they are OnNotify(joined_spectators). it would be cheerful, better than to play with people here an example.
http://youtu.be/UqPO8Rofb0g
Will do. Also, I edited Timing.cs again because the correct way to solve the issue is mentioned here on MSDN using a GCHandle:
http://msdn.microsoft.com/en-us/library/367eeye0.aspx
EDIT - The GSC function AddTestClient is null-sub'ed, aka, it's been emptied out so it does absolutely nothing. I remember @NTAuthority made an modification which allowed it, will dig in and figure it out.
EDIT #2 - This looks like quite a bit of work to do, there's alot for me to patch and port to C#, I'll do it when I have time, I'm currently working on something else right now that's not MW3 related. YOU convert a code with C++ on #?
or you want to add them in addon?
Posts: 719
Threads: 69
Joined: Nov 2010
Reputation:
76
01-02-2014, 09:04
(This post was last modified: 01-02-2014, 09:05 by master131.)
(01-02-2014, 08:57)[HARD] Tony. Wrote: (01-02-2014, 08:46)master131 Wrote: (01-02-2014, 08:38)[HARD] Tony. Wrote: I think would be cheerful if to add bots. they are OnNotify(joined_spectators). it would be cheerful, better than to play with people here an example.
http://youtu.be/UqPO8Rofb0g
Will do. Also, I edited Timing.cs again because the correct way to solve the issue is mentioned here on MSDN using a GCHandle:
http://msdn.microsoft.com/en-us/library/367eeye0.aspx
EDIT - The GSC function AddTestClient is null-sub'ed, aka, it's been emptied out so it does absolutely nothing. I remember @NTAuthority made an modification which allowed it, will dig in and figure it out.
EDIT #2 - This looks like quite a bit of work to do, there's alot for me to patch and port to C#, I'll do it when I have time, I'm currently working on something else right now that's not MW3 related. YOU convert a code with C++ on #?
or you want to add them in addon?
I'm not going to make a custom version of the addon, I'm going to port the bots code to C#.
A casual conversation between barata and I about Nukem.
Posts: 245
Threads: 79
Joined: Feb 2013
(01-02-2014, 09:04)master131 Wrote: (01-02-2014, 08:57)[HARD] Tony. Wrote: (01-02-2014, 08:46)master131 Wrote: (01-02-2014, 08:38)[HARD] Tony. Wrote: I think would be cheerful if to add bots. they are OnNotify(joined_spectators). it would be cheerful, better than to play with people here an example.
http://youtu.be/UqPO8Rofb0g
Will do. Also, I edited Timing.cs again because the correct way to solve the issue is mentioned here on MSDN using a GCHandle:
http://msdn.microsoft.com/en-us/library/367eeye0.aspx
EDIT - The GSC function AddTestClient is null-sub'ed, aka, it's been emptied out so it does absolutely nothing. I remember @NTAuthority made an modification which allowed it, will dig in and figure it out.
EDIT #2 - This looks like quite a bit of work to do, there's alot for me to patch and port to C#, I'll do it when I have time, I'm currently working on something else right now that's not MW3 related. YOU convert a code with C++ on #?
or you want to add them in addon?
I'm not going to make a custom version of the addon, I'm going to port the bots code to C#.
Thanks
Posts: 299
Threads: 1
Joined: Aug 2013
Reputation:
10
Thanks.
Posts: 719
Threads: 69
Joined: Nov 2010
Reputation:
76
01-02-2014, 18:53
(This post was last modified: 01-03-2014, 01:48 by master131.)
Here's TestClients.cs, I haven't gotten around to making the bots properly spawn, but they appear as spectators when you call TestClients.AddTestClient. Credits go to @ NTAuthority for the original code for IW5M.
<removed, check main post>
A casual conversation between barata and I about Nukem.
Posts: 245
Threads: 79
Joined: Feb 2013
01-02-2014, 19:05
(This post was last modified: 01-02-2014, 19:46 by [HARD] Tony..)
(01-02-2014, 18:53)master131 Wrote: Here's TestClients.cs, I haven't gotten around to making the bots properly spawn, but they appear as spectators when you call TestClients.AddTestClient. Credits go to @NTAuthority for the original code for IW5M.
Code: using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Addon
{
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 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);
// Call SV_SendClientGameState
SvSendClientGameState(botClient);
// SV_ClientEnterWorld
SvClientEnterWorld(botClient, new byte[44]);
// Return client num.
return index;
}
}
}
full help
well, but I can't test today it (I have already 10 o'clock in the morning,. ) tomorrow I will get up and I will test it. ....
Posts: 299
Threads: 1
Joined: Aug 2013
Reputation:
10
ok so how do i run the bots code??
Posts: 245
Threads: 79
Joined: Feb 2013
(01-02-2014, 19:38)Casper Wrote: ok so how do i run the bots code??
TestClients.AddTestClient
Posts: 3,704
Threads: 147
Joined: Jan 2011
Reputation:
119
Hahaha, "connect" string. I didn't knew that bots using this way.
C++/Obj-Cdeveloper. Neko engine wip
Steam: Click
Posts: 299
Threads: 1
Joined: Aug 2013
Reputation:
10
well the code works. but yea they only appear as spectators.
|