Merge.
Merge.
1.1 --- a/extensions/cstrike/AMBuilder Sun Jun 26 10:54:12 2011 -0400
1.2 +++ b/extensions/cstrike/AMBuilder Sun Jun 26 18:09:55 2011 -0400
1.3 @@ -15,7 +15,10 @@
1.4 'natives.cpp',
1.5 'RegNatives.cpp',
1.6 'timeleft.cpp',
1.7 - 'sdk/smsdk_ext.cpp'
1.8 + 'forwards.cpp',
1.9 + 'sdk/smsdk_ext.cpp',
1.10 + 'CDetour/detours.cpp',
1.11 + 'asm/asm.c'
1.12 ])
1.13 SM.PostSetupHL2Job(extension, binary, 'ep2v')
1.14 SM.AutoVersion('extensions/cstrike', binary)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/extensions/cstrike/CDetour/detourhelpers.h Sun Jun 26 18:09:55 2011 -0400
2.3 @@ -0,0 +1,98 @@
2.4 +/**
2.5 + * vim: set ts=4 :
2.6 + * =============================================================================
2.7 + * SourceMod
2.8 + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
2.9 + * =============================================================================
2.10 + *
2.11 + * This program is free software; you can redistribute it and/or modify it under
2.12 + * the terms of the GNU General Public License, version 3.0, as published by the
2.13 + * Free Software Foundation.
2.14 + *
2.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
2.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
2.18 + * details.
2.19 + *
2.20 + * You should have received a copy of the GNU General Public License along with
2.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
2.22 + *
2.23 + * As a special exception, AlliedModders LLC gives you permission to link the
2.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
2.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
2.26 + * by the Valve Corporation. You must obey the GNU General Public License in
2.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
2.28 + * this exception to all derivative works. AlliedModders LLC defines further
2.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
2.30 + * or <http://www.sourcemod.net/license.php>.
2.31 + *
2.32 + * Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
2.33 + */
2.34 +
2.35 +#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
2.36 +#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
2.37 +
2.38 +#if defined PLATFORM_POSIX
2.39 +#include <sys/mman.h>
2.40 +#define PAGE_SIZE 4096
2.41 +#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
2.42 +#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
2.43 +#endif
2.44 +
2.45 +struct patch_t
2.46 +{
2.47 + patch_t()
2.48 + {
2.49 + patch[0] = 0;
2.50 + bytes = 0;
2.51 + }
2.52 + unsigned char patch[20];
2.53 + size_t bytes;
2.54 +};
2.55 +
2.56 +inline void ProtectMemory(void *addr, int length, int prot)
2.57 +{
2.58 +#if defined PLATFORM_POSIX
2.59 + void *addr2 = (void *)ALIGN(addr);
2.60 + mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
2.61 +#elif defined PLATFORM_WINDOWS
2.62 + DWORD old_prot;
2.63 + VirtualProtect(addr, length, prot, &old_prot);
2.64 +#endif
2.65 +}
2.66 +
2.67 +inline void SetMemPatchable(void *address, size_t size)
2.68 +{
2.69 + ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
2.70 +}
2.71 +
2.72 +inline void DoGatePatch(unsigned char *target, void *callback)
2.73 +{
2.74 + SetMemPatchable(target, 20);
2.75 +
2.76 + target[0] = 0xFF; /* JMP */
2.77 + target[1] = 0x25; /* MEM32 */
2.78 + *(void **)(&target[2]) = callback;
2.79 +}
2.80 +
2.81 +inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
2.82 +{
2.83 + ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE);
2.84 +
2.85 + unsigned char *addr = (unsigned char *)address + offset;
2.86 + if (restore)
2.87 + {
2.88 + for (size_t i=0; i<patch->bytes; i++)
2.89 + {
2.90 + restore->patch[i] = addr[i];
2.91 + }
2.92 + restore->bytes = patch->bytes;
2.93 + }
2.94 +
2.95 + for (size_t i=0; i<patch->bytes; i++)
2.96 + {
2.97 + addr[i] = patch->patch[i];
2.98 + }
2.99 +}
2.100 +
2.101 +#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/extensions/cstrike/CDetour/detours.cpp Sun Jun 26 18:09:55 2011 -0400
3.3 @@ -0,0 +1,192 @@
3.4 +/**
3.5 +* vim: set ts=4 :
3.6 +* =============================================================================
3.7 +* SourceMod
3.8 +* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
3.9 +* =============================================================================
3.10 +*
3.11 +* This program is free software; you can redistribute it and/or modify it under
3.12 +* the terms of the GNU General Public License, version 3.0, as published by the
3.13 +* Free Software Foundation.
3.14 +*
3.15 +* This program is distributed in the hope that it will be useful, but WITHOUT
3.16 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.17 +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
3.18 +* details.
3.19 +*
3.20 +* You should have received a copy of the GNU General Public License along with
3.21 +* this program. If not, see <http://www.gnu.org/licenses/>.
3.22 +*
3.23 +* As a special exception, AlliedModders LLC gives you permission to link the
3.24 +* code of this program (as well as its derivative works) to "Half-Life 2," the
3.25 +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
3.26 +* by the Valve Corporation. You must obey the GNU General Public License in
3.27 +* all respects for all other code used. Additionally, AlliedModders LLC grants
3.28 +* this exception to all derivative works. AlliedModders LLC defines further
3.29 +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
3.30 +* or <http://www.sourcemod.net/license.php>.
3.31 +*
3.32 +* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
3.33 +*/
3.34 +
3.35 +#include "detours.h"
3.36 +#include <asm/asm.h>
3.37 +
3.38 +ISourcePawnEngine *CDetourManager::spengine = NULL;
3.39 +IGameConfig *CDetourManager::gameconf = NULL;
3.40 +
3.41 +void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
3.42 +{
3.43 + CDetourManager::spengine = spengine;
3.44 + CDetourManager::gameconf = gameconf;
3.45 +}
3.46 +
3.47 +CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
3.48 +{
3.49 + CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
3.50 + if (detour)
3.51 + {
3.52 + if (!detour->Init(spengine, gameconf))
3.53 + {
3.54 + delete detour;
3.55 + return NULL;
3.56 + }
3.57 +
3.58 + return detour;
3.59 + }
3.60 +
3.61 + return NULL;
3.62 +}
3.63 +
3.64 +CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
3.65 +{
3.66 + enabled = false;
3.67 + detoured = false;
3.68 + detour_address = NULL;
3.69 + detour_trampoline = NULL;
3.70 + this->signame = signame;
3.71 + this->detour_callback = callbackfunction;
3.72 + spengine = NULL;
3.73 + gameconf = NULL;
3.74 + this->trampoline = trampoline;
3.75 +}
3.76 +
3.77 +bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
3.78 +{
3.79 + this->spengine = spengine;
3.80 + this->gameconf = gameconf;
3.81 +
3.82 + if (!CreateDetour())
3.83 + {
3.84 + enabled = false;
3.85 + return enabled;
3.86 + }
3.87 +
3.88 + enabled = true;
3.89 +
3.90 + return enabled;
3.91 +}
3.92 +
3.93 +void CDetour::Destroy()
3.94 +{
3.95 + DeleteDetour();
3.96 + delete this;
3.97 +}
3.98 +
3.99 +bool CDetour::IsEnabled()
3.100 +{
3.101 + return enabled;
3.102 +}
3.103 +
3.104 +bool CDetour::CreateDetour()
3.105 +{
3.106 + if (!gameconf->GetMemSig(signame, &detour_address))
3.107 + {
3.108 + g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
3.109 + return false;
3.110 + }
3.111 +
3.112 + if (!detour_address)
3.113 + {
3.114 + g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame);
3.115 + return false;
3.116 + }
3.117 +
3.118 + detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
3.119 +
3.120 + /* First, save restore bits */
3.121 + for (size_t i=0; i<detour_restore.bytes; i++)
3.122 + {
3.123 + detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
3.124 + }
3.125 +
3.126 + JitWriter wr;
3.127 + JitWriter *jit = ≀
3.128 + jit_uint32_t CodeSize = 0;
3.129 +
3.130 + wr.outbase = NULL;
3.131 + wr.outptr = NULL;
3.132 +
3.133 +jit_rewind:
3.134 +
3.135 + /* Patch old bytes in */
3.136 + if (wr.outbase != NULL)
3.137 + {
3.138 + copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes);
3.139 + }
3.140 + wr.outptr += detour_restore.bytes;
3.141 +
3.142 + /* Return to the original function */
3.143 + jitoffs_t call = IA32_Jump_Imm32(jit, 0);
3.144 + IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
3.145 +
3.146 + if (wr.outbase == NULL)
3.147 + {
3.148 + CodeSize = wr.get_outputpos();
3.149 + wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize);
3.150 + spengine->SetReadWrite(wr.outbase);
3.151 + wr.outptr = wr.outbase;
3.152 + detour_trampoline = wr.outbase;
3.153 + goto jit_rewind;
3.154 + }
3.155 +
3.156 + spengine->SetReadExecute(wr.outbase);
3.157 +
3.158 + *trampoline = detour_trampoline;
3.159 +
3.160 + return true;
3.161 +}
3.162 +
3.163 +void CDetour::DeleteDetour()
3.164 +{
3.165 + if (detoured)
3.166 + {
3.167 + DisableDetour();
3.168 + }
3.169 +
3.170 + if (detour_trampoline)
3.171 + {
3.172 + /* Free the allocated trampoline memory */
3.173 + spengine->FreePageMemory(detour_trampoline);
3.174 + detour_trampoline = NULL;
3.175 + }
3.176 +}
3.177 +
3.178 +void CDetour::EnableDetour()
3.179 +{
3.180 + if (!detoured)
3.181 + {
3.182 + DoGatePatch((unsigned char *)detour_address, &detour_callback);
3.183 + detoured = true;
3.184 + }
3.185 +}
3.186 +
3.187 +void CDetour::DisableDetour()
3.188 +{
3.189 + if (detoured)
3.190 + {
3.191 + /* Remove the patch */
3.192 + ApplyPatch(detour_address, 0, &detour_restore, NULL);
3.193 + detoured = false;
3.194 + }
3.195 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/extensions/cstrike/CDetour/detours.h Sun Jun 26 18:09:55 2011 -0400
4.3 @@ -0,0 +1,241 @@
4.4 +/**
4.5 +* vim: set ts=4 :
4.6 +* =============================================================================
4.7 +* SourceMod
4.8 +* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
4.9 +* =============================================================================
4.10 +*
4.11 +* This program is free software; you can redistribute it and/or modify it under
4.12 +* the terms of the GNU General Public License, version 3.0, as published by the
4.13 +* Free Software Foundation.
4.14 +*
4.15 +* This program is distributed in the hope that it will be useful, but WITHOUT
4.16 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4.17 +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
4.18 +* details.
4.19 +*
4.20 +* You should have received a copy of the GNU General Public License along with
4.21 +* this program. If not, see <http://www.gnu.org/licenses/>.
4.22 +*
4.23 +* As a special exception, AlliedModders LLC gives you permission to link the
4.24 +* code of this program (as well as its derivative works) to "Half-Life 2," the
4.25 +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
4.26 +* by the Valve Corporation. You must obey the GNU General Public License in
4.27 +* all respects for all other code used. Additionally, AlliedModders LLC grants
4.28 +* this exception to all derivative works. AlliedModders LLC defines further
4.29 +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
4.30 +* or <http://www.sourcemod.net/license.php>.
4.31 +*
4.32 +* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
4.33 +*/
4.34 +
4.35 +#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
4.36 +#define _INCLUDE_SOURCEMOD_DETOURS_H_
4.37 +
4.38 +#include "extension.h"
4.39 +#include <jit/jit_helpers.h>
4.40 +#include <jit/x86/x86_macros.h>
4.41 +#include "detourhelpers.h"
4.42 +
4.43 +/**
4.44 + * CDetours class for SourceMod Extensions by pRED*
4.45 + * detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
4.46 + * asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly
4.47 + * Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/)
4.48 + * Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp)
4.49 + */
4.50 +
4.51 +#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
4.52 +#define DETOUR_STATIC_CALL(name) (name##_Actual)
4.53 +
4.54 +#define DETOUR_DECL_STATIC0(name, ret) \
4.55 +ret (*name##_Actual)(void) = NULL; \
4.56 +ret name(void)
4.57 +
4.58 +#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
4.59 +ret (*name##_Actual)(p1type) = NULL; \
4.60 +ret name(p1type p1name)
4.61 +
4.62 +#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
4.63 +ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
4.64 +ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
4.65 +
4.66 +#define DETOUR_DECL_MEMBER0(name, ret) \
4.67 +class name##Class \
4.68 +{ \
4.69 +public: \
4.70 + ret name(); \
4.71 + static ret (name##Class::* name##_Actual)(void); \
4.72 +}; \
4.73 +ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
4.74 +ret name##Class::name()
4.75 +
4.76 +#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
4.77 +class name##Class \
4.78 +{ \
4.79 +public: \
4.80 + ret name(p1type p1name); \
4.81 + static ret (name##Class::* name##_Actual)(p1type); \
4.82 +}; \
4.83 +ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
4.84 +ret name##Class::name(p1type p1name)
4.85 +
4.86 +#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
4.87 +class name##Class \
4.88 +{ \
4.89 +public: \
4.90 + ret name(p1type p1name, p2type p2name); \
4.91 + static ret (name##Class::* name##_Actual)(p1type, p2type); \
4.92 +}; \
4.93 +ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
4.94 +ret name##Class::name(p1type p1name, p2type p2name)
4.95 +
4.96 +#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
4.97 +class name##Class \
4.98 +{ \
4.99 +public: \
4.100 + ret name(p1type p1name, p2type p2name, p3type p3name); \
4.101 + static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
4.102 +}; \
4.103 +ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
4.104 +ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
4.105 +
4.106 +#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
4.107 +class name##Class \
4.108 +{ \
4.109 +public: \
4.110 + ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
4.111 + static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
4.112 +}; \
4.113 +ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
4.114 +ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
4.115 +
4.116 +
4.117 +#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
4.118 +#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
4.119 +
4.120 +#define GET_STATIC_CALLBACK(name) (void *)&name
4.121 +#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
4.122 +
4.123 +#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
4.124 +#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
4.125 +
4.126 +
4.127 +class GenericClass {};
4.128 +typedef void (GenericClass::*VoidFunc)();
4.129 +
4.130 +inline void *GetCodeAddr(VoidFunc mfp)
4.131 +{
4.132 + return *(void **)&mfp;
4.133 +}
4.134 +
4.135 +/**
4.136 + * Converts a member function pointer to a void pointer.
4.137 + * This relies on the assumption that the code address lies at mfp+0
4.138 + * This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
4.139 + * Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
4.140 + */
4.141 +#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast<VoidFunc>(mfp))
4.142 +
4.143 +class CDetourManager;
4.144 +
4.145 +class CDetour
4.146 +{
4.147 +public:
4.148 +
4.149 + bool IsEnabled();
4.150 +
4.151 + /**
4.152 + * These would be somewhat self-explanatory I hope
4.153 + */
4.154 + void EnableDetour();
4.155 + void DisableDetour();
4.156 +
4.157 + void Destroy();
4.158 +
4.159 + friend class CDetourManager;
4.160 +
4.161 +protected:
4.162 + CDetour(void *callbackfunction, void **trampoline, const char *signame);
4.163 +
4.164 + bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
4.165 +private:
4.166 +
4.167 + /* These create/delete the allocated memory */
4.168 + bool CreateDetour();
4.169 + void DeleteDetour();
4.170 +
4.171 + bool enabled;
4.172 + bool detoured;
4.173 +
4.174 + patch_t detour_restore;
4.175 + /* Address of the detoured function */
4.176 + void *detour_address;
4.177 + /* Address of the allocated trampoline function */
4.178 + void *detour_trampoline;
4.179 + /* Address of the callback handler */
4.180 + void *detour_callback;
4.181 + /* The function pointer used to call our trampoline */
4.182 + void **trampoline;
4.183 +
4.184 + const char *signame;
4.185 + ISourcePawnEngine *spengine;
4.186 + IGameConfig *gameconf;
4.187 +};
4.188 +
4.189 +class CDetourManager
4.190 +{
4.191 +public:
4.192 +
4.193 + static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
4.194 +
4.195 + /**
4.196 + * Creates a new detour
4.197 + *
4.198 + * @param callbackfunction Void pointer to your detour callback function.
4.199 + * @param trampoline Address of the trampoline pointer
4.200 + * @param signame Section name containing a signature to fetch from the gamedata file.
4.201 + * @return A new CDetour pointer to control your detour.
4.202 + *
4.203 + * Example:
4.204 + *
4.205 + * CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
4.206 + *
4.207 + * Define a new class with the required function and a member function pointer to the same type:
4.208 + *
4.209 + * class CBaseServerDetour
4.210 + * {
4.211 + * public:
4.212 + * bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
4.213 + * static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
4.214 + * }
4.215 + *
4.216 + * void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
4.217 + * void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
4.218 + *
4.219 + * Creation:
4.220 + * CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
4.221 + *
4.222 + * Usage:
4.223 + *
4.224 + * CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
4.225 + * {
4.226 + * //pre hook code
4.227 + * bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
4.228 + * //post hook code
4.229 + * return result;
4.230 + * }
4.231 + *
4.232 + * Note we changed the netadr_s reference into a void* to avoid needing to define the type
4.233 + */
4.234 + static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
4.235 +
4.236 + friend class CBlocker;
4.237 + friend class CDetour;
4.238 +
4.239 +private:
4.240 + static ISourcePawnEngine *spengine;
4.241 + static IGameConfig *gameconf;
4.242 +};
4.243 +
4.244 +#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
5.1 --- a/extensions/cstrike/Makefile Sun Jun 26 10:54:12 2011 -0400
5.2 +++ b/extensions/cstrike/Makefile Sun Jun 26 18:09:55 2011 -0400
5.3 @@ -18,7 +18,7 @@
5.4 #Uncomment for Metamod: Source enabled extension
5.5 USEMETA = true
5.6
5.7 -OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp timeleft.cpp
5.8 +OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp timeleft.cpp forwards.cpp CDetour/detours.cpp asm/asm.c
5.9
5.10 ##############################################
5.11 ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
5.12 @@ -156,7 +156,9 @@
5.13 $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
5.14
5.15 all: check
5.16 - mkdir -p $(BIN_DIR)/sdk
5.17 + mkdir -p $(BIN_DIR)/sdk
5.18 + mkdir -p $(BIN_DIR)/CDetour
5.19 + mkdir -p $(BIN_DIR)/asm
5.20 if [ "$(USEMETA)" = "true" ]; then \
5.21 ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX); \
5.22 ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX); \
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/extensions/cstrike/asm/asm.c Sun Jun 26 18:09:55 2011 -0400
6.3 @@ -0,0 +1,421 @@
6.4 +#include "asm.h"
6.5 +
6.6 +#ifndef WIN32
6.7 +#define _GNU_SOURCE
6.8 +#include <dlfcn.h>
6.9 +#include <string.h>
6.10 +
6.11 +#define REG_EAX 0
6.12 +#define REG_ECX 1
6.13 +#define REG_EDX 2
6.14 +#define REG_EBX 3
6.15 +
6.16 +#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
6.17 +#endif
6.18 +
6.19 +extern void Msg( const char *, ... );
6.20 +
6.21 +/**
6.22 +* Checks if a call to a fpic thunk has just been written into dest.
6.23 +* If found replaces it with a direct mov that sets the required register to the value of pc.
6.24 +*
6.25 +* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
6.26 +* @param pc The program counter value that needs to be set (usually the next address from the source).
6.27 +* @noreturn
6.28 +*/
6.29 +void check_thunks(unsigned char *dest, unsigned char *pc)
6.30 +{
6.31 +#if defined WIN32
6.32 + return;
6.33 +#else
6.34 + /* Step write address back 4 to the start of the function address */
6.35 + unsigned char *writeaddr = dest - 4;
6.36 + unsigned char *calloffset = *(unsigned char **)writeaddr;
6.37 + unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
6.38 +
6.39 + /* Lookup name of function being called */
6.40 + if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
6.41 + {
6.42 + //a thunk maybe?
6.43 + char movByte = IA32_MOV_REG_IMM;
6.44 +
6.45 + /* Calculate the correct mov opcode */
6.46 + switch (*(calladdr+1))
6.47 + {
6.48 + case 0x04:
6.49 + {
6.50 + movByte += REG_EAX;
6.51 + break;
6.52 + }
6.53 + case 0x1C:
6.54 + {
6.55 + movByte += REG_EBX;
6.56 + break;
6.57 + }
6.58 + case 0x0C:
6.59 + {
6.60 + movByte += REG_ECX;
6.61 + break;
6.62 + }
6.63 + case 0x14:
6.64 + {
6.65 + movByte += REG_EDX;
6.66 + break;
6.67 + }
6.68 + default:
6.69 + {
6.70 + Msg("Unknown thunk: %c\n", *(calladdr+1));
6.71 + break;
6.72 + }
6.73 + }
6.74 +
6.75 + /* Move our write address back one to where the call opcode was */
6.76 + writeaddr--;
6.77 +
6.78 +
6.79 + /* Write our mov */
6.80 + *writeaddr = movByte;
6.81 + writeaddr++;
6.82 +
6.83 + /* Write the value - The provided program counter value */
6.84 + *(void **)writeaddr = (void *)pc;
6.85 + writeaddr += 4;
6.86 + }
6.87 +
6.88 + return;
6.89 +#endif
6.90 +}
6.91 +
6.92 +//if dest is NULL, returns minimum number of bytes needed to be copied
6.93 +//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
6.94 +//http://www.devmaster.net/forums/showthread.php?t=2311
6.95 +int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
6.96 + int bytecount = 0;
6.97 +
6.98 + while(bytecount < required_len && *func != 0xCC)
6.99 + {
6.100 + // prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
6.101 + int operandSize = 4;
6.102 + int FPU = 0;
6.103 + int twoByte = 0;
6.104 + unsigned char opcode = 0x90;
6.105 + unsigned char modRM = 0xFF;
6.106 + while(*func == 0xF0 ||
6.107 + *func == 0xF2 ||
6.108 + *func == 0xF3 ||
6.109 + (*func & 0xFC) == 0x64 ||
6.110 + (*func & 0xF8) == 0xD8 ||
6.111 + (*func & 0x7E) == 0x62)
6.112 + {
6.113 + if(*func == 0x66)
6.114 + {
6.115 + operandSize = 2;
6.116 + }
6.117 + else if((*func & 0xF8) == 0xD8)
6.118 + {
6.119 + FPU = *func;
6.120 + if (dest)
6.121 + *dest++ = *func++;
6.122 + else
6.123 + func++;
6.124 + bytecount++;
6.125 + break;
6.126 + }
6.127 +
6.128 + if (dest)
6.129 + *dest++ = *func++;
6.130 + else
6.131 + func++;
6.132 + bytecount++;
6.133 + }
6.134 +
6.135 + // two-byte opcode byte
6.136 + if(*func == 0x0F)
6.137 + {
6.138 + twoByte = 1;
6.139 + if (dest)
6.140 + *dest++ = *func++;
6.141 + else
6.142 + func++;
6.143 + bytecount++;
6.144 + }
6.145 +
6.146 + // opcode byte
6.147 + opcode = *func++;
6.148 + if (dest) *dest++ = opcode;
6.149 + bytecount++;
6.150 +
6.151 + // mod R/M byte
6.152 + modRM = 0xFF;
6.153 + if(FPU)
6.154 + {
6.155 + if((opcode & 0xC0) != 0xC0)
6.156 + {
6.157 + modRM = opcode;
6.158 + }
6.159 + }
6.160 + else if(!twoByte)
6.161 + {
6.162 + if((opcode & 0xC4) == 0x00 ||
6.163 + ((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) ||
6.164 + (opcode & 0xF0) == 0x80 ||
6.165 + ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) ||
6.166 + (opcode & 0xFC) == 0xD0 ||
6.167 + (opcode & 0xF6) == 0xF6)
6.168 + {
6.169 + modRM = *func++;
6.170 + if (dest) *dest++ = modRM;
6.171 + bytecount++;
6.172 + }
6.173 + }
6.174 + else
6.175 + {
6.176 + if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
6.177 + (opcode & 0xF0) == 0x30 ||
6.178 + opcode == 0x77 ||
6.179 + (opcode & 0xF0) == 0x80 ||
6.180 + ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
6.181 + (opcode & 0xF8) == 0xC8)
6.182 + {
6.183 + // No mod R/M byte
6.184 + }
6.185 + else
6.186 + {
6.187 + modRM = *func++;
6.188 + if (dest) *dest++ = modRM;
6.189 + bytecount++;
6.190 + }
6.191 + }
6.192 +
6.193 + // SIB
6.194 + if((modRM & 0x07) == 0x04 &&
6.195 + (modRM & 0xC0) != 0xC0)
6.196 + {
6.197 + if (dest)
6.198 + *dest++ = *func++; //SIB
6.199 + else
6.200 + func++;
6.201 + bytecount++;
6.202 + }
6.203 +
6.204 + // mod R/M displacement
6.205 +
6.206 + // Dword displacement, no base
6.207 + if((modRM & 0xC5) == 0x05) {
6.208 + if (dest) {
6.209 + *(unsigned int*)dest = *(unsigned int*)func;
6.210 + dest += 4;
6.211 + }
6.212 + func += 4;
6.213 + bytecount += 4;
6.214 + }
6.215 +
6.216 + // Byte displacement
6.217 + if((modRM & 0xC0) == 0x40) {
6.218 + if (dest)
6.219 + *dest++ = *func++;
6.220 + else
6.221 + func++;
6.222 + bytecount++;
6.223 + }
6.224 +
6.225 + // Dword displacement
6.226 + if((modRM & 0xC0) == 0x80) {
6.227 + if (dest) {
6.228 + *(unsigned int*)dest = *(unsigned int*)func;
6.229 + dest += 4;
6.230 + }
6.231 + func += 4;
6.232 + bytecount += 4;
6.233 + }
6.234 +
6.235 + // immediate
6.236 + if(FPU)
6.237 + {
6.238 + // Can't have immediate operand
6.239 + }
6.240 + else if(!twoByte)
6.241 + {
6.242 + if((opcode & 0xC7) == 0x04 ||
6.243 + (opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
6.244 + (opcode & 0xF0) == 0x70 || // Jcc
6.245 + opcode == 0x80 ||
6.246 + opcode == 0x83 ||
6.247 + (opcode & 0xFD) == 0xA0 || // MOV
6.248 + opcode == 0xA8 || // TEST
6.249 + (opcode & 0xF8) == 0xB0 || // MOV
6.250 + (opcode & 0xFE) == 0xC0 || // RCL
6.251 + opcode == 0xC6 || // MOV
6.252 + opcode == 0xCD || // INT
6.253 + (opcode & 0xFE) == 0xD4 || // AAD/AAM
6.254 + (opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
6.255 + opcode == 0xEB ||
6.256 + (opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST
6.257 + {
6.258 + if (dest)
6.259 + *dest++ = *func++;
6.260 + else
6.261 + func++;
6.262 + bytecount++;
6.263 + }
6.264 + else if((opcode & 0xF7) == 0xC2) // RET
6.265 + {
6.266 + if (dest) {
6.267 + *(unsigned short*)dest = *(unsigned short*)func;
6.268 + dest += 2;
6.269 + }
6.270 + func += 2;
6.271 + bytecount += 2;
6.272 + }
6.273 + else if((opcode & 0xFC) == 0x80 ||
6.274 + (opcode & 0xC7) == 0x05 ||
6.275 + (opcode & 0xF8) == 0xB8 ||
6.276 + (opcode & 0xFE) == 0xE8 || // CALL/Jcc
6.277 + (opcode & 0xFE) == 0x68 ||
6.278 + (opcode & 0xFC) == 0xA0 ||
6.279 + (opcode & 0xEE) == 0xA8 ||
6.280 + opcode == 0xC7 ||
6.281 + (opcode == 0xF7 && (modRM & 0x30) == 0x00))
6.282 + {
6.283 + if (dest) {
6.284 + //Fix CALL/JMP offset
6.285 + if ((opcode & 0xFE) == 0xE8) {
6.286 + if (operandSize == 4)
6.287 + {
6.288 + *(long*)dest = ((func + *(long*)func) - dest);
6.289 +
6.290 + //pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
6.291 + check_thunks(dest+4, func+4);
6.292 + }
6.293 + else
6.294 + *(short*)dest = ((func + *(short*)func) - dest);
6.295 +
6.296 + } else {
6.297 + if (operandSize == 4)
6.298 + *(unsigned long*)dest = *(unsigned long*)func;
6.299 + else
6.300 + *(unsigned short*)dest = *(unsigned short*)func;
6.301 + }
6.302 + dest += operandSize;
6.303 + }
6.304 + func += operandSize;
6.305 + bytecount += operandSize;
6.306 +
6.307 + }
6.308 + }
6.309 + else
6.310 + {
6.311 + if(opcode == 0xBA || // BT
6.312 + opcode == 0x0F || // 3DNow!
6.313 + (opcode & 0xFC) == 0x70 || // PSLLW
6.314 + (opcode & 0xF7) == 0xA4 || // SHLD
6.315 + opcode == 0xC2 ||
6.316 + opcode == 0xC4 ||
6.317 + opcode == 0xC5 ||
6.318 + opcode == 0xC6)
6.319 + {
6.320 + if (dest)
6.321 + *dest++ = *func++;
6.322 + else
6.323 + func++;
6.324 + }
6.325 + else if((opcode & 0xF0) == 0x80) // Jcc -i
6.326 + {
6.327 + if (dest) {
6.328 + if (operandSize == 4)
6.329 + *(unsigned long*)dest = *(unsigned long*)func;
6.330 + else
6.331 + *(unsigned short*)dest = *(unsigned short*)func;
6.332 +
6.333 + dest += operandSize;
6.334 + }
6.335 + func += operandSize;
6.336 + bytecount += operandSize;
6.337 + }
6.338 + }
6.339 + }
6.340 +
6.341 + return bytecount;
6.342 +}
6.343 +
6.344 +//insert a specific JMP instruction at the given location
6.345 +void inject_jmp(void* src, void* dest) {
6.346 + *(unsigned char*)src = OP_JMP;
6.347 + *(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
6.348 +}
6.349 +
6.350 +//fill a given block with NOPs
6.351 +void fill_nop(void* src, unsigned int len) {
6.352 + unsigned char* src2 = (unsigned char*)src;
6.353 + while (len) {
6.354 + *src2++ = OP_NOP;
6.355 + --len;
6.356 + }
6.357 +}
6.358 +
6.359 +void* eval_jump(void* src) {
6.360 + unsigned char* addr = (unsigned char*)src;
6.361 +
6.362 + if (!addr) return 0;
6.363 +
6.364 + //import table jump
6.365 + if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
6.366 + addr += 2;
6.367 + addr = *(unsigned char**)addr;
6.368 + //TODO: if addr points into the IAT
6.369 + return *(void**)addr;
6.370 + }
6.371 +
6.372 + //8bit offset
6.373 + else if (addr[0] == OP_JMP_BYTE) {
6.374 + addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
6.375 + //mangled 32bit jump?
6.376 + if (addr[0] == OP_JMP) {
6.377 + addr = addr + *(int*)&addr[1];
6.378 + }
6.379 + return addr;
6.380 + }
6.381 + /*
6.382 + //32bit offset
6.383 + else if (addr[0] == OP_JMP) {
6.384 + addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
6.385 + }
6.386 + */
6.387 +
6.388 + return addr;
6.389 +}
6.390 +/*
6.391 +from ms detours package
6.392 +static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
6.393 +{
6.394 + MEMORY_BASIC_INFORMATION mbi;
6.395 + VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
6.396 + __try {
6.397 + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
6.398 + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
6.399 + return false;
6.400 + }
6.401 +
6.402 + PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
6.403 + pDosHeader->e_lfanew);
6.404 + if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
6.405 + return false;
6.406 + }
6.407 +
6.408 + if (pbAddress >= ((PBYTE)pDosHeader +
6.409 + pNtHeader->OptionalHeader
6.410 + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
6.411 + pbAddress < ((PBYTE)pDosHeader +
6.412 + pNtHeader->OptionalHeader
6.413 + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
6.414 + pNtHeader->OptionalHeader
6.415 + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
6.416 + return true;
6.417 + }
6.418 + return false;
6.419 + }
6.420 + __except(EXCEPTION_EXECUTE_HANDLER) {
6.421 + return false;
6.422 + }
6.423 +}
6.424 +*/
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/extensions/cstrike/asm/asm.h Sun Jun 26 18:09:55 2011 -0400
7.3 @@ -0,0 +1,40 @@
7.4 +#ifndef __ASM_H__
7.5 +#define __ASM_H__
7.6 +
7.7 +#define OP_JMP 0xE9
7.8 +#define OP_JMP_SIZE 5
7.9 +
7.10 +#define OP_NOP 0x90
7.11 +#define OP_NOP_SIZE 1
7.12 +
7.13 +#define OP_PREFIX 0xFF
7.14 +#define OP_JMP_SEG 0x25
7.15 +
7.16 +#define OP_JMP_BYTE 0xEB
7.17 +#define OP_JMP_BYTE_SIZE 2
7.18 +
7.19 +#ifdef __cplusplus
7.20 +extern "C" {
7.21 +#endif
7.22 +
7.23 +void check_thunks(unsigned char *dest, unsigned char *pc);
7.24 +
7.25 +//if dest is NULL, returns minimum number of bytes needed to be copied
7.26 +//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
7.27 +//http://www.devmaster.net/forums/showthread.php?t=2311
7.28 +int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
7.29 +
7.30 +//insert a specific JMP instruction at the given location
7.31 +void inject_jmp(void* src, void* dest);
7.32 +
7.33 +//fill a given block with NOPs
7.34 +void fill_nop(void* src, unsigned int len);
7.35 +
7.36 +//evaluate a JMP at the target
7.37 +void* eval_jump(void* src);
7.38 +
7.39 +#ifdef __cplusplus
7.40 +}
7.41 +#endif
7.42 +
7.43 +#endif //__ASM_H__
8.1 --- a/extensions/cstrike/extension.cpp Sun Jun 26 10:54:12 2011 -0400
8.2 +++ b/extensions/cstrike/extension.cpp Sun Jun 26 18:09:55 2011 -0400
8.3 @@ -34,6 +34,8 @@
8.4 #include "RegNatives.h"
8.5 #include "timeleft.h"
8.6 #include "iplayerinfo.h"
8.7 +#include "ISDKTools.h"
8.8 +#include "forwards.h"
8.9
8.10 /**
8.11 * @file extension.cpp
8.12 @@ -53,6 +55,8 @@
8.13
8.14 extern sp_nativeinfo_t g_CSNatives[];
8.15
8.16 +ISDKTools *g_pSDKTools = NULL;
8.17 +
8.18 bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
8.19 {
8.20 if (strcmp(g_pSM->GetGameFolderName(), "cstrike") != 0)
8.21 @@ -75,9 +79,23 @@
8.22
8.23 sharesys->AddNatives(myself, g_CSNatives);
8.24 sharesys->RegisterLibrary(myself, "cstrike");
8.25 + plsys->AddPluginsListener(this);
8.26
8.27 playerhelpers->RegisterCommandTargetProcessor(this);
8.28
8.29 + CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
8.30 +
8.31 + g_pHandleBuyForward = forwards->CreateForward("CS_OnBuyCommand", ET_Event, 2, NULL, Param_Cell, Param_String);
8.32 + g_pPriceForward = forwards->CreateForward("CS_OnGetWeaponPrice", ET_Event, 3, NULL, Param_Cell, Param_String, Param_CellByRef);
8.33 + g_pTerminateRoundForward = forwards->CreateForward("CS_OnTerminateRound", ET_Event, 2, NULL, Param_FloatByRef, Param_CellByRef);
8.34 + g_pCSWeaponDropForward = forwards->CreateForward("CS_OnCSWeaponDrop", ET_Event, 2, NULL, Param_Cell, Param_Cell);
8.35 +
8.36 +
8.37 + m_TerminateRoundDetourEnabled = false;
8.38 + m_WeaponPriceDetourEnabled = false;
8.39 + m_HandleBuyDetourEnabled = false;
8.40 + m_CSWeaponDetourEnabled = false;
8.41 +
8.42 return true;
8.43 }
8.44
8.45 @@ -99,11 +117,26 @@
8.46 }
8.47 g_RegNatives.UnregisterAll();
8.48 gameconfs->CloseGameConfigFile(g_pGameConf);
8.49 + plsys->RemovePluginsListener(this);
8.50 playerhelpers->UnregisterCommandTargetProcessor(this);
8.51 + forwards->ReleaseForward(g_pHandleBuyForward);
8.52 + forwards->ReleaseForward(g_pPriceForward);
8.53 + forwards->ReleaseForward(g_pTerminateRoundForward);
8.54 + forwards->ReleaseForward(g_pCSWeaponDropForward);
8.55 }
8.56
8.57 void CStrike::SDK_OnAllLoaded()
8.58 {
8.59 + SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
8.60 + if (g_pSDKTools == NULL)
8.61 + {
8.62 + smutils->LogError(myself, "SDKTools interface not found. TerminateRound native disabled.");
8.63 + }
8.64 + else if (g_pSDKTools->GetInterfaceVersion() < 2)
8.65 + {
8.66 + //<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
8.67 + smutils->LogError(myself, "SDKTools interface is outdated. TerminateRound native disabled.");
8.68 + }
8.69 gameevents->AddListener(&g_TimeLeftEvents, "round_start", true);
8.70 gameevents->AddListener(&g_TimeLeftEvents, "round_end", true);
8.71 SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, &g_TimeLeftEvents, &TimeLeftEvents::LevelInit, true);
8.72 @@ -257,3 +290,48 @@
8.73 return SM_BUILD_TIMESTAMP;
8.74 }
8.75
8.76 +void CStrike::OnPluginLoaded(IPlugin *plugin)
8.77 +{
8.78 + if (!m_WeaponPriceDetourEnabled && g_pPriceForward->GetFunctionCount())
8.79 + {
8.80 + m_WeaponPriceDetourEnabled = CreateWeaponPriceDetour();
8.81 + if (m_WeaponPriceDetourEnabled)
8.82 + m_HandleBuyDetourEnabled = true;
8.83 + }
8.84 + if (!m_TerminateRoundDetourEnabled && g_pTerminateRoundForward->GetFunctionCount())
8.85 + {
8.86 + m_TerminateRoundDetourEnabled = CreateTerminateRoundDetour();
8.87 + }
8.88 + if (!m_HandleBuyDetourEnabled && g_pHandleBuyForward->GetFunctionCount())
8.89 + {
8.90 + m_HandleBuyDetourEnabled = CreateHandleBuyDetour();
8.91 + }
8.92 + if (!m_CSWeaponDetourEnabled && g_pCSWeaponDropForward->GetFunctionCount())
8.93 + {
8.94 + m_CSWeaponDetourEnabled = CreateCSWeaponDropDetour();
8.95 + }
8.96 +}
8.97 +
8.98 +void CStrike::OnPluginUnloaded(IPlugin *plugin)
8.99 +{
8.100 + if (m_WeaponPriceDetourEnabled && !g_pPriceForward->GetFunctionCount())
8.101 + {
8.102 + RemoveWeaponPriceDetour();
8.103 + m_WeaponPriceDetourEnabled = false;
8.104 + }
8.105 + if (m_TerminateRoundDetourEnabled && !g_pTerminateRoundForward->GetFunctionCount())
8.106 + {
8.107 + RemoveTerminateRoundDetour();
8.108 + m_TerminateRoundDetourEnabled = false;
8.109 + }
8.110 + if (m_HandleBuyDetourEnabled && !g_pHandleBuyForward->GetFunctionCount())
8.111 + {
8.112 + RemoveHandleBuyDetour();
8.113 + m_HandleBuyDetourEnabled = false;
8.114 + }
8.115 + if (m_CSWeaponDetourEnabled && !g_pCSWeaponDropForward->GetFunctionCount())
8.116 + {
8.117 + RemoveCSWeaponDropDetour();
8.118 + m_CSWeaponDetourEnabled = false;;
8.119 + }
8.120 +}
9.1 --- a/extensions/cstrike/extension.h Sun Jun 26 10:54:12 2011 -0400
9.2 +++ b/extensions/cstrike/extension.h Sun Jun 26 18:09:55 2011 -0400
9.3 @@ -38,7 +38,9 @@
9.4 */
9.5
9.6 #include "smsdk_ext.h"
9.7 +#include "CDetour/detours.h"
9.8 #include <IBinTools.h>
9.9 +#include <ISDKTools.h>
9.10
9.11 /**
9.12 * @brief Sample implementation of the SDK Extension.
9.13 @@ -46,7 +48,8 @@
9.14 */
9.15 class CStrike :
9.16 public SDKExtension,
9.17 - public ICommandTargetProcessor
9.18 + public ICommandTargetProcessor,
9.19 + public IPluginsListener
9.20 {
9.21 public:
9.22 /**
9.23 @@ -91,6 +94,9 @@
9.24 const char *GetExtensionDateString();
9.25 public:
9.26 bool ProcessCommandTarget(cmd_target_info_t *info);
9.27 +public: //IPluginsListener
9.28 + void OnPluginLoaded(IPlugin *plugin);
9.29 + void OnPluginUnloaded(IPlugin *plugin);
9.30 public:
9.31 #if defined SMEXT_CONF_METAMOD
9.32 /**
9.33 @@ -124,11 +130,21 @@
9.34 */
9.35 //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
9.36 #endif
9.37 +private:
9.38 + bool m_WeaponPriceDetourEnabled;
9.39 + bool m_TerminateRoundDetourEnabled;
9.40 + bool m_HandleBuyDetourEnabled;
9.41 + bool m_CSWeaponDetourEnabled;
9.42 };
9.43
9.44 /* Interfaces from SourceMod */
9.45 extern IBinTools *g_pBinTools;
9.46 extern IGameConfig *g_pGameConf;
9.47 +extern ISDKTools *g_pSDKTools;
9.48 extern int g_msgHintText;
9.49 +extern bool g_pIgnoreTerminateDetour;
9.50 +extern bool g_pIgnoreCSWeaponDropDetour;
9.51 +extern bool g_pTerminateRoundDetoured;
9.52 +extern bool g_pCSWeaponDropDetoured;
9.53
9.54 #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/extensions/cstrike/forwards.cpp Sun Jun 26 18:09:55 2011 -0400
10.3 @@ -0,0 +1,234 @@
10.4 +#include "extension.h"
10.5 +#include "forwards.h"
10.6 +
10.7 +bool g_pTerminateRoundDetoured = false;
10.8 +bool g_pCSWeaponDropDetoured = false;
10.9 +bool g_pIgnoreTerminateDetour = false;
10.10 +bool g_pIgnoreCSWeaponDropDetour = false;
10.11 +bool g_PriceDetoured = false;
10.12 +bool g_HandleBuyDetoured = false;
10.13 +int lastclient = -1;
10.14 +
10.15 +IForward *g_pHandleBuyForward = NULL;
10.16 +IForward *g_pPriceForward = NULL;
10.17 +IForward *g_pTerminateRoundForward = NULL;
10.18 +IForward *g_pCSWeaponDropForward = NULL;
10.19 +CDetour *DHandleBuy = NULL;
10.20 +CDetour *DWeaponPrice = NULL;
10.21 +CDetour *DTerminateRound = NULL;
10.22 +CDetour *DCSWeaponDrop = NULL;
10.23 +
10.24 +int weaponNameOffset = -1;
10.25 +
10.26 +DETOUR_DECL_MEMBER1(DetourHandleBuy, int, const char *, weapon)
10.27 +{
10.28 + int client = engine->IndexOfEdict(engine->PEntityOfEntIndex(gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(this))));
10.29 +
10.30 + lastclient = client;
10.31 +
10.32 + cell_t result = Pl_Continue;
10.33 +
10.34 + g_pHandleBuyForward->PushCell(client);
10.35 + g_pHandleBuyForward->PushString(weapon);
10.36 + g_pHandleBuyForward->Execute(&result);
10.37 +
10.38 + if (result != Pl_Continue)
10.39 + {
10.40 + lastclient = -1;
10.41 + return 0;
10.42 + }
10.43 + int val = DETOUR_MEMBER_CALL(DetourHandleBuy)(weapon);
10.44 + lastclient = -1;
10.45 + return val;
10.46 +}
10.47 +
10.48 +DETOUR_DECL_MEMBER0(DetourWeaponPrice, int)
10.49 +{
10.50 + int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)();
10.51 +
10.52 + if (lastclient == -1)
10.53 + return price;
10.54 +
10.55 + const char *weapon_name = reinterpret_cast<char *>(this+weaponNameOffset);
10.56 +
10.57 + int original = price;
10.58 +
10.59 + cell_t result = Pl_Continue;
10.60 +
10.61 + g_pPriceForward->PushCell(lastclient);
10.62 + g_pPriceForward->PushString(weapon_name);
10.63 + g_pPriceForward->PushCellByRef(&price);
10.64 + g_pPriceForward->Execute(&result);
10.65 +
10.66 + if (result == Pl_Continue)
10.67 + return original;
10.68 +
10.69 + return price;
10.70 +}
10.71 +
10.72 +DETOUR_DECL_MEMBER2(DetourTerminateRound, void, float, delay, int, reason)
10.73 +{
10.74 + if (g_pIgnoreTerminateDetour)
10.75 + {
10.76 + g_pIgnoreTerminateDetour = false;
10.77 + DETOUR_MEMBER_CALL(DetourTerminateRound)(delay, reason);
10.78 + return;
10.79 + }
10.80 + float orgdelay = delay;
10.81 + int orgreason = reason;
10.82 +
10.83 + cell_t result = Pl_Continue;
10.84 +
10.85 + g_pTerminateRoundForward->PushFloatByRef(&delay);
10.86 + g_pTerminateRoundForward->PushCellByRef(&reason);
10.87 + g_pTerminateRoundForward->Execute(&result);
10.88 +
10.89 + if (result >= Pl_Handled)
10.90 + return;
10.91 +
10.92 + if (result == Pl_Changed)
10.93 + return DETOUR_MEMBER_CALL(DetourTerminateRound)(delay, reason);
10.94 +
10.95 + return DETOUR_MEMBER_CALL(DetourTerminateRound)(orgdelay, orgreason);
10.96 +}
10.97 +DETOUR_DECL_MEMBER3(DetourCSWeaponDrop, void, CBaseEntity *, weapon, bool, something, bool, toss)
10.98 +{
10.99 + if (g_pIgnoreCSWeaponDropDetour)
10.100 + {
10.101 + g_pIgnoreCSWeaponDropDetour = false;
10.102 + DETOUR_MEMBER_CALL(DetourCSWeaponDrop)(weapon, something, toss);
10.103 + return;
10.104 + }
10.105 +
10.106 + int client = engine->IndexOfEdict(engine->PEntityOfEntIndex(gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(this))));
10.107 + int weaponIndex = engine->IndexOfEdict(engine->PEntityOfEntIndex(gamehelpers->EntityToBCompatRef(weapon)));
10.108 +
10.109 + cell_t result = Pl_Continue;
10.110 + g_pCSWeaponDropForward->PushCell(client);
10.111 + g_pCSWeaponDropForward->PushCell(weaponIndex);
10.112 + g_pCSWeaponDropForward->Execute(&result);
10.113 +
10.114 +
10.115 + if (result == Pl_Continue)
10.116 + DETOUR_MEMBER_CALL(DetourCSWeaponDrop)(weapon, something, toss);
10.117 +
10.118 + return;
10.119 +}
10.120 +bool CreateWeaponPriceDetour()
10.121 +{
10.122 + if (weaponNameOffset == -1)
10.123 + {
10.124 + if (!g_pGameConf->GetOffset("WeaponName", &weaponNameOffset))
10.125 + {
10.126 + smutils->LogError(myself, "Could not find WeaponName offset - Disabled OnGetWeaponPrice forward");
10.127 + return false;
10.128 + }
10.129 + }
10.130 + DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetWeaponPrice");
10.131 +
10.132 + if (DWeaponPrice != NULL)
10.133 + {
10.134 + if (!CreateHandleBuyDetour())
10.135 + {
10.136 + g_pSM->LogError(myself, "GetWeaponPrice detour could not be initialized - HandleCommand_Buy_Internal failed to detour, disabled OnGetWeaponPrice forward.");
10.137 + return false;
10.138 + }
10.139 + DWeaponPrice->EnableDetour();
10.140 + g_PriceDetoured = true;
10.141 + return true;
10.142 + }
10.143 +
10.144 + g_pSM->LogError(myself, "GetWeaponPrice detour could not be initialized - Disabled OnGetWeaponPrice forward.");
10.145 +
10.146 + return false;
10.147 +}
10.148 +
10.149 +bool CreateTerminateRoundDetour()
10.150 +{
10.151 + DTerminateRound = DETOUR_CREATE_MEMBER(DetourTerminateRound, "TerminateRound");
10.152 +
10.153 + if (DTerminateRound != NULL)
10.154 + {
10.155 + DTerminateRound->EnableDetour();
10.156 + g_pTerminateRoundDetoured = true;
10.157 + return true;
10.158 + }
10.159 + g_pSM->LogError(myself, "TerminateRound detour could not be initialized - Disabled OnTerminateRound forward");
10.160 + return false;
10.161 +}
10.162 +
10.163 +bool CreateHandleBuyDetour()
10.164 +{
10.165 + if (g_HandleBuyDetoured)
10.166 + return true;
10.167 +
10.168 + DHandleBuy = DETOUR_CREATE_MEMBER(DetourHandleBuy, "HandleCommand_Buy_Internal");
10.169 +
10.170 + if (DHandleBuy != NULL)
10.171 + {
10.172 + DHandleBuy->EnableDetour();
10.173 + g_HandleBuyDetoured = true;
10.174 + return true;
10.175 + }
10.176 + g_pSM->LogError(myself, "HandleCommand_Buy_Internal detour could not be initialized - Disabled OnBuyCommand forward");
10.177 + return false;
10.178 +}
10.179 +
10.180 +bool CreateCSWeaponDropDetour()
10.181 +{
10.182 + DCSWeaponDrop = DETOUR_CREATE_MEMBER(DetourCSWeaponDrop, "CSWeaponDrop");
10.183 +
10.184 + if (DCSWeaponDrop != NULL)
10.185 + {
10.186 + DCSWeaponDrop->EnableDetour();
10.187 + g_pCSWeaponDropDetoured = true;
10.188 + return true;
10.189 + }
10.190 +
10.191 + g_pSM->LogError(myself, "CSWeaponDrop detour could not be initialized - Disabled OnCSWeaponDrop forward");
10.192 + return false;
10.193 +}
10.194 +
10.195 +void RemoveWeaponPriceDetour()
10.196 +{
10.197 + if (DWeaponPrice != NULL)
10.198 + {
10.199 + DWeaponPrice->Destroy();
10.200 + DWeaponPrice = NULL;
10.201 + }
10.202 + g_PriceDetoured = false;
10.203 +
10.204 +}
10.205 +
10.206 +void RemoveHandleBuyDetour()
10.207 +{
10.208 + if (g_PriceDetoured)
10.209 + return;
10.210 +
10.211 + if (DHandleBuy != NULL)
10.212 + {
10.213 + DHandleBuy->Destroy();
10.214 + DHandleBuy = NULL;
10.215 + }
10.216 + g_HandleBuyDetoured = false;
10.217 +}
10.218 +
10.219 +void RemoveTerminateRoundDetour()
10.220 +{
10.221 + if (DTerminateRound != NULL)
10.222 + {
10.223 + DTerminateRound->Destroy();
10.224 + DTerminateRound = NULL;
10.225 + }
10.226 + g_pTerminateRoundDetoured = false;
10.227 +}
10.228 +
10.229 +void RemoveCSWeaponDropDetour()
10.230 +{
10.231 + if (DCSWeaponDrop != NULL)
10.232 + {
10.233 + DCSWeaponDrop->Destroy();
10.234 + DCSWeaponDrop = NULL;
10.235 + }
10.236 + g_pCSWeaponDropDetoured = false;
10.237 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/extensions/cstrike/forwards.h Sun Jun 26 18:09:55 2011 -0400
11.3 @@ -0,0 +1,17 @@
11.4 +#ifndef _INCLUDE_CSTRIKE_FORWARDS_H_
11.5 +#define _INCLUDE_CSTRIKE_FORWARDS_H_
11.6 +bool CreateWeaponPriceDetour();
11.7 +bool CreateHandleBuyDetour();
11.8 +bool CreateTerminateRoundDetour();
11.9 +bool CreateCSWeaponDropDetour();
11.10 +void RemoveWeaponPriceDetour();
11.11 +void RemoveHandleBuyDetour();
11.12 +void RemoveTerminateRoundDetour();
11.13 +void RemoveCSWeaponDropDetour();
11.14 +
11.15 +extern IServerGameEnts *gameents;
11.16 +extern IForward *g_pHandleBuyForward;
11.17 +extern IForward *g_pPriceForward;
11.18 +extern IForward *g_pTerminateRoundForward;
11.19 +extern IForward *g_pCSWeaponDropForward;
11.20 +#endif //_INCLUDE_CSTRIKE_FORWARDS_H_
12.1 --- a/extensions/cstrike/msvc9/cstrike.vcproj Sun Jun 26 10:54:12 2011 -0400
12.2 +++ b/extensions/cstrike/msvc9/cstrike.vcproj Sun Jun 26 18:09:55 2011 -0400
12.3 @@ -505,7 +505,7 @@
12.4 Name="VCPostBuildEventTool"
12.5 />
12.6 </Configuration>
12.7 - <Configuration
12.8 + <Configuration
12.9 Name="Debug - Episode1|Win32"
12.10 OutputDirectory="$(SolutionDir)$(ConfigurationName)"
12.11 IntermediateDirectory="$(ConfigurationName)"
12.12 @@ -682,6 +682,10 @@
12.13 >
12.14 </File>
12.15 <File
12.16 + RelativePath="..\forwards.cpp"
12.17 + >
12.18 + </File>
12.19 + <File
12.20 RelativePath="..\natives.cpp"
12.21 >
12.22 </File>
12.23 @@ -704,6 +708,10 @@
12.24 >
12.25 </File>
12.26 <File
12.27 + RelativePath="..\forwards.h"
12.28 + >
12.29 + </File>
12.30 + <File
12.31 RelativePath="..\RegNatives.h"
12.32 >
12.33 </File>
12.34 @@ -739,6 +747,34 @@
12.35 >
12.36 </File>
12.37 </Filter>
12.38 + <Filter
12.39 + Name="asm"
12.40 + >
12.41 + <File
12.42 + RelativePath="..\asm\asm.c"
12.43 + >
12.44 + </File>
12.45 + <File
12.46 + RelativePath="..\asm\asm.h"
12.47 + >
12.48 + </File>
12.49 + </Filter>
12.50 + <Filter
12.51 + Name="CDetour"
12.52 + >
12.53 + <File
12.54 + RelativePath="..\CDetour\detourhelpers.h"
12.55 + >
12.56 + </File>
12.57 + <File
12.58 + RelativePath="..\CDetour\detours.cpp"
12.59 + >
12.60 + </File>
12.61 + <File
12.62 + RelativePath="..\CDetour\detours.h"
12.63 + >
12.64 + </File>
12.65 + </Filter>
12.66 </Files>
12.67 <Globals>
12.68 </Globals>
13.1 --- a/extensions/cstrike/natives.cpp Sun Jun 26 10:54:12 2011 -0400
13.2 +++ b/extensions/cstrike/natives.cpp Sun Jun 26 18:09:55 2011 -0400
13.3 @@ -31,10 +31,11 @@
13.4
13.5 #include "extension.h"
13.6 #include "RegNatives.h"
13.7 +#include <server_class.h>
13.8
13.9 #define REGISTER_NATIVE_ADDR(name, code) \
13.10 void *addr; \
13.11 - if (!g_pGameConf->GetMemSig(name, &addr)) \
13.12 + if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
13.13 { \
13.14 return pContext->ThrowNativeError("Failed to locate function"); \
13.15 } \
13.16 @@ -71,6 +72,59 @@
13.17 return pUnk->GetBaseEntity();
13.18 }
13.19
13.20 +bool UTIL_FindDataTable(SendTable *pTable, const char *name, sm_sendprop_info_t *info, unsigned int offset)
13.21 +{
13.22 + const char *pname;
13.23 + int props = pTable->GetNumProps();
13.24 + SendProp *prop;
13.25 + SendTable *table;
13.26 +
13.27 + for (int i=0; i<props; i++)
13.28 + {
13.29 + prop = pTable->GetProp(i);
13.30 +
13.31 + if ((table = prop->GetDataTable()) != NULL)
13.32 + {
13.33 + pname = table->GetName();
13.34 + if (pname && strcmp(name, pname) == 0)
13.35 + {
13.36 + info->prop = prop;
13.37 + info->actual_offset = offset + info->prop->GetOffset();
13.38 + return true;
13.39 + }
13.40 +
13.41 + if (UTIL_FindDataTable(table,
13.42 + name,
13.43 + info,
13.44 + offset + prop->GetOffset())
13.45 + )
13.46 + {
13.47 + return true;
13.48 + }
13.49 + }
13.50 + }
13.51 +
13.52 + return false;
13.53 +}
13.54 +
13.55 +//Taken From Sourcemod Core
13.56 +unsigned int strncopy(char *dest, const char *src, size_t count)
13.57 +{
13.58 + if (!count)
13.59 + {
13.60 + return 0;
13.61 + }
13.62 +
13.63 + char *start = dest;
13.64 + while ((*src) && (--count))
13.65 + {
13.66 + *dest++ = *src++;
13.67 + }
13.68 + *dest = '\0';
13.69 +
13.70 + return (dest - start);
13.71 +}
13.72 +
13.73 static cell_t CS_RespawnPlayer(IPluginContext *pContext, const cell_t *params)
13.74 {
13.75 static ICallWrapper *pWrapper = NULL;
13.76 @@ -120,10 +174,165 @@
13.77 return 1;
13.78 }
13.79
13.80 +static cell_t CS_DropWeapon(IPluginContext *pContext, const cell_t *params)
13.81 +{
13.82 + static ICallWrapper *pWrapper = NULL;
13.83 + if (!pWrapper)
13.84 + {
13.85 + REGISTER_NATIVE_ADDR("CSWeaponDrop",
13.86 + PassInfo pass[3]; \
13.87 + pass[0].flags = PASSFLAG_BYVAL; \
13.88 + pass[0].type = PassType_Basic; \
13.89 + pass[0].size = sizeof(CBaseEntity *); \
13.90 + pass[1].flags = PASSFLAG_BYVAL; \
13.91 + pass[1].type = PassType_Basic; \
13.92 + pass[1].size = sizeof(bool); \
13.93 + pass[2].flags = PASSFLAG_BYVAL; \
13.94 + pass[2].type = PassType_Basic; \
13.95 + pass[2].size = sizeof(bool); \
13.96 + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
13.97 + }
13.98 +
13.99 + CBaseEntity *pEntity;
13.100 + if (!(pEntity = GetCBaseEntity(params[1], true)))
13.101 + {
13.102 + return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
13.103 + }
13.104 +
13.105 + CBaseEntity *pWeapon;
13.106 + if (!(pWeapon = GetCBaseEntity(params[2], false)))
13.107 + {
13.108 + return pContext->ThrowNativeError("Weapon index %d is not valid", params[2]);
13.109 + }
13.110 +
13.111 + //Psychonic is awesome for this
13.112 + sm_sendprop_info_t *spi = new sm_sendprop_info_t;
13.113 + IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
13.114 + IServerNetworkable *pNet = pUnk->GetNetworkable();
13.115 +
13.116 + if (!UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, "DT_WeaponCSBase", spi, 0))
13.117 + return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);
13.118 +
13.119 + if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", spi))
13.120 + return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);
13.121 +
13.122 + CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + spi->actual_offset);
13.123 + if (params[1] != hndl.GetEntryIndex())
13.124 + return pContext->ThrowNativeError("Weapon %d is not owned by client %d", params[2], params[1]);
13.125 +
13.126 + if (params[4] == 1 && g_pCSWeaponDropDetoured)
13.127 + g_pIgnoreCSWeaponDropDetour = true;
13.128 +
13.129 + unsigned char vstk[sizeof(CBaseEntity *) * 2 + sizeof(bool) * 2];
13.130 + unsigned char *vptr = vstk;
13.131 +
13.132 + // <psychonic> first one is always false. second is true to toss, false to just drop
13.133 + *(CBaseEntity **)vptr = pEntity;
13.134 + vptr += sizeof(CBaseEntity *);
13.135 + *(CBaseEntity **)vptr = pWeapon;
13.136 + vptr += sizeof(CBaseEntity *);
13.137 + *(bool *)vptr = false;
13.138 + vptr += sizeof(bool);
13.139 + *(bool *)vptr = (params[3]) ? true : false;
13.140 +
13.141 + pWrapper->Execute(vstk, NULL);
13.142 +
13.143 + return 1;
13.144 +}
13.145 +
13.146 +static cell_t CS_TerminateRound(IPluginContext *pContext, const cell_t *params)
13.147 +{
13.148 + if (g_pSDKTools == NULL)
13.149 + {
13.150 + smutils->LogError(myself, "SDKTools interface not found. TerminateRound native disabled.");
13.151 + }
13.152 + else if (g_pSDKTools->GetInterfaceVersion() < 2)
13.153 + {
13.154 + //<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
13.155 + return pContext->ThrowNativeError("SDKTools interface is outdated. TerminateRound native disabled.");
13.156 + }
13.157 +
13.158 + static ICallWrapper *pWrapper = NULL;
13.159 +
13.160 + if (!pWrapper)
13.161 + {
13.162 + REGISTER_NATIVE_ADDR("TerminateRound",
13.163 + PassInfo pass[2]; \
13.164 + pass[0].flags = PASSFLAG_BYVAL; \
13.165 + pass[0].type = PassType_Basic; \
13.166 + pass[0].size = sizeof(float); \
13.167 + pass[1].flags = PASSFLAG_BYVAL; \
13.168 + pass[1].type = PassType_Basic; \
13.169 + pass[1].size = sizeof(int); \
13.170 + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
13.171 + }
13.172 +
13.173 + void *gamerules = g_pSDKTools->GetGameRules();
13.174 + if (gamerules == NULL)
13.175 + {
13.176 + return pContext->ThrowNativeError("GameRules not available. TerminateRound native disabled.");
13.177 + }
13.178 +
13.179 + if (params[3] == 1 && g_pTerminateRoundDetoured)
13.180 + g_pIgnoreTerminateDetour = true;
13.181 +
13.182 + unsigned char vstk[sizeof(void *) + sizeof(float)+ sizeof(int)];
13.183 + unsigned char *vptr = vstk;
13.184 +
13.185 + *(void **)vptr = gamerules;
13.186 + vptr += sizeof(void *);
13.187 + *(float *)vptr = sp_ctof(params[1]);
13.188 + vptr += sizeof(float);
13.189 + *(int*)vptr = params[2];
13.190 +
13.191 + pWrapper->Execute(vstk, NULL);
13.192 +
13.193 + return 1;
13.194 +}
13.195 +
13.196 +static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t *params)
13.197 +{
13.198 + static ICallWrapper *pWrapper = NULL;
13.199 +
13.200 + if (!pWrapper)
13.201 + {
13.202 + REGISTER_NATIVE_ADDR("GetTranslatedWeaponAlias",
13.203 + PassInfo pass[1]; \
13.204 + PassInfo retpass[1]; \
13.205 + pass[0].flags = PASSFLAG_BYVAL; \
13.206 + pass[0].type = PassType_Basic; \
13.207 + pass[0].size = sizeof(char *); \
13.208 + retpass[0].flags = PASSFLAG_BYVAL; \
13.209 + retpass[0].type = PassType_Basic; \
13.210 + retpass[0].size = sizeof(char *); \
13.211 + pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass[0], pass, 1))
13.212 + }
13.213 + char *dest, *weapon;
13.214 +
13.215 + pContext->LocalToString(params[2], &dest);
13.216 + pContext->LocalToString(params[1], &weapon);
13.217 +
13.218 + char *ret = new char[128];
13.219 +
13.220 + unsigned char vstk[sizeof(char *)];
13.221 + unsigned char *vptr = vstk;
13.222 +
13.223 + *(char **)vptr = weapon;
13.224 +
13.225 + pWrapper->Execute(vstk, &ret);
13.226 +
13.227 + strncopy(dest, ret, params[3]);
13.228 +
13.229 + return 1;
13.230 +}
13.231 +
13.232 sp_nativeinfo_t g_CSNatives[] =
13.233 {
13.234 {"CS_RespawnPlayer", CS_RespawnPlayer},
13.235 - {"CS_SwitchTeam", CS_SwitchTeam},
13.236 + {"CS_SwitchTeam", CS_SwitchTeam},
13.237 + {"CS_DropWeapon", CS_DropWeapon},
13.238 + {"CS_TerminateRound", CS_TerminateRound},
13.239 + {"CS_GetTranslatedWeaponAlias", CS_GetTranslatedWeaponAlias},
13.240 {NULL, NULL}
13.241 };
13.242
14.1 --- a/extensions/cstrike/sdk/smsdk_config.h Sun Jun 26 10:54:12 2011 -0400
14.2 +++ b/extensions/cstrike/sdk/smsdk_config.h Sun Jun 26 18:09:55 2011 -0400
14.3 @@ -59,16 +59,17 @@
14.4 #define SMEXT_CONF_METAMOD
14.5
14.6 /** Enable interfaces you want to use here by uncommenting lines */
14.7 -//#define SMEXT_ENABLE_FORWARDSYS
14.8 +#define SMEXT_ENABLE_FORWARDSYS
14.9 //#define SMEXT_ENABLE_HANDLESYS
14.10 #define SMEXT_ENABLE_PLAYERHELPERS
14.11 //#define SMEXT_ENABLE_DBMANAGER
14.12 #define SMEXT_ENABLE_GAMECONF
14.13 //#define SMEXT_ENABLE_MEMUTILS
14.14 -//#define SMEXT_ENABLE_GAMEHELPERS
14.15 +#define SMEXT_ENABLE_GAMEHELPERS
14.16 #define SMEXT_ENABLE_TIMERSYS
14.17 //#define SMEXT_ENABLE_THREADER
14.18 //#define SMEXT_ENABLE_LIBSYS
14.19 #define SMEXT_ENABLE_USERMSGS
14.20 +#define SMEXT_ENABLE_PLUGINSYS
14.21
14.22 #endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
15.1 --- a/extensions/cstrike/sdk/smsdk_ext.h Sun Jun 26 10:54:12 2011 -0400
15.2 +++ b/extensions/cstrike/sdk/smsdk_ext.h Sun Jun 26 18:09:55 2011 -0400
15.3 @@ -76,6 +76,9 @@
15.4 #if defined SMEXT_ENABLE_USERMSGS
15.5 #include <IUserMessages.h>
15.6 #endif
15.7 +#if defined SMEXT_ENABLE_PLUGINSYS
15.8 +#include <IPluginSys.h>
15.9 +#endif
15.10
15.11 #if defined SMEXT_CONF_METAMOD
15.12 #include <ISmmPlugin.h>
15.13 @@ -266,6 +269,10 @@
15.14 #if defined SMEXT_ENABLE_USERMSGS
15.15 extern IUserMessages *usermsgs;
15.16 #endif
15.17 +#if defined SMEXT_ENABLE_PLUGINSYS
15.18 +extern IPluginManager *plsys;
15.19 +#endif
15.20 +
15.21
15.22 #if defined SMEXT_CONF_METAMOD
15.23 PLUGIN_GLOBALVARS();
16.1 --- a/gamedata/sm-cstrike.games.txt Sun Jun 26 10:54:12 2011 -0400
16.2 +++ b/gamedata/sm-cstrike.games.txt Sun Jun 26 18:09:55 2011 -0400
16.3 @@ -13,6 +13,16 @@
16.4 {
16.5 "cstrike"
16.6 {
16.7 + "Offsets"
16.8 + {
16.9 + //Offset of szClassName in CCSWeaponInfo
16.10 + "WeaponName"
16.11 + {
16.12 + "windows" "6"
16.13 + "linux" "6"
16.14 + "mac" "6"
16.15 + }
16.16 + }
16.17 "Signatures"
16.18 {
16.19 "RoundRespawn"
16.20 @@ -29,6 +39,41 @@
16.21 "linux" "@_ZN9CCSPlayer10SwitchTeamEi"
16.22 "mac" "@_ZN9CCSPlayer10SwitchTeamEi"
16.23 }
16.24 + "HandleCommand_Buy_Internal"
16.25 + {
16.26 + "library" "server"
16.27 + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x01\x00\x00\x89\x8D\x58"
16.28 + "linux" "@_ZN9CCSPlayer26HandleCommand_Buy_InternalEPKc"
16.29 + "mac" "@_ZN9CCSPlayer26HandleCommand_Buy_InternalEPKc"
16.30 + }
16.31 + "GetWeaponPrice"
16.32 + {
16.33 + "library" "server"
16.34 + "windows" "\x8B\x81\xB0\x08\x00\x00\xC3"
16.35 + "linux" "@_ZNK13CCSWeaponInfo14GetWeaponPriceEv"
16.36 + "mac" "@_ZNK13CCSWeaponInfo14GetWeaponPriceEv"
16.37 + }
16.38 + "CSWeaponDrop"//Wildcard first 6 bytes for CS:S DM
16.39 + {
16.40 + "library" "server"
16.41 + "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x89\x8D\x5C\x2A\x2A\x2A\xC6\x45\x2A\x2A\x8B\x8D\x5C\x2A\x2A\x2A\xE8"
16.42 + "linux" "@_ZN9CCSPlayer12CSWeaponDropEP17CBaseCombatWeaponbb"
16.43 + "mac" "@_ZN9CCSPlayer12CSWeaponDropEP17CBaseCombatWeaponbb"
16.44 + }
16.45 + "TerminateRound"
16.46 + {
16.47 + "library" "server"
16.48 + "windows" "\x83\xEC\x2A\x53\x8B\x5C\x2A\x2A\x55\x56\x57\x33\xF6\x8B\xE9\x33"
16.49 + "linux" "@_ZN12CCSGameRules14TerminateRoundEfi"
16.50 + "mac" "@_ZN12CCSGameRules14TerminateRoundEfi"
16.51 + }
16.52 + "GetTranslatedWeaponAlias"
16.53 + {
16.54 + "library" "server"
16.55 + "windows" "\xA1\x2A\x2A\x2A\x2A\x80\x2A\x00\x53"
16.56 + "linux" "@_Z24GetTranslatedWeaponAliasPKc"
16.57 + "mac" "@_Z24GetTranslatedWeaponAliasPKc"
16.58 + }
16.59 }
16.60 }
16.61 }
17.1 --- a/plugins/include/cstrike.inc Sun Jun 26 10:54:12 2011 -0400
17.2 +++ b/plugins/include/cstrike.inc Sun Jun 26 18:09:55 2011 -0400
17.3 @@ -45,6 +45,70 @@
17.4 #define CS_SLOT_GRENADE 3 /**< Grenade slot (will only return one grenade). */
17.5 #define CS_SLOT_C4 4 /**< C4 slot. */
17.6
17.7 +enum CSRoundEndReason
17.8 +{
17.9 + CSRoundEnd_TargetBombed = 0, // Target Successfully Bombed!
17.10 + CSRoundEnd_VIPEscaped, // The VIP has escaped!
17.11 + CSRoundEnd_VIPKilled, // VIP has been assassinated!
17.12 + CSRoundEnd_TerroristsEscaped, // The terrorists have escaped!
17.13 + CSRoundEnd_CTStoppedEscape, // The CTs have prevented most of the terrorists from escaping!
17.14 + CSRoundEnd_TerroristsStopped, // Escaping terrorists have all been neutralized!
17.15 + CSRoundEnd_BombDefused, // The bomb has been defused!
17.16 + CSRoundEnd_CTWin, // Counter-Terrorists Win!
17.17 + CSRoundEnd_TerroristWin, // Terrorists Win!
17.18 + CSRoundEnd_Draw, // Round Draw!
17.19 + CSRoundEnd_HostagesRescued, // All Hostages have been rescued!
17.20 + CSRoundEnd_TargetSaved, // Target has been saved!
17.21 + CSRoundEnd_HostagesNotRescued, // Hostages have not been rescued!
17.22 + CSRoundEnd_TerroristsNotEscaped, // Terrorists have not escaped!
17.23 + CSRoundEnd_VIPNotEscaped, // VIP has not escaped!
17.24 + CSRoundEnd_GameStart // Game Commencing!
17.25 +};
17.26 +
17.27 +/**
17.28 + * Called when a player attempts to purchase an item.
17.29 + * Return Plugin_Continue to allow the purchase or return a
17.30 + * higher action to deny.
17.31 + *
17.32 + * @param client Client index
17.33 + * @param weapon User input for weapon name
17.34 + */
17.35 +forward Action:CS_OnBuyCommand(client, const String:weapon[]);
17.36 +
17.37 +/**
17.38 + * Called when CSWeaponDrop is called
17.39 + * Return Plugin_Continue to allow the call or return a
17.40 + * higher action to deny.
17.41 + *
17.42 + * @param client Client index
17.43 + * @param weapon Weapon index
17.44 + */
17.45 +forward Action:CS_OnCSWeaponDrop(client, weaponIndex);
17.46 +
17.47 +/**
17.48 + * Called when game retrieves a weapon's price for a player.
17.49 + * Return Plugin_Continue to use default value or return a higher
17.50 + * action to use a newly-set price.
17.51 + *
17.52 + * @note This can be called multiple times per weapon purchase
17.53 + *
17.54 + * @param client Client index
17.55 + * @param weapon Weapon classname
17.56 + * @param price Buffer param for the price of the weapon
17.57 + */
17.58 +forward Action:CS_OnGetWeaponPrice(client, const String:weapon[], &price);
17.59 +
17.60 +/**
17.61 + * Called when TerminateRound is called.
17.62 + * Return Plugin_Continue to ignore, return Plugin_Changed to continue,
17.63 + * using the given delay and reason, or return Plugin_Handled or a higher
17.64 + * action to block TerminateRound from firing.
17.65 + *
17.66 + * @param delay Time (in seconds) until new round starts
17.67 + * @param reason Reason for round end
17.68 + */
17.69 +forward Action:CS_OnTerminateRound(&Float:delay, &CSRoundEndReason:reason);
17.70 +
17.71 /**
17.72 * Respawns a player.
17.73 *
17.74 @@ -65,6 +129,42 @@
17.75 native CS_SwitchTeam(client, team);
17.76
17.77 /**
17.78 + * Forces a player to drop or toss their weapon
17.79 + *
17.80 + * @param client Player's index.
17.81 + * @param weaponIndex Index of weapon to drop.
17.82 + * @param toss True to toss weapon (with velocity) or false to just drop weapon
17.83 + * @param blockhook Set to true to stop the corresponding CS_OnCSWeaponDrop
17.84 + *
17.85 + * @noreturn
17.86 + * @error Invalid client index, client not in game, or invalid weapon index.
17.87 + */
17.88 +native CS_DropWeapon(client, weaponIndex, bool:toss, bool:blockhook = false);
17.89 +
17.90 +/**
17.91 + * Forces round to end with a reason
17.92 + *
17.93 + * @param delay Time (in seconds) to delay before new round starts
17.94 + * @param reason Reason for the round ending
17.95 + * @param blockhook Set to true to stop the corresponding CS_OnTerminateRound
17.96 + * forward from being called.
17.97 + * @noreturn
17.98 + */
17.99 + native CS_TerminateRound(Float:delay, CSRoundEndReason:reason, bool:blockhook = false);
17.100 +
17.101 + /**
17.102 + * Gets a weapon name from a weapon alias
17.103 + *
17.104 + * @param alias Weapons alias to get weapon name for.
17.105 + * @param weapon Buffer to store weapons name
17.106 + * @param size Size of buffer to store the weapons name.
17.107 + * @noreturn
17.108 + *
17.109 + * @note Will set the buffer to the original alias if it is not an alias to a weapon.
17.110 + */
17.111 + native CS_GetTranslatedWeaponAlias(const String:alias[], String:weapon[], size);
17.112 +
17.113 +/**
17.114 * Do not edit below this line!
17.115 */
17.116 public Extension:__ext_cstrike =
17.117 @@ -84,5 +184,9 @@
17.118 {
17.119 MarkNativeAsOptional("CS_RespawnPlayer");
17.120 MarkNativeAsOptional("CS_SwitchTeam");
17.121 + MarkNativeAsOptional("CS_DropWeapon");
17.122 + MarkNativeAsOptional("CS_TerminateRound");
17.123 + MarkNativeAsOptional("CS_GetTranslatedWeaponAlias");
17.124 }
17.125 #endif
17.126 +