Merge.
authorNicholas Hastings <skamonkey@gmail.com>
Sun Jun 26 18:09:55 2011 -0400 (2011-06-26)
changeset 3315c069730eaa79
parent 3314 0b5a61f9f487
parent 3313 2ddc75e24c53
child 3316 e2eff7875978
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 = &wr;
   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 +