• 9 Vote(s) - 4.56 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Release] MW3 Server Addon Extensions
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 Sad .
As I wanted to give to bots or the similar weapon, it is possible?
  Reply
Thanks @master131 for all your hard work.
~FYANB~ Servers Website

Primary Account:
[Image: 76561198070236721.png]
Secondary Account:
[Image: 76561198096107676.png]
Third Account:
[Image: 76561198164751656.png]
  Reply
(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 Sad .
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...
  Reply
Because they act like clients and take up your slots.
~FYANB~ Servers Website

Primary Account:
[Image: 76561198070236721.png]
Secondary Account:
[Image: 76561198096107676.png]
Third Account:
[Image: 76561198164751656.png]
  Reply
Just kick the bots in the console then? Dodgy
[Image: 30xhrep.png]

A casual conversation between barata and I about Nukem.
  Reply
Wink 
@master131 , you couldn't add function killplayer() and playersuicede?
it would be the invaluable help, very great, @addon414 crash each 30 minutes...
  Reply
(01-04-2014, 01:37)master131 Wrote: Just kick the bots in the console then? Dodgy

don't work
  Reply
@master131

could you possibly add an option so that a set amount can be forced to go on a certain side ie: Axis
[Image: b_560_95_1.png]


[Image: b_560_95_1.png]

  Reply
@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..
~FYANB~ Servers Website

Primary Account:
[Image: 76561198070236721.png]
Secondary Account:
[Image: 76561198096107676.png]
Third Account:
[Image: 76561198164751656.png]
  Reply
(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.
  Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Help, server Admin largosik 0 2,066 02-02-2019, 18:09
Last Post: largosik
  Add a point shop to my server h1dexyz 1 2,825 03-04-2018, 22:36
Last Post: h1dexyz
Lightbulb Preview Weapon Classe For Infected Clasic Server groochu1982 0 2,211 02-19-2017, 08:35
Last Post: groochu1982
Exclamation Help HOW CAN I TURN OFF THE "CROSSHAIR" IN MY SERVER? Eliichong0 0 2,502 06-16-2016, 16:01
Last Post: Eliichong0
Bug Upload files to FTP server S3VDIT0 4 4,174 01-28-2016, 17:17
Last Post: S3VDIT0

Forum Jump:


Users browsing this thread: 5 Guest(s)