Initial commit.
This commit is contained in:
commit
a67ef4d482
332
AMBuildScript
Normal file
332
AMBuildScript
Normal file
@ -0,0 +1,332 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
import sys
|
||||
import ambuild.command as command
|
||||
from ambuild.command import SymlinkCommand
|
||||
|
||||
vboxhack = 0
|
||||
|
||||
class SM:
|
||||
def __init__(self):
|
||||
self.compiler = Cpp.Compiler()
|
||||
|
||||
#Build SDK info
|
||||
self.sdkInfo = { }
|
||||
self.sdkInfo['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '4',
|
||||
'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin']}
|
||||
|
||||
if AMBuild.mode == 'config':
|
||||
#Detect compilers
|
||||
self.compiler.DetectAll(AMBuild)
|
||||
|
||||
#Detect variables
|
||||
envvars = { 'MMSOURCE18': 'mmsource-1.8',
|
||||
'HL2SDKOBVALVE': 'hl2sdk-ob-valve',
|
||||
'SOURCEMOD13': 'sourcemod-1.3'
|
||||
}
|
||||
|
||||
#Must have a path for each envvar (file a bug if you don't like this)
|
||||
for i in envvars:
|
||||
if i in os.environ:
|
||||
path = os.environ[i]
|
||||
if not os.path.isdir(path):
|
||||
raise Exception('Path for {0} was not found: {1}'.format(i, path))
|
||||
else:
|
||||
head = os.getcwd()
|
||||
oldhead = None
|
||||
while head != None and head != oldhead:
|
||||
path = os.path.join(head, envvars[i])
|
||||
if os.path.isdir(path):
|
||||
break
|
||||
oldhead = head
|
||||
head, tail = os.path.split(head)
|
||||
if head == None or head == oldhead:
|
||||
raise Exception('Could not find a valid path for {0}'.format(i))
|
||||
AMBuild.cache.CacheVariable(i, path)
|
||||
|
||||
#Set up defines
|
||||
cxx = self.compiler.cxx
|
||||
if isinstance(cxx, Cpp.GCC):
|
||||
self.vendor = 'gcc'
|
||||
self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
|
||||
self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
|
||||
self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
|
||||
self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
|
||||
self.compiler.AddToListVar('CFLAGS', '-pipe')
|
||||
self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
|
||||
if cxx.majorVersion >= 4:
|
||||
self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wall')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Werror')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
|
||||
self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
|
||||
self.compiler.AddToListVar('CFLAGS', '-msse')
|
||||
self.compiler.AddToListVar('CFLAGS', '-m32')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
|
||||
self.compiler.AddToListVar('CFLAGS', '-static-libgcc')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
|
||||
self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
|
||||
elif isinstance(cxx, Cpp.MSVC):
|
||||
self.vendor = 'msvc'
|
||||
if AMBuild.options.debug == '1':
|
||||
self.compiler.AddToListVar('CFLAGS', '/MTd')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
|
||||
else:
|
||||
self.compiler.AddToListVar('CFLAGS', '/MT')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/GR-')
|
||||
self.compiler.AddToListVar('CFLAGS', '/W3')
|
||||
self.compiler.AddToListVar('CFLAGS', '/nologo')
|
||||
self.compiler.AddToListVar('CFLAGS', '/Zi')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/TP')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
|
||||
|
||||
#Optimization
|
||||
if AMBuild.options.opt == '1':
|
||||
self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
|
||||
if self.vendor == 'gcc':
|
||||
self.compiler.AddToListVar('CFLAGS', '-O3')
|
||||
elif self.vendor == 'msvc':
|
||||
self.compiler.AddToListVar('CFLAGS', '/Ox')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
|
||||
|
||||
#Debugging
|
||||
if AMBuild.options.debug == '1':
|
||||
self.compiler.AddToListVar('CDEFINES', 'DEBUG')
|
||||
self.compiler.AddToListVar('CDEFINES', '_DEBUG')
|
||||
if self.vendor == 'gcc':
|
||||
self.compiler.AddToListVar('CFLAGS', '-g3')
|
||||
elif self.vendor == 'msvc':
|
||||
self.compiler.AddToListVar('CFLAGS', '/Od')
|
||||
self.compiler.AddToListVar('CFLAGS', '/RTC1')
|
||||
|
||||
#Platform-specifics
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
self.compiler.AddToListVar('CDEFINES', '_LINUX')
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
self.compiler.AddToListVar('CFLAGS', ['-isysroot',
|
||||
'/Developer/SDKs/MacOSX10.5.sdk'])
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
|
||||
|
||||
# For OS X dylib versioning
|
||||
import re
|
||||
productFile = open(os.path.join(AMBuild.sourceFolder, 'buildbot', 'product.version'), 'r')
|
||||
productContents = productFile.read()
|
||||
productFile.close()
|
||||
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||
if m == None:
|
||||
self.version = '1.0.0'
|
||||
else:
|
||||
major, minor, release = m.groups()
|
||||
self.version = '{0}.{1}.{2}'.format(major, minor, release)
|
||||
AMBuild.cache.CacheVariable('version', self.version)
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
self.compiler.AddToListVar('CDEFINES', 'WIN32')
|
||||
self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
|
||||
|
||||
#Finish up
|
||||
self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
|
||||
self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
|
||||
self.compiler.AddToListVar('CINCLUDES',
|
||||
os.path.join(AMBuild.outputFolder, 'includes'))
|
||||
self.compiler.ToConfig(AMBuild, 'compiler')
|
||||
AMBuild.cache.CacheVariable('vendor', self.vendor)
|
||||
self.targetMap = { }
|
||||
AMBuild.cache.CacheVariable('targetMap', self.targetMap)
|
||||
else:
|
||||
self.compiler.FromConfig(AMBuild, 'compiler')
|
||||
self.targetMap = AMBuild.cache['targetMap']
|
||||
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'extension'))
|
||||
|
||||
self.mmsPath = AMBuild.cache['MMSOURCE18']
|
||||
|
||||
def DefaultCompiler(self):
|
||||
return self.compiler.Clone()
|
||||
|
||||
def JobMatters(self, jobname):
|
||||
file = sys._getframe().f_code.co_filename
|
||||
if AMBuild.mode == 'config':
|
||||
self.targetMap[jobname] = file
|
||||
return True
|
||||
if len(AMBuild.args) == 0:
|
||||
return True
|
||||
if not jobname in AMBuild.args:
|
||||
return False
|
||||
|
||||
def DefaultExtCompiler(self, path):
|
||||
compiler = self.DefaultCompiler()
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
|
||||
return compiler
|
||||
|
||||
def AutoVersion(self, folder, binary):
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
|
||||
binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
|
||||
elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
|
||||
binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
|
||||
binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
|
||||
else:
|
||||
return
|
||||
|
||||
def PreSetupHL2Job(self, job, builder, sdk):
|
||||
info = self.sdkInfo[sdk]
|
||||
sdkPath = AMBuild.cache[info['sdk']]
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
if sdk == 'ep1':
|
||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
||||
else:
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
||||
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
|
||||
if sdk in ['ep2v', 'l4d', 'l4d2']:
|
||||
for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']:
|
||||
link = os.path.join(workFolder, i)
|
||||
target = os.path.join(staticLibs, i)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
if vboxhack == 1:
|
||||
job.AddCommand(command.DirectCommand(['cp', '-f', target, link]))
|
||||
else:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
else:
|
||||
for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
|
||||
link = os.path.join(workFolder, i)
|
||||
target = os.path.join(staticLibs, i)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
if vboxhack == 1:
|
||||
job.AddCommand(command.DirectCommand(['cp', '-f', target, link]))
|
||||
else:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'mac')
|
||||
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
|
||||
for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']:
|
||||
link = os.path.join(workFolder, i)
|
||||
target = os.path.join(staticLibs, i)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
if vboxhack == 1:
|
||||
job.AddCommand(command.DirectCommand(['cp', '-f', target, link]))
|
||||
else:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||
if sdk == 'swarm':
|
||||
libs.append('interfaces')
|
||||
for lib in libs:
|
||||
libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
|
||||
builder.RebuildIfNewer(libPath)
|
||||
builder['POSTLINKFLAGS'].append(libPath)
|
||||
|
||||
def PostSetupHL2Job(self, job, builder, sdk):
|
||||
if AMBuild.target['platform'] in ['linux', 'darwin']:
|
||||
builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
|
||||
|
||||
def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
|
||||
compiler = self.DefaultExtCompiler(path)
|
||||
|
||||
mms = 'core'
|
||||
if sdk == 'ep1':
|
||||
mms += oldMms
|
||||
|
||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
|
||||
|
||||
info = self.sdkInfo
|
||||
compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
|
||||
|
||||
paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
|
||||
['public', 'tier0'], ['public', 'tier1']]
|
||||
if sdk == 'ep1' or sdk == 'darkm':
|
||||
paths.append(['public', 'dlls'])
|
||||
paths.append(['game_shared'])
|
||||
else:
|
||||
paths.append(['public', 'game', 'server'])
|
||||
paths.append(['game', 'shared'])
|
||||
paths.append(['common'])
|
||||
|
||||
info = self.sdkInfo[sdk]
|
||||
sdkPath = AMBuild.cache[info['sdk']]
|
||||
|
||||
compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
|
||||
|
||||
if sdk == 'swarm' and AMBuild.target['platform'] == 'windows':
|
||||
compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
|
||||
|
||||
if sdk == 'ep1':
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
||||
else:
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'mac')
|
||||
|
||||
for i in paths:
|
||||
compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
|
||||
|
||||
if not noLink:
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['-lm']
|
||||
if sdk in ['ep2v', 'l4d', 'l4d2']:
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
|
||||
else:
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
|
||||
|
||||
return compiler
|
||||
|
||||
sm = SM()
|
||||
globals = {
|
||||
'SM': sm
|
||||
}
|
||||
|
||||
#AMBuild.Include(os.path.join('buildbot', 'Versioning'), globals)
|
||||
|
||||
FileList = [
|
||||
['AMBuilder'],
|
||||
['buildbot', 'PackageScript']
|
||||
]
|
||||
|
||||
for parts in FileList:
|
||||
AMBuild.Include(os.path.join(*parts), globals)
|
||||
|
||||
34
AMBuilder
Normal file
34
AMBuilder
Normal file
@ -0,0 +1,34 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
|
||||
for i in SM.sdkInfo:
|
||||
sdk = SM.sdkInfo[i]
|
||||
if AMBuild.target['platform'] not in sdk['platform']:
|
||||
continue
|
||||
|
||||
compiler = SM.DefaultHL2Compiler('', i)
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD13'], 'public'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD13'], 'public', 'sourcepawn'))
|
||||
#compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD13'], 'public', 'jit'))
|
||||
#compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD13'], 'public', 'jit', 'x86'))
|
||||
|
||||
if compiler.cc.name == 'gcc':
|
||||
compiler['CFLAGS'].append('-Wno-parentheses')
|
||||
|
||||
if i != 'ep1':
|
||||
compiler['CDEFINES'].append('HOOKING_ENABLED')
|
||||
|
||||
name = 'connect.ext.' + sdk['ext']
|
||||
extension = AMBuild.AddJob(name)
|
||||
binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler)
|
||||
SM.PreSetupHL2Job(extension, binary, i)
|
||||
binary.AddSourceFiles('', [
|
||||
'extension.cpp',
|
||||
'asm/asm.c',
|
||||
'CDetour/detours.cpp',
|
||||
'sdk/smsdk_ext.cpp'
|
||||
])
|
||||
SM.PostSetupHL2Job(extension, binary, i)
|
||||
#SM.AutoVersion('extension', binary)
|
||||
binary.SendToJob()
|
||||
|
||||
98
CDetour/detourhelpers.h
Normal file
98
CDetour/detourhelpers.h
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||
#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||
|
||||
#if defined PLATFORM_LINUX
|
||||
#include <sys/mman.h>
|
||||
#define PAGE_SIZE 4096
|
||||
#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
|
||||
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
||||
#endif
|
||||
|
||||
struct patch_t
|
||||
{
|
||||
patch_t()
|
||||
{
|
||||
patch[0] = 0;
|
||||
bytes = 0;
|
||||
}
|
||||
unsigned char patch[20];
|
||||
size_t bytes;
|
||||
};
|
||||
|
||||
inline void ProtectMemory(void *addr, int length, int prot)
|
||||
{
|
||||
#if defined PLATFORM_LINUX
|
||||
void *addr2 = (void *)ALIGN(addr);
|
||||
mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
DWORD old_prot;
|
||||
VirtualProtect(addr, length, prot, &old_prot);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void SetMemPatchable(void *address, size_t size)
|
||||
{
|
||||
ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
inline void DoGatePatch(unsigned char *target, void *callback)
|
||||
{
|
||||
SetMemPatchable(target, 20);
|
||||
|
||||
target[0] = 0xFF; /* JMP */
|
||||
target[1] = 0x25; /* MEM32 */
|
||||
*(void **)(&target[2]) = callback;
|
||||
}
|
||||
|
||||
inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
|
||||
{
|
||||
ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
unsigned char *addr = (unsigned char *)address + offset;
|
||||
if (restore)
|
||||
{
|
||||
for (size_t i=0; i<patch->bytes; i++)
|
||||
{
|
||||
restore->patch[i] = addr[i];
|
||||
}
|
||||
restore->bytes = patch->bytes;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<patch->bytes; i++)
|
||||
{
|
||||
addr[i] = patch->patch[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||
192
CDetour/detours.cpp
Normal file
192
CDetour/detours.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
|
||||
*/
|
||||
|
||||
#include "detours.h"
|
||||
#include <asm/asm.h>
|
||||
|
||||
ISourcePawnEngine *CDetourManager::spengine = NULL;
|
||||
IGameConfig *CDetourManager::gameconf = NULL;
|
||||
|
||||
void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||
{
|
||||
CDetourManager::spengine = spengine;
|
||||
CDetourManager::gameconf = gameconf;
|
||||
}
|
||||
|
||||
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
|
||||
{
|
||||
CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
|
||||
if (detour)
|
||||
{
|
||||
if (!detour->Init(spengine, gameconf))
|
||||
{
|
||||
delete detour;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return detour;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
|
||||
{
|
||||
enabled = false;
|
||||
detoured = false;
|
||||
detour_address = NULL;
|
||||
detour_trampoline = NULL;
|
||||
this->signame = signame;
|
||||
this->detour_callback = callbackfunction;
|
||||
spengine = NULL;
|
||||
gameconf = NULL;
|
||||
this->trampoline = trampoline;
|
||||
}
|
||||
|
||||
bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||
{
|
||||
this->spengine = spengine;
|
||||
this->gameconf = gameconf;
|
||||
|
||||
if (!CreateDetour())
|
||||
{
|
||||
enabled = false;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
enabled = true;
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void CDetour::Destroy()
|
||||
{
|
||||
DeleteDetour();
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool CDetour::IsEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
bool CDetour::CreateDetour()
|
||||
{
|
||||
if (!gameconf->GetMemSig(signame, &detour_address))
|
||||
{
|
||||
g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!detour_address)
|
||||
{
|
||||
g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame);
|
||||
return false;
|
||||
}
|
||||
|
||||
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
|
||||
|
||||
/* First, save restore bits */
|
||||
for (size_t i=0; i<detour_restore.bytes; i++)
|
||||
{
|
||||
detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
|
||||
}
|
||||
|
||||
JitWriter wr;
|
||||
JitWriter *jit = ≀
|
||||
jit_uint32_t CodeSize = 0;
|
||||
|
||||
wr.outbase = NULL;
|
||||
wr.outptr = NULL;
|
||||
|
||||
jit_rewind:
|
||||
|
||||
/* Patch old bytes in */
|
||||
if (wr.outbase != NULL)
|
||||
{
|
||||
copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes);
|
||||
}
|
||||
wr.outptr += detour_restore.bytes;
|
||||
|
||||
/* Return to the original function */
|
||||
jitoffs_t call = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
|
||||
|
||||
if (wr.outbase == NULL)
|
||||
{
|
||||
CodeSize = wr.get_outputpos();
|
||||
wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize);
|
||||
spengine->SetReadWrite(wr.outbase);
|
||||
wr.outptr = wr.outbase;
|
||||
detour_trampoline = wr.outbase;
|
||||
goto jit_rewind;
|
||||
}
|
||||
|
||||
spengine->SetReadExecute(wr.outbase);
|
||||
|
||||
*trampoline = detour_trampoline;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDetour::DeleteDetour()
|
||||
{
|
||||
if (detoured)
|
||||
{
|
||||
DisableDetour();
|
||||
}
|
||||
|
||||
if (detour_trampoline)
|
||||
{
|
||||
/* Free the allocated trampoline memory */
|
||||
spengine->FreePageMemory(detour_trampoline);
|
||||
detour_trampoline = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CDetour::EnableDetour()
|
||||
{
|
||||
if (!detoured)
|
||||
{
|
||||
DoGatePatch((unsigned char *)detour_address, &detour_callback);
|
||||
detoured = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CDetour::DisableDetour()
|
||||
{
|
||||
if (detoured)
|
||||
{
|
||||
/* Remove the patch */
|
||||
ApplyPatch(detour_address, 0, &detour_restore, NULL);
|
||||
detoured = false;
|
||||
}
|
||||
}
|
||||
300
CDetour/detours.h
Normal file
300
CDetour/detours.h
Normal file
@ -0,0 +1,300 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||
#define _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||
|
||||
#include "extension.hpp"
|
||||
#include <jit/jit_helpers.h>
|
||||
#include <jit/x86/x86_macros.h>
|
||||
#include "detourhelpers.h"
|
||||
|
||||
/**
|
||||
* CDetours class for SourceMod Extensions by pRED*
|
||||
* detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
|
||||
* asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly
|
||||
* Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/)
|
||||
* Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp)
|
||||
*/
|
||||
|
||||
#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
|
||||
#define DETOUR_STATIC_CALL(name) (name##_Actual)
|
||||
|
||||
#define DETOUR_DECL_STATIC0(name, ret) \
|
||||
ret (*name##_Actual)(void) = NULL; \
|
||||
ret name(void)
|
||||
|
||||
#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
|
||||
ret (*name##_Actual)(p1type) = NULL; \
|
||||
ret name(p1type p1name)
|
||||
|
||||
#define DETOUR_DECL_STATIC2(name, ret, p1type, p1name, p2type, p2name) \
|
||||
ret (*name##_Actual)(p1type, p2type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER0(name, ret) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(); \
|
||||
static ret (name##Class::* name##_Actual)(void); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
|
||||
ret name##Class::name()
|
||||
|
||||
#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
|
||||
ret name##Class::name(p1type p1name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER5(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER7(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER8(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER9(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER10(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name)
|
||||
|
||||
#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
|
||||
#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
|
||||
|
||||
#define GET_STATIC_CALLBACK(name) (void *)&name
|
||||
#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
|
||||
|
||||
#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
|
||||
#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
|
||||
|
||||
|
||||
class GenericClass {};
|
||||
typedef void (GenericClass::*VoidFunc)();
|
||||
|
||||
inline void *GetCodeAddr(VoidFunc mfp)
|
||||
{
|
||||
return *(void **)&mfp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a member function pointer to a void pointer.
|
||||
* This relies on the assumption that the code address lies at mfp+0
|
||||
* This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
|
||||
* Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
|
||||
*/
|
||||
#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast<VoidFunc>(mfp))
|
||||
|
||||
class CDetourManager;
|
||||
|
||||
class CDetour
|
||||
{
|
||||
public:
|
||||
|
||||
bool IsEnabled();
|
||||
|
||||
/**
|
||||
* These would be somewhat self-explanatory I hope
|
||||
*/
|
||||
void EnableDetour();
|
||||
void DisableDetour();
|
||||
|
||||
void Destroy();
|
||||
|
||||
friend class CDetourManager;
|
||||
|
||||
protected:
|
||||
CDetour(void *callbackfunction, void **trampoline, const char *signame);
|
||||
|
||||
bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||
private:
|
||||
|
||||
/* These create/delete the allocated memory */
|
||||
bool CreateDetour();
|
||||
void DeleteDetour();
|
||||
|
||||
bool enabled;
|
||||
bool detoured;
|
||||
|
||||
patch_t detour_restore;
|
||||
/* Address of the detoured function */
|
||||
void *detour_address;
|
||||
/* Address of the allocated trampoline function */
|
||||
void *detour_trampoline;
|
||||
/* Address of the callback handler */
|
||||
void *detour_callback;
|
||||
/* The function pointer used to call our trampoline */
|
||||
void **trampoline;
|
||||
|
||||
const char *signame;
|
||||
ISourcePawnEngine *spengine;
|
||||
IGameConfig *gameconf;
|
||||
};
|
||||
|
||||
class CDetourManager
|
||||
{
|
||||
public:
|
||||
|
||||
static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||
|
||||
/**
|
||||
* Creates a new detour
|
||||
*
|
||||
* @param callbackfunction Void pointer to your detour callback function.
|
||||
* @param trampoline Address of the trampoline pointer
|
||||
* @param signame Section name containing a signature to fetch from the gamedata file.
|
||||
* @return A new CDetour pointer to control your detour.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
|
||||
*
|
||||
* Define a new class with the required function and a member function pointer to the same type:
|
||||
*
|
||||
* class CBaseServerDetour
|
||||
* {
|
||||
* public:
|
||||
* bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
||||
* static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
||||
* }
|
||||
*
|
||||
* void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
|
||||
* void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
|
||||
*
|
||||
* Creation:
|
||||
* CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
|
||||
* {
|
||||
* //pre hook code
|
||||
* bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
|
||||
* //post hook code
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* Note we changed the netadr_s reference into a void* to avoid needing to define the type
|
||||
*/
|
||||
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
|
||||
|
||||
friend class CBlocker;
|
||||
friend class CDetour;
|
||||
|
||||
private:
|
||||
static ISourcePawnEngine *spengine;
|
||||
static IGameConfig *gameconf;
|
||||
};
|
||||
|
||||
#define DECL_DETOUR(name) \
|
||||
CDetour *name##_Detour = NULL;
|
||||
|
||||
#define CREATE_DETOUR(name) \
|
||||
name##_Detour = DETOUR_CREATE_MEMBER(name, #name); \
|
||||
if (name##_Detour != NULL) \
|
||||
{ \
|
||||
name##_Detour->EnableDetour(); \
|
||||
} else { \
|
||||
snprintf(error, maxlen, "Failed to create " #name " detour, check error log.\n"); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define DESTROY_DETOUR(name) \
|
||||
if (name##_Detour != NULL) \
|
||||
{ \
|
||||
name##_Detour->Destroy(); \
|
||||
name##_Detour = NULL; \
|
||||
}
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||
421
asm/asm.c
Normal file
421
asm/asm.c
Normal file
@ -0,0 +1,421 @@
|
||||
#include "asm.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#define REG_EAX 0
|
||||
#define REG_ECX 1
|
||||
#define REG_EDX 2
|
||||
#define REG_EBX 3
|
||||
|
||||
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
|
||||
#endif
|
||||
|
||||
extern void Msg( const char *, ... );
|
||||
|
||||
/**
|
||||
* Checks if a call to a fpic thunk has just been written into dest.
|
||||
* If found replaces it with a direct mov that sets the required register to the value of pc.
|
||||
*
|
||||
* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
|
||||
* @param pc The program counter value that needs to be set (usually the next address from the source).
|
||||
* @noreturn
|
||||
*/
|
||||
void check_thunks(unsigned char *dest, unsigned char *pc)
|
||||
{
|
||||
#if defined WIN32
|
||||
return;
|
||||
#else
|
||||
/* Step write address back 4 to the start of the function address */
|
||||
unsigned char *writeaddr = dest - 4;
|
||||
unsigned char *calloffset = *(unsigned char **)writeaddr;
|
||||
unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
|
||||
|
||||
/* Lookup name of function being called */
|
||||
if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
|
||||
{
|
||||
//a thunk maybe?
|
||||
char movByte = IA32_MOV_REG_IMM;
|
||||
|
||||
/* Calculate the correct mov opcode */
|
||||
switch (*(calladdr+1))
|
||||
{
|
||||
case 0x04:
|
||||
{
|
||||
movByte += REG_EAX;
|
||||
break;
|
||||
}
|
||||
case 0x1C:
|
||||
{
|
||||
movByte += REG_EBX;
|
||||
break;
|
||||
}
|
||||
case 0x0C:
|
||||
{
|
||||
movByte += REG_ECX;
|
||||
break;
|
||||
}
|
||||
case 0x14:
|
||||
{
|
||||
movByte += REG_EDX;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Msg("Unknown thunk: %c\n", *(calladdr+1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move our write address back one to where the call opcode was */
|
||||
writeaddr--;
|
||||
|
||||
|
||||
/* Write our mov */
|
||||
*writeaddr = movByte;
|
||||
writeaddr++;
|
||||
|
||||
/* Write the value - The provided program counter value */
|
||||
*(void **)writeaddr = (void *)pc;
|
||||
writeaddr += 4;
|
||||
}
|
||||
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
//if dest is NULL, returns minimum number of bytes needed to be copied
|
||||
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
||||
//http://www.devmaster.net/forums/showthread.php?t=2311
|
||||
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
|
||||
int bytecount = 0;
|
||||
|
||||
while(bytecount < required_len && *func != 0xCC)
|
||||
{
|
||||
// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
|
||||
int operandSize = 4;
|
||||
int FPU = 0;
|
||||
int twoByte = 0;
|
||||
unsigned char opcode = 0x90;
|
||||
unsigned char modRM = 0xFF;
|
||||
while(*func == 0xF0 ||
|
||||
*func == 0xF2 ||
|
||||
*func == 0xF3 ||
|
||||
(*func & 0xFC) == 0x64 ||
|
||||
(*func & 0xF8) == 0xD8 ||
|
||||
(*func & 0x7E) == 0x62)
|
||||
{
|
||||
if(*func == 0x66)
|
||||
{
|
||||
operandSize = 2;
|
||||
}
|
||||
else if((*func & 0xF8) == 0xD8)
|
||||
{
|
||||
FPU = *func;
|
||||
if (dest)
|
||||
*dest++ = *func++;
|
||||
else
|
||||
func++;
|
||||
bytecount++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dest)
|
||||
*dest++ = *func++;
|
||||
else
|
||||
func++;
|
||||
bytecount++;
|
||||
}
|
||||
|
||||
// two-byte opcode byte
|
||||
if(*func == 0x0F)
|
||||
{
|
||||
twoByte = 1;
|
||||
if (dest)
|
||||
*dest++ = *func++;
|
||||
else
|
||||
func++;
|
||||
bytecount++;
|
||||
}
|
||||
|
||||
// opcode byte
|
||||
opcode = *func++;
|
||||
if (dest) *dest++ = opcode;
|
||||
bytecount++;
|
||||
|
||||
// mod R/M byte
|
||||
modRM = 0xFF;
|
||||
if(FPU)
|
||||
{
|
||||
if((opcode & 0xC0) != 0xC0)
|
||||
{
|
||||
modRM = opcode;
|
||||
}
|
||||
}
|
||||
else if(!twoByte)
|
||||
{
|
||||
if((opcode & 0xC4) == 0x00 ||
|
||||
(opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09) ||
|
||||
(opcode & 0xF0) == 0x80 ||
|
||||
(opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02 ||
|
||||
(opcode & 0xFC) == 0xD0 ||
|
||||
(opcode & 0xF6) == 0xF6)
|
||||
{
|
||||
modRM = *func++;
|
||||
if (dest) *dest++ = modRM;
|
||||
bytecount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D ||
|
||||
(opcode & 0xF0) == 0x30 ||
|
||||
opcode == 0x77 ||
|
||||
(opcode & 0xF0) == 0x80 ||
|
||||
(opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02 ||
|
||||
(opcode & 0xF8) == 0xC8)
|
||||
{
|
||||
// No mod R/M byte
|
||||
}
|
||||
else
|
||||
{
|
||||
modRM = *func++;
|
||||
if (dest) *dest++ = modRM;
|
||||
bytecount++;
|
||||
}
|
||||
}
|
||||
|
||||
// SIB
|
||||
if((modRM & 0x07) == 0x04 &&
|
||||
(modRM & 0xC0) != 0xC0)
|
||||
{
|
||||
if (dest)
|
||||
*dest++ = *func++; //SIB
|
||||
else
|
||||
func++;
|
||||
bytecount++;
|
||||
}
|
||||
|
||||
// mod R/M displacement
|
||||
|
||||
// Dword displacement, no base
|
||||
if((modRM & 0xC5) == 0x05) {
|
||||
if (dest) {
|
||||
*(unsigned int*)dest = *(unsigned int*)func;
|
||||
dest += 4;
|
||||
}
|
||||
func += 4;
|
||||
bytecount += 4;
|
||||
}
|
||||
|
||||
// Byte displacement
|
||||
if((modRM & 0xC0) == 0x40) {
|
||||
if (dest)
|
||||
*dest++ = *func++;
|
||||
else
|
||||
func++;
|
||||
bytecount++;
|
||||
}
|
||||
|
||||
// Dword displacement
|
||||
if((modRM & 0xC0) == 0x80) {
|
||||
if (dest) {
|
||||
*(unsigned int*)dest = *(unsigned int*)func;
|
||||
dest += 4;
|
||||
}
|
||||
func += 4;
|
||||
bytecount += 4;
|
||||
}
|
||||
|
||||
// immediate
|
||||
if(FPU)
|
||||
{
|
||||
// Can't have immediate operand
|
||||
}
|
||||
else if(!twoByte)
|
||||
{
|
||||
if((opcode & 0xC7) == 0x04 ||
|
||||
(opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
|
||||
(opcode & 0xF0) == 0x70 || // Jcc
|
||||
opcode == 0x80 ||
|
||||
opcode == 0x83 ||
|
||||
(opcode & 0xFD) == 0xA0 || // MOV
|
||||
opcode == 0xA8 || // TEST
|
||||
(opcode & 0xF8) == 0xB0 || // MOV
|
||||
(opcode & 0xFE) == 0xC0 || // RCL
|
||||
opcode == 0xC6 || // MOV
|
||||
opcode == 0xCD || // INT
|
||||
(opcode & 0xFE) == 0xD4 || // AAD/AAM
|
||||
(opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
|
||||
opcode == 0xEB ||
|
||||
opcode == 0xF6 && (modRM & 0x30) == 0x00) // TEST
|
||||
{
|
||||
if (dest)
|
||||
*dest++ = *func++;
|
||||
else
|
||||
func++;
|
||||
bytecount++;
|
||||
}
|
||||
else if((opcode & 0xF7) == 0xC2) // RET
|
||||
{
|
||||
if (dest) {
|
||||
*(unsigned short*)dest = *(unsigned short*)func;
|
||||
dest += 2;
|
||||
}
|
||||
func += 2;
|
||||
bytecount += 2;
|
||||
}
|
||||
else if((opcode & 0xFC) == 0x80 ||
|
||||
(opcode & 0xC7) == 0x05 ||
|
||||
(opcode & 0xF8) == 0xB8 ||
|
||||
(opcode & 0xFE) == 0xE8 || // CALL/Jcc
|
||||
(opcode & 0xFE) == 0x68 ||
|
||||
(opcode & 0xFC) == 0xA0 ||
|
||||
(opcode & 0xEE) == 0xA8 ||
|
||||
opcode == 0xC7 ||
|
||||
opcode == 0xF7 && (modRM & 0x30) == 0x00)
|
||||
{
|
||||
if (dest) {
|
||||
//Fix CALL/JMP offset
|
||||
if ((opcode & 0xFE) == 0xE8) {
|
||||
if (operandSize == 4)
|
||||
{
|
||||
*(long*)dest = ((func + *(long*)func) - dest);
|
||||
|
||||
//pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
|
||||
check_thunks(dest+4, func+4);
|
||||
}
|
||||
else
|
||||
*(short*)dest = ((func + *(short*)func) - dest);
|
||||
|
||||
} else {
|
||||
if (operandSize == 4)
|
||||
*(unsigned long*)dest = *(unsigned long*)func;
|
||||
else
|
||||
*(unsigned short*)dest = *(unsigned short*)func;
|
||||
}
|
||||
dest += operandSize;
|
||||
}
|
||||
func += operandSize;
|
||||
bytecount += operandSize;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(opcode == 0xBA || // BT
|
||||
opcode == 0x0F || // 3DNow!
|
||||
(opcode & 0xFC) == 0x70 || // PSLLW
|
||||
(opcode & 0xF7) == 0xA4 || // SHLD
|
||||
opcode == 0xC2 ||
|
||||
opcode == 0xC4 ||
|
||||
opcode == 0xC5 ||
|
||||
opcode == 0xC6)
|
||||
{
|
||||
if (dest)
|
||||
*dest++ = *func++;
|
||||
else
|
||||
func++;
|
||||
}
|
||||
else if((opcode & 0xF0) == 0x80) // Jcc -i
|
||||
{
|
||||
if (dest) {
|
||||
if (operandSize == 4)
|
||||
*(unsigned long*)dest = *(unsigned long*)func;
|
||||
else
|
||||
*(unsigned short*)dest = *(unsigned short*)func;
|
||||
|
||||
dest += operandSize;
|
||||
}
|
||||
func += operandSize;
|
||||
bytecount += operandSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytecount;
|
||||
}
|
||||
|
||||
//insert a specific JMP instruction at the given location
|
||||
void inject_jmp(void* src, void* dest) {
|
||||
*(unsigned char*)src = OP_JMP;
|
||||
*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
|
||||
}
|
||||
|
||||
//fill a given block with NOPs
|
||||
void fill_nop(void* src, unsigned int len) {
|
||||
unsigned char* src2 = (unsigned char*)src;
|
||||
while (len) {
|
||||
*src2++ = OP_NOP;
|
||||
--len;
|
||||
}
|
||||
}
|
||||
|
||||
void* eval_jump(void* src) {
|
||||
unsigned char* addr = (unsigned char*)src;
|
||||
|
||||
if (!addr) return 0;
|
||||
|
||||
//import table jump
|
||||
if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
|
||||
addr += 2;
|
||||
addr = *(unsigned char**)addr;
|
||||
//TODO: if addr points into the IAT
|
||||
return *(void**)addr;
|
||||
}
|
||||
|
||||
//8bit offset
|
||||
else if (addr[0] == OP_JMP_BYTE) {
|
||||
addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
|
||||
//mangled 32bit jump?
|
||||
if (addr[0] = OP_JMP) {
|
||||
addr = addr + *(int*)&addr[1];
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
/*
|
||||
//32bit offset
|
||||
else if (addr[0] == OP_JMP) {
|
||||
addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
|
||||
}
|
||||
*/
|
||||
|
||||
return addr;
|
||||
}
|
||||
/*
|
||||
from ms detours package
|
||||
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
|
||||
__try {
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pbAddress >= ((PBYTE)pDosHeader +
|
||||
pNtHeader->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
|
||||
pbAddress < ((PBYTE)pDosHeader +
|
||||
pNtHeader->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
|
||||
pNtHeader->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
40
asm/asm.h
Normal file
40
asm/asm.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef __ASM_H__
|
||||
#define __ASM_H__
|
||||
|
||||
#define OP_JMP 0xE9
|
||||
#define OP_JMP_SIZE 5
|
||||
|
||||
#define OP_NOP 0x90
|
||||
#define OP_NOP_SIZE 1
|
||||
|
||||
#define OP_PREFIX 0xFF
|
||||
#define OP_JMP_SEG 0x25
|
||||
|
||||
#define OP_JMP_BYTE 0xEB
|
||||
#define OP_JMP_BYTE_SIZE 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void check_thunks(unsigned char *dest, unsigned char *pc);
|
||||
|
||||
//if dest is NULL, returns minimum number of bytes needed to be copied
|
||||
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
||||
//http://www.devmaster.net/forums/showthread.php?t=2311
|
||||
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
|
||||
|
||||
//insert a specific JMP instruction at the given location
|
||||
void inject_jmp(void* src, void* dest);
|
||||
|
||||
//fill a given block with NOPs
|
||||
void fill_nop(void* src, unsigned int len);
|
||||
|
||||
//evaluate a JMP at the target
|
||||
void* eval_jump(void* src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__ASM_H__
|
||||
7
build.bat
Normal file
7
build.bat
Normal file
@ -0,0 +1,7 @@
|
||||
mkdir build
|
||||
cd build
|
||||
call "%VS100COMNTOOLS%\vsvars32.bat"
|
||||
..\configure.py
|
||||
build.py
|
||||
pause
|
||||
cd ..
|
||||
10
build.py
Normal file
10
build.py
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
import ambuild.runner as runner
|
||||
|
||||
run = runner.Runner()
|
||||
run.options.usage = '%prog [options] [job list]'
|
||||
run.options.add_option('-l', '--list-jobs', action='store_true', dest='list', help='print list of jobs')
|
||||
run.Build()
|
||||
|
||||
109
buildbot/PackageScript
Normal file
109
buildbot/PackageScript
Normal file
@ -0,0 +1,109 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
import shutil
|
||||
import ambuild.osutil as osutil
|
||||
from ambuild.command import Command
|
||||
|
||||
job = AMBuild.AddJob('package')
|
||||
|
||||
class DestroyPath(Command):
|
||||
def __init__(self, folder):
|
||||
Command.__init__(self)
|
||||
self.folder = folder
|
||||
|
||||
def destroy(self, path):
|
||||
entries = os.listdir(path)
|
||||
for entry in entries:
|
||||
newpath = os.path.join(path, entry)
|
||||
if os.path.isdir(newpath):
|
||||
self.destroy(newpath)
|
||||
os.rmdir(newpath)
|
||||
elif os.path.isfile(newpath):
|
||||
os.remove(newpath)
|
||||
|
||||
def run(self, runner, job):
|
||||
runner.PrintOut('rm -rf {0}/*'.format(self.folder))
|
||||
self.destroy(self.folder)
|
||||
|
||||
class CreateFolders(Command):
|
||||
def __init__(self, folders):
|
||||
Command.__init__(self)
|
||||
self.folders = folders
|
||||
|
||||
def run(self, runner, job):
|
||||
for folder in self.folders:
|
||||
path = os.path.join(*folder)
|
||||
runner.PrintOut('mkdir {0}'.format(path))
|
||||
os.makedirs(path)
|
||||
|
||||
#Shallow folder copy
|
||||
class CopyFolder(Command):
|
||||
def __init__(self, fromList, toList, excludes = []):
|
||||
Command.__init__(self)
|
||||
self.fromPath = os.path.join(AMBuild.sourceFolder, *fromList)
|
||||
self.toPath = os.path.join(*toList)
|
||||
self.excludes = excludes
|
||||
|
||||
def run(self, runner, job):
|
||||
entries = os.listdir(self.fromPath)
|
||||
for entry in entries:
|
||||
if entry in self.excludes:
|
||||
continue
|
||||
path = os.path.join(self.fromPath, entry)
|
||||
if not os.path.isfile(path):
|
||||
continue
|
||||
runner.PrintOut('copy {0} to {1}'.format(path, self.toPath))
|
||||
shutil.copy(path, self.toPath)
|
||||
|
||||
#Single file copy
|
||||
class CopyFile(Command):
|
||||
def __init__(self, fromFile, toPath):
|
||||
Command.__init__(self)
|
||||
self.fromFile = fromFile
|
||||
self.toPath = toPath
|
||||
|
||||
def run(self, runner, job):
|
||||
runner.PrintOut('copy {0} to {1}'.format(self.fromFile, self.toPath))
|
||||
shutil.copy(self.fromFile, self.toPath)
|
||||
|
||||
|
||||
folders = [['addons', 'sourcemod', 'extensions'], ['addons', 'sourcemod', 'gamedata'], ['addons', 'sourcemod', 'scripting', 'include']]
|
||||
|
||||
#Setup
|
||||
job.AddCommand(DestroyPath(os.path.join(AMBuild.outputFolder, 'package')))
|
||||
job.AddCommand(CreateFolders(folders))
|
||||
|
||||
#Copy Files
|
||||
job.AddCommand(CopyFile(os.path.join(AMBuild.sourceFolder, 'connect.games.txt'),
|
||||
os.path.join('addons', 'sourcemod', 'gamedata')))
|
||||
job.AddCommand(CopyFile(os.path.join(AMBuild.sourceFolder, 'connect.inc'),
|
||||
os.path.join('addons', 'sourcemod', 'scripting', 'include')))
|
||||
job.AddCommand(CopyFile(os.path.join(AMBuild.sourceFolder, 'connect.sp'),
|
||||
os.path.join('addons', 'sourcemod', 'scripting')))
|
||||
|
||||
bincopies = []
|
||||
|
||||
def AddNormalLibrary(name, dest):
|
||||
dest = os.path.join('addons', 'sourcemod', dest)
|
||||
bincopies.append(CopyFile(os.path.join('..', name, name + osutil.SharedLibSuffix()), dest))
|
||||
#pdb_list.append(name + '\\' + name + '.pdb')
|
||||
|
||||
def AddHL2Library(name, dest):
|
||||
for i in SM.sdkInfo:
|
||||
sdk = SM.sdkInfo[i]
|
||||
if AMBuild.target['platform'] not in sdk['platform']:
|
||||
continue
|
||||
AddNormalLibrary(name + '.ext.' + sdk['ext'], dest)
|
||||
|
||||
#pdb_list = []
|
||||
|
||||
AddHL2Library('connect', 'extensions')
|
||||
|
||||
job.AddCommandGroup(bincopies)
|
||||
|
||||
#if AMBuild.target['platform'] == 'windows':
|
||||
# pdblog = open(os.path.join(AMBuild.outputFolder, 'pdblog.txt'), 'wt')
|
||||
# for pdb in pdb_list:
|
||||
# pdblog.write(pdb + '\n')
|
||||
# pdblog.close()
|
||||
|
||||
79
buildbot/bootstrap.pl
Normal file
79
buildbot/bootstrap.pl
Normal file
@ -0,0 +1,79 @@
|
||||
#!/usr/bin/perl
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
|
||||
use strict;
|
||||
use Cwd;
|
||||
use File::Basename;
|
||||
use File::Path;
|
||||
|
||||
my ($myself, $path) = fileparse($0);
|
||||
chdir($path);
|
||||
|
||||
require 'helpers.pm';
|
||||
|
||||
#Go back above build dir
|
||||
chdir(Build::PathFormat('../..'));
|
||||
|
||||
#Get the source path.
|
||||
our ($root) = getcwd();
|
||||
|
||||
rmtree('OUTPUT');
|
||||
mkdir('OUTPUT') or die("Failed to create output folder: $!\n");
|
||||
chdir('OUTPUT');
|
||||
my ($result);
|
||||
print "Attempting to reconfigure...\n";
|
||||
|
||||
#update and configure shiz
|
||||
if ($^O eq "linux") {
|
||||
my @sdks = ('sourcemod-1.3', 'mmsource-1.8', 'hl2sdk-ob-valve');
|
||||
my ($sdk);
|
||||
foreach $sdk (@sdks) {
|
||||
print "Updating checkout of ", $sdk, " on ", $^O, "\n";
|
||||
$result = `hg pull -u /home/builds/common/$sdk`;
|
||||
print $result;
|
||||
}
|
||||
|
||||
$ENV{'SOURCEMOD13'} = '/home/builds/common/sourcemod-1.3';
|
||||
$ENV{'MMSOURCE18'} = '/home/builds/common/mmsource-1.8';
|
||||
|
||||
$ENV{'HL2SDKOBVALVE'} = '/home/builds/common/hl2sdk-ob-valve';
|
||||
} elsif ($^O eq "darwin") {
|
||||
my @sdks = ('sourcemod-1.3', 'mmsource-1.8', 'hl2sdk-ob-valve');
|
||||
my ($sdk);
|
||||
foreach $sdk (@sdks) {
|
||||
print "Updating checkout of ", $sdk, " on ", $^O, "\n";
|
||||
$result = `hg pull -u /Users/builds/builds/common/$sdk`;
|
||||
print $result;
|
||||
}
|
||||
|
||||
$ENV{'SOURCEMOD13'} = '/Users/builds/builds/common/sourcemod-1.3';
|
||||
$ENV{'MMSOURCE18'} = '/Users/builds/builds/common/mmsource-1.8';
|
||||
|
||||
$ENV{'HL2SDKOBVALVE'} = '/Users/builds/builds/common/hl2sdk-ob-valve';
|
||||
} else {
|
||||
my @sdks = ('sourcemod-1.3', 'mmsource-1.8', 'hl2sdk-ob-valve');
|
||||
my ($sdk);
|
||||
foreach $sdk (@sdks) {
|
||||
print "Updating checkout of ", $sdk, " on ", $^O, "\n";
|
||||
$result = `hg pull -u C:/Scripts/common/$sdk`;
|
||||
print $result;
|
||||
}
|
||||
|
||||
$ENV{'SOURCEMOD13'} = 'C:/Scripts/common/sourcemod-1.3';
|
||||
$ENV{'MMSOURCE18'} = 'C:/Scripts/common/mmsource-1.8';
|
||||
|
||||
$ENV{'HL2SDKOBVALVE'} = 'C:/Scripts/common/hl2sdk-ob-valve';
|
||||
}
|
||||
|
||||
#configure AMBuild
|
||||
if ($^O eq "linux") {
|
||||
$result = `CC=gcc-4.1 CXX=gcc-4.1 python3.1 ../build/configure.py --enable-optimize`;
|
||||
} elsif ($^O eq "darwin") {
|
||||
$result = `CC=gcc-4.2 CXX=gcc-4.2 python3.1 ../build/configure.py --enable-optimize`;
|
||||
} else {
|
||||
$result = `C:\\Python31\\Python.exe ..\\build\\configure.py --enable-optimize`;
|
||||
}
|
||||
print "$result\n";
|
||||
if ($? != 0) {
|
||||
die('Could not configure!');
|
||||
}
|
||||
94
buildbot/helpers.pm
Normal file
94
buildbot/helpers.pm
Normal file
@ -0,0 +1,94 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use Cwd;
|
||||
|
||||
package Build;
|
||||
|
||||
sub HgRevNum
|
||||
{
|
||||
my ($path) = (@_);
|
||||
my ($cd, $text, $rev);
|
||||
|
||||
$cd = Cwd::cwd();
|
||||
chdir($path);
|
||||
$text = `hg identify -n`;
|
||||
chdir($cd);
|
||||
|
||||
chomp $text;
|
||||
if ($text =~ /^(\d+)/)
|
||||
{
|
||||
return $1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub ProductVersion
|
||||
{
|
||||
my ($file) = (@_);
|
||||
my ($version);
|
||||
open(FILE, $file) or die "Could not open $file: $!\n";
|
||||
$version = <FILE>;
|
||||
close(FILE);
|
||||
chomp $version;
|
||||
return $version;
|
||||
}
|
||||
|
||||
sub Delete
|
||||
{
|
||||
my ($str)=(@_);
|
||||
if ($^O =~ /MSWin/)
|
||||
{
|
||||
Command("del /S /F /Q \"$str\"");
|
||||
Command("rmdir /S /Q \"$str\"");
|
||||
} else {
|
||||
Command("rm -rf $str");
|
||||
}
|
||||
return !(-e $str);
|
||||
}
|
||||
|
||||
sub Copy
|
||||
{
|
||||
my ($src,$dest)=(@_);
|
||||
if ($^O =~ /MSWin/)
|
||||
{
|
||||
Command("copy \"$src\" \"$dest\" /y");
|
||||
} else {
|
||||
Command("cp \"$src\" \"$dest\"");
|
||||
}
|
||||
return (-e $dest);
|
||||
}
|
||||
|
||||
sub Move
|
||||
{
|
||||
my ($src,$dest)=(@_);
|
||||
if ($^O =~ /MSWin/)
|
||||
{
|
||||
Command("move \"$src\" \"$dest\"");
|
||||
} else {
|
||||
Command("mv \"$src\" \"$dest\"");
|
||||
}
|
||||
return (-e $dest);
|
||||
}
|
||||
|
||||
sub Command
|
||||
{
|
||||
my($cmd)=(@_);
|
||||
print "$cmd\n";
|
||||
return `$cmd`;
|
||||
}
|
||||
|
||||
sub PathFormat
|
||||
{
|
||||
my ($str)=(@_);
|
||||
if ($^O =~ /MSWin/)
|
||||
{
|
||||
$str =~ s#/#\\#g;
|
||||
} else {
|
||||
$str =~ s#\\#/#g;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
return 1;
|
||||
82
buildbot/package.pl
Normal file
82
buildbot/package.pl
Normal file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use Cwd;
|
||||
use File::Basename;
|
||||
use Net::FTP;
|
||||
|
||||
my ($ftp_host, $ftp_user, $ftp_pass, $ftp_path);
|
||||
|
||||
$ftp_host = $ARGV[0];
|
||||
$ftp_user = $ARGV[1];
|
||||
$ftp_pass = $ARGV[2];
|
||||
$ftp_path = $ARGV[3];
|
||||
|
||||
my ($myself, $path) = fileparse($0);
|
||||
chdir($path);
|
||||
|
||||
require 'helpers.pm';
|
||||
|
||||
my ($version);
|
||||
$version = Build::ProductVersion(Build::PathFormat('product.version'));
|
||||
$version .= '-hg' . Build::HgRevNum('.');
|
||||
|
||||
# Append OS to package version
|
||||
if ($^O eq "darwin")
|
||||
{
|
||||
$version .= '-mac';
|
||||
}
|
||||
elsif ($^O =~ /MSWin/)
|
||||
{
|
||||
$version .= '-windows';
|
||||
}
|
||||
else
|
||||
{
|
||||
$version .= '-' . $^O;
|
||||
}
|
||||
|
||||
#Switch to the output folder.
|
||||
chdir(Build::PathFormat('../../OUTPUT/package'));
|
||||
|
||||
my ($filename);
|
||||
$filename = 'vanillaweps-' . $version;
|
||||
if ($^O eq "linux")
|
||||
{
|
||||
$filename .= '.tar.gz';
|
||||
print "tar zcvf $filename addons\n";
|
||||
system("tar zcvf $filename addons");
|
||||
}
|
||||
else
|
||||
{
|
||||
$filename .= '.zip';
|
||||
print "zip -r $filename addons\n";
|
||||
system("zip -r $filename addons");
|
||||
}
|
||||
|
||||
#my ($major,$minor) = ($version =~ /^(\d+)\.(\d+)/);
|
||||
#$ftp_path .= "/$major.$minor";
|
||||
|
||||
my ($ftp);
|
||||
|
||||
$ftp = Net::FTP->new($ftp_host, Debug => 0)
|
||||
or die "Cannot connect to host $ftp_host : $@";
|
||||
|
||||
$ftp->login($ftp_user, $ftp_pass)
|
||||
or die "Cannot connect to host $ftp_host as $ftp_user : " . $ftp->message . "\n";
|
||||
|
||||
if ($ftp_path ne '')
|
||||
{
|
||||
$ftp->cwd($ftp_path)
|
||||
or die "Cannot change to folder $ftp_path : " . $ftp->message . "\n";
|
||||
}
|
||||
|
||||
$ftp->binary();
|
||||
$ftp->put($filename)
|
||||
or die "Cannot drop file $filename ($ftp_path) : " . $ftp->message . "\n";
|
||||
|
||||
$ftp->close();
|
||||
|
||||
print "File sent to drop site as $filename -- build succeeded.\n";
|
||||
|
||||
exit(0);
|
||||
|
||||
1
buildbot/product.version
Normal file
1
buildbot/product.version
Normal file
@ -0,0 +1 @@
|
||||
1.0.0
|
||||
0
buildbot/pushbuild.txt
Normal file
0
buildbot/pushbuild.txt
Normal file
27
buildbot/startbuild.pl
Normal file
27
buildbot/startbuild.pl
Normal file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/perl
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
|
||||
use File::Basename;
|
||||
|
||||
my ($myself, $path) = fileparse($0);
|
||||
chdir($path);
|
||||
|
||||
require 'helpers.pm';
|
||||
|
||||
chdir('../../OUTPUT');
|
||||
|
||||
if ($^O eq "linux" || $^O eq "darwin") {
|
||||
system("python3.1 build.py 2>&1");
|
||||
} else {
|
||||
system("C:\\Python31\\python.exe build.py 2>&1");
|
||||
}
|
||||
|
||||
if ($? != 0)
|
||||
{
|
||||
die "Build failed: $!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
10
configure.py
Normal file
10
configure.py
Normal file
@ -0,0 +1,10 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
import ambuild.runner as runner
|
||||
|
||||
run = runner.Runner()
|
||||
run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
help='Enable debugging symbols')
|
||||
run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||
help='Enable optimization')
|
||||
run.Configure(sys.path[0])
|
||||
68
connect.games.txt
Normal file
68
connect.games.txt
Normal file
@ -0,0 +1,68 @@
|
||||
"Games"
|
||||
{
|
||||
"#default"
|
||||
{
|
||||
"#supported"
|
||||
{
|
||||
"engine" "orangebox_valve"
|
||||
}
|
||||
|
||||
"Offsets"
|
||||
{
|
||||
"ISteamGameServer__BeginAuthSession"
|
||||
{
|
||||
"linux" "20"
|
||||
"windows" "20"
|
||||
}
|
||||
|
||||
"ISteamGameServer__EndAuthSession"
|
||||
{
|
||||
"linux" "21"
|
||||
"windows" "21"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
{
|
||||
"CBaseServer__ConnectClient"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i"
|
||||
"windows" "\x81\xEC\x2A\x2A\x2A\x2A\x56\x68\x2A\x2A\x2A\x2A\x8B\xF1\xFF\x15\x2A\x2A\x2A\x2A\x8B\x06"
|
||||
}
|
||||
|
||||
"CBaseServer__CheckChallengeType"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
|
||||
"windows" "\x8B\x44\x24\x10\x83\xEC\x14"
|
||||
}
|
||||
|
||||
"CBaseServer__RejectConnection"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPc"
|
||||
"windows" "\x81\xEC\x2A\x2A\x2A\x2A\x56\x6A\xFF"
|
||||
}
|
||||
|
||||
"CBaseClient__SetSteamID"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
|
||||
"windows" "\x8B\x44\x24\x04\x8B\x10\x89\x51\x2A\x8B\x40\x2A\x89\x41\x2A\xC2\x04\x00"
|
||||
}
|
||||
|
||||
"CBaseServer__CheckMasterServerRequestRestart"
|
||||
{
|
||||
"library" "engine"
|
||||
"windows" "\xE8\x2A\x2A\x2A\x2A\x83\x78\x08\x00\x74\x2A\xE8\x2A\x2A\x2A\x2A\x8B\x48\x08\x8B\x01\x8B\x50\x2A\xFF\xD2\x84\xC0"
|
||||
}
|
||||
|
||||
"Steam3Server"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_Z12Steam3Serverv"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
connect.inc
Normal file
22
connect.inc
Normal file
@ -0,0 +1,22 @@
|
||||
#if defined _connect_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _connect_included
|
||||
|
||||
forward bool:OnClientPreConnect(const String:name[], String:password[255], const String:ip[], const String:steamID[], String:rejectReason[255]);
|
||||
|
||||
public Extension:__ext_Connect =
|
||||
{
|
||||
name = "Connect",
|
||||
file = "connect.ext",
|
||||
#if defined AUTOLOAD_EXTENSIONS
|
||||
autoload = 1,
|
||||
#else
|
||||
autoload = 0,
|
||||
#endif
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
}
|
||||
24
connect.sp
Normal file
24
connect.sp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma semicolon 1 // Force strict semicolon mode.
|
||||
|
||||
#include <sourcemod>
|
||||
#define REQUIRE_EXTENSIONS
|
||||
#include <connect>
|
||||
|
||||
public bool:OnClientPreConnect(const String:name[], String:password[255], const String:ip[], const String:steamID[], String:rejectReason[255])
|
||||
{
|
||||
PrintToServer("----------------\nName: %s\nPassword: %s\nIP: %s\nSteamID: %s\n----------------", name, password, ip, steamID);
|
||||
|
||||
new AdminId:admin = FindAdminByIdentity(AUTHMETHOD_STEAM, steamID);
|
||||
|
||||
if (admin == INVALID_ADMIN_ID)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetAdminFlag(admin, Admin_Root))
|
||||
{
|
||||
GetConVarString(FindConVar("sv_password"), password, 255);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
392
extension.cpp
Normal file
392
extension.cpp
Normal file
@ -0,0 +1,392 @@
|
||||
/*
|
||||
* =============================================================================
|
||||
* Connect Extension
|
||||
* Copyright (C) 2011 Asher Baker (asherkin). All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "extension.hpp"
|
||||
#include "CDetour/detours.h"
|
||||
|
||||
#include "steam/steamclientpublic.h"
|
||||
|
||||
Connect g_connect;
|
||||
|
||||
SMEXT_LINK(&g_connect);
|
||||
|
||||
ICvar *icvar = NULL;
|
||||
|
||||
ConVar connectVersion("connect_version", SMEXT_CONF_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, SMEXT_CONF_DESCRIPTION " Version");
|
||||
|
||||
IGameConfig *g_pGameConf = NULL;
|
||||
|
||||
IForward *g_pConnectForward = NULL;
|
||||
|
||||
class IClient;
|
||||
class CBaseClient;
|
||||
|
||||
class CBaseServer;
|
||||
|
||||
typedef enum EBeginAuthSessionResult
|
||||
{
|
||||
k_EBeginAuthSessionResultOK = 0, // Ticket is valid for this game and this steamID.
|
||||
k_EBeginAuthSessionResultInvalidTicket = 1, // Ticket is not valid.
|
||||
k_EBeginAuthSessionResultDuplicateRequest = 2, // A ticket has already been submitted for this steamID
|
||||
k_EBeginAuthSessionResultInvalidVersion = 3, // Ticket is from an incompatible interface version
|
||||
k_EBeginAuthSessionResultGameMismatch = 4, // Ticket is not for this game
|
||||
k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired
|
||||
} EBeginAuthSessionResult;
|
||||
|
||||
typedef struct netadr_s
|
||||
{
|
||||
private:
|
||||
typedef enum
|
||||
{
|
||||
NA_NULL = 0,
|
||||
NA_LOOPBACK,
|
||||
NA_BROADCAST,
|
||||
NA_IP,
|
||||
} netadrtype_t;
|
||||
|
||||
public:
|
||||
netadrtype_t type;
|
||||
unsigned char ip[4];
|
||||
unsigned short port;
|
||||
} netadr_t;
|
||||
|
||||
char *CSteamID::Render() const
|
||||
{
|
||||
static char szSteamID[64];
|
||||
V_snprintf(szSteamID, sizeof(szSteamID), "STEAM_0:%u:%u", (m_unAccountID % 2) ? 1 : 0, (int32)m_unAccountID/2);
|
||||
return szSteamID;
|
||||
}
|
||||
|
||||
class CSteam3Server
|
||||
{
|
||||
public:
|
||||
void *m_pSteamGameServer;
|
||||
void *m_pSteamGameServerUtils;
|
||||
void *m_pSteamMasterServerUpdater;
|
||||
void *m_pSteamGameServerNetworking;
|
||||
void *m_pSteamGameServerStats;
|
||||
} *g_pSteam3Server;
|
||||
|
||||
CBaseServer *g_pBaseServer = NULL;
|
||||
|
||||
typedef CSteam3Server *(*Steam3ServerFunc)();
|
||||
|
||||
#ifndef WIN32
|
||||
typedef void (*RejectConnectionFunc)(CBaseServer *, const netadr_t &address, int iClientChallenge, char *pchReason);
|
||||
#else
|
||||
typedef void (__fastcall *RejectConnectionFunc)(CBaseServer *, void *, const netadr_t &address, int iClientChallenge, char *pchReason);
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
typedef void (*SetSteamIDFunc)(CBaseClient *, const CSteamID &steamID);
|
||||
#else
|
||||
typedef void (__fastcall *SetSteamIDFunc)(CBaseClient *, void *, const CSteamID &steamID);
|
||||
#endif
|
||||
|
||||
Steam3ServerFunc g_pSteam3ServerFunc = NULL;
|
||||
RejectConnectionFunc g_pRejectConnectionFunc = NULL;
|
||||
SetSteamIDFunc g_pSetSteamIDFunc = NULL;
|
||||
|
||||
CSteam3Server *Steam3Server()
|
||||
{
|
||||
if (!g_pSteam3ServerFunc)
|
||||
return NULL;
|
||||
|
||||
return g_pSteam3ServerFunc();
|
||||
}
|
||||
|
||||
void RejectConnection(const netadr_t &address, int iClientChallenge, char *pchReason)
|
||||
{
|
||||
if (!g_pRejectConnectionFunc || !g_pBaseServer)
|
||||
return;
|
||||
|
||||
#ifndef WIN32
|
||||
g_pRejectConnectionFunc(g_pBaseServer, address, iClientChallenge, pchReason);
|
||||
#else
|
||||
g_pRejectConnectionFunc(g_pBaseServer, NULL, address, iClientChallenge, pchReason);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetSteamID(CBaseClient *pClient, const CSteamID &steamID)
|
||||
{
|
||||
if (!pClient || !g_pSetSteamIDFunc)
|
||||
return;
|
||||
|
||||
#ifndef WIN32
|
||||
g_pSetSteamIDFunc(pClient, steamID);
|
||||
#else
|
||||
g_pSetSteamIDFunc(pClient, NULL, steamID);
|
||||
#endif
|
||||
}
|
||||
|
||||
class VFuncEmptyClass{};
|
||||
|
||||
int g_nBeginAuthSessionOffset = 0;
|
||||
int g_nEndAuthSessionOffset = 0;
|
||||
|
||||
EBeginAuthSessionResult BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID)
|
||||
{
|
||||
if (!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer || g_nBeginAuthSessionOffset == 0)
|
||||
return k_EBeginAuthSessionResultOK;
|
||||
|
||||
void **this_ptr = *(void ***)&g_pSteam3Server->m_pSteamGameServer;
|
||||
void **vtable = *(void ***)g_pSteam3Server->m_pSteamGameServer;
|
||||
void *func = vtable[g_nBeginAuthSessionOffset];
|
||||
|
||||
union {
|
||||
EBeginAuthSessionResult (VFuncEmptyClass::*mfpnew)(const void *, int, CSteamID);
|
||||
|
||||
#ifndef WIN32
|
||||
struct {
|
||||
void *addr;
|
||||
intptr_t adjustor;
|
||||
} s;
|
||||
} u;
|
||||
|
||||
u.s.addr = func;
|
||||
u.s.adjustor = 0;
|
||||
#else
|
||||
void *addr;
|
||||
} u;
|
||||
|
||||
u.addr = func;
|
||||
#endif
|
||||
|
||||
return (EBeginAuthSessionResult)(reinterpret_cast<VFuncEmptyClass*>(this_ptr)->*u.mfpnew)(pAuthTicket, cbAuthTicket, steamID);
|
||||
}
|
||||
|
||||
void EndAuthSession(CSteamID steamID)
|
||||
{
|
||||
if (!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer || g_nEndAuthSessionOffset == 0)
|
||||
return;
|
||||
|
||||
void **this_ptr = *(void ***)&g_pSteam3Server->m_pSteamGameServer;
|
||||
void **vtable = *(void ***)g_pSteam3Server->m_pSteamGameServer;
|
||||
void *func = vtable[g_nEndAuthSessionOffset];
|
||||
|
||||
union {
|
||||
void (VFuncEmptyClass::*mfpnew)(CSteamID);
|
||||
|
||||
#ifndef WIN32
|
||||
struct {
|
||||
void *addr;
|
||||
intptr_t adjustor;
|
||||
} s;
|
||||
} u;
|
||||
|
||||
u.s.addr = func;
|
||||
u.s.adjustor = 0;
|
||||
#else
|
||||
void *addr;
|
||||
} u;
|
||||
|
||||
u.addr = func;
|
||||
#endif
|
||||
|
||||
return (void)(reinterpret_cast<VFuncEmptyClass*>(this_ptr)->*u.mfpnew)(steamID);
|
||||
}
|
||||
|
||||
DECL_DETOUR(CBaseServer__ConnectClient);
|
||||
DECL_DETOUR(CBaseServer__CheckChallengeType);
|
||||
|
||||
bool g_bSuppressCheckChallengeType = false;
|
||||
|
||||
char passwordBuffer[255];
|
||||
DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient *, netadr_t &, address, int, nProtocol, int, iChallenge, int, iClientChallenge, int, nAuthProtocol, const char *, pchName, const char *, pchPassword, const char *, pCookie, int, cbCookie)
|
||||
{
|
||||
g_pBaseServer = (CBaseServer *)this;
|
||||
|
||||
if (pCookie == NULL || cbCookie < sizeof(uint64))
|
||||
{
|
||||
RejectConnection(address, iClientChallenge, "#GameUI_ServerRejectInvalidSteamCertLen");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char ipString[30];
|
||||
V_snprintf(ipString, sizeof(ipString), "%u.%u.%u.%u", address.ip[0], address.ip[1], address.ip[2], address.ip[3]);
|
||||
V_strncpy(passwordBuffer, pchPassword, 255);
|
||||
uint64 ullSteamID = *(uint64 *)pCookie;
|
||||
|
||||
void *pvTicket = (void *)((intptr_t)pCookie + sizeof(uint64));
|
||||
int cbTicket = cbCookie - sizeof(uint64);
|
||||
|
||||
EBeginAuthSessionResult result = BeginAuthSession(pvTicket, cbTicket, CSteamID(ullSteamID));
|
||||
if (result != k_EBeginAuthSessionResultOK)
|
||||
{
|
||||
EndAuthSession(CSteamID(ullSteamID));
|
||||
RejectConnection(address, iClientChallenge, "#GameUI_ServerRejectSteam");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char rejectReason[255];
|
||||
|
||||
g_pConnectForward->PushString(pchName);
|
||||
g_pConnectForward->PushStringEx(passwordBuffer, 255, SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
g_pConnectForward->PushString(ipString);
|
||||
g_pConnectForward->PushString(CSteamID(ullSteamID).Render());
|
||||
g_pConnectForward->PushStringEx(rejectReason, 255, SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
|
||||
cell_t retVal = 1;
|
||||
g_pConnectForward->Execute(&retVal);
|
||||
|
||||
if (retVal == 0)
|
||||
{
|
||||
EndAuthSession(CSteamID(ullSteamID));
|
||||
RejectConnection(address, iClientChallenge, rejectReason);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pchPassword = passwordBuffer;
|
||||
|
||||
g_bSuppressCheckChallengeType = true;
|
||||
return DETOUR_MEMBER_CALL(CBaseServer__ConnectClient)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie);
|
||||
}
|
||||
|
||||
DETOUR_DECL_MEMBER7(CBaseServer__CheckChallengeType, bool, CBaseClient *, pClient, int, nUserID, netadr_t &, address, int, nAuthProtocol, const char *, pCookie, int, cbCookie, int, iClientChallenge)
|
||||
{
|
||||
if (g_bSuppressCheckChallengeType)
|
||||
{
|
||||
uint64 ullSteamID = *(uint64 *)pCookie;
|
||||
SetSteamID(pClient, CSteamID(ullSteamID));
|
||||
|
||||
g_bSuppressCheckChallengeType = false;
|
||||
return true;
|
||||
} else {
|
||||
return DETOUR_MEMBER_CALL(CBaseServer__CheckChallengeType)(pClient, nUserID, address, nAuthProtocol, pCookie, cbCookie, iClientChallenge);
|
||||
}
|
||||
}
|
||||
|
||||
bool Connect::SDK_OnLoad(char *error, size_t maxlen, bool late)
|
||||
{
|
||||
char conf_error[255] = "";
|
||||
if (!gameconfs->LoadGameConfigFile("connect.games", &g_pGameConf, conf_error, sizeof(conf_error)))
|
||||
{
|
||||
if (conf_error[0])
|
||||
{
|
||||
snprintf(error, maxlen, "Could not read connect.games.txt: %s\n", conf_error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_pGameConf->GetMemSig("CBaseServer__RejectConnection", (void **)(&g_pRejectConnectionFunc)) || !g_pRejectConnectionFunc)
|
||||
{
|
||||
snprintf(error, maxlen, "Failed to find CBaseServer__RejectConnection function.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_pGameConf->GetMemSig("CBaseClient__SetSteamID", (void **)(&g_pSetSteamIDFunc)) || !g_pSetSteamIDFunc)
|
||||
{
|
||||
snprintf(error, maxlen, "Failed to find CBaseClient__SetSteamID function.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (!g_pGameConf->GetMemSig("Steam3Server", (void **)(&g_pSteam3ServerFunc)) || !g_pSteam3ServerFunc)
|
||||
{
|
||||
snprintf(error, maxlen, "Failed to find Steam3Server function.\n");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
void *address;
|
||||
if (!g_pGameConf->GetMemSig("CBaseServer__CheckMasterServerRequestRestart", &address) || !address)
|
||||
{
|
||||
snprintf(error, maxlen, "Failed to find CBaseServer__CheckMasterServerRequestRestart function.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//META_CONPRINTF("CheckMasterServerRequestRestart: %p\n", address);
|
||||
address = (void *)((intptr_t)address + 1); // Skip CALL opcode
|
||||
intptr_t offset = (intptr_t)(*(void **)address); // Get offset
|
||||
|
||||
g_pSteam3ServerFunc = (Steam3ServerFunc)((intptr_t)address + offset + sizeof(intptr_t));
|
||||
//META_CONPRINTF("Steam3Server: %p\n", g_pSteam3ServerFunc);
|
||||
#endif
|
||||
|
||||
g_pSteam3Server = Steam3Server();
|
||||
if (!g_pSteam3Server)
|
||||
{
|
||||
snprintf(error, maxlen, "Unable to get Steam3Server singleton.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
META_CONPRINTF("ISteamGameServer: %p\n", g_pSteam3Server->m_pSteamGameServer);
|
||||
META_CONPRINTF("ISteamUtils: %p\n", g_pSteam3Server->m_pSteamGameServerUtils);
|
||||
META_CONPRINTF("ISteamMasterServerUpdater: %p\n", g_pSteam3Server->m_pSteamMasterServerUpdater);
|
||||
META_CONPRINTF("ISteamNetworking: %p\n", g_pSteam3Server->m_pSteamGameServerNetworking);
|
||||
META_CONPRINTF("ISteamGameServerStats: %p\n", g_pSteam3Server->m_pSteamGameServerStats);
|
||||
*/
|
||||
|
||||
if (!g_pGameConf->GetOffset("ISteamGameServer__BeginAuthSession", &g_nBeginAuthSessionOffset) || g_nBeginAuthSessionOffset == 0)
|
||||
{
|
||||
snprintf(error, maxlen, "Failed to find ISteamGameServer__BeginAuthSession offset.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_pGameConf->GetOffset("ISteamGameServer__EndAuthSession", &g_nEndAuthSessionOffset) || g_nEndAuthSessionOffset == 0)
|
||||
{
|
||||
snprintf(error, maxlen, "Failed to find ISteamGameServer__EndAuthSession offset.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
|
||||
|
||||
CREATE_DETOUR(CBaseServer__ConnectClient);
|
||||
CREATE_DETOUR(CBaseServer__CheckChallengeType);
|
||||
|
||||
g_pConnectForward = g_pForwards->CreateForward("OnClientPreConnect", ET_LowEvent, 5, NULL, Param_String, Param_String, Param_String, Param_String, Param_String);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connect::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||
{
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
|
||||
if (!icvar)
|
||||
{
|
||||
snprintf(error, maxlen, "Could not find interface %s", CVAR_INTERFACE_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_pCVar = icvar;
|
||||
|
||||
ConVar_Register(0, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Connect::SDK_OnUnload()
|
||||
{
|
||||
g_pForwards->ReleaseForward(g_pConnectForward);
|
||||
|
||||
gameconfs->CloseGameConfigFile(g_pGameConf);
|
||||
}
|
||||
|
||||
bool Connect::SDK_OnMetamodUnload(char *error, size_t maxlen)
|
||||
{
|
||||
DESTROY_DETOUR(CBaseServer__ConnectClient);
|
||||
DESTROY_DETOUR(CBaseServer__CheckChallengeType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connect::RegisterConCommandBase(ConCommandBase *pCommand) {
|
||||
META_REGCVAR(pCommand);
|
||||
return true;
|
||||
}
|
||||
103
extension.hpp
Normal file
103
extension.hpp
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* =============================================================================
|
||||
* TF2 Items Extension
|
||||
* Copyright (C) 2009-2010 AzuiSleet, Asher Baker (asherkin). All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
|
||||
/**
|
||||
* @file extension.hpp
|
||||
* @brief Connect extension code header.
|
||||
*/
|
||||
|
||||
#include "smsdk_ext.hpp"
|
||||
|
||||
/**
|
||||
* @brief Sample implementation of the SDK Extension.
|
||||
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
|
||||
*/
|
||||
class Connect : public SDKExtension, public IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief This is called after the initial loading sequence has been processed.
|
||||
*
|
||||
* @param error Error message buffer.
|
||||
* @param maxlength Size of error message buffer.
|
||||
* @param late Whether or not the module was loaded after map load.
|
||||
* @return True to succeed loading, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnLoad(char *error, size_t maxlen, bool late);
|
||||
|
||||
/**
|
||||
* @brief This is called right before the extension is unloaded.
|
||||
*/
|
||||
virtual void SDK_OnUnload();
|
||||
|
||||
/**
|
||||
* @brief Called when the pause state is changed.
|
||||
*/
|
||||
//virtual void SDK_OnPauseChange(bool paused);
|
||||
|
||||
/**
|
||||
* @brief this is called when Core wants to know if your extension is working.
|
||||
*
|
||||
* @param error Error message buffer.
|
||||
* @param maxlength Size of error message buffer.
|
||||
* @return True if working, false otherwise.
|
||||
*/
|
||||
//virtual bool QueryRunning(char *error, size_t maxlen);
|
||||
public:
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
/**
|
||||
* @brief Called when Metamod is attached, before the extension version is called.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @param late Whether or not Metamod considers this a late load.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod is detaching, after the extension version is called.
|
||||
* NOTE: By default this is blocked unless sent from SourceMod.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnMetamodUnload(char *error, size_t maxlen);
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod's pause state is changing.
|
||||
* NOTE: By default this is blocked unless sent from SourceMod.
|
||||
*
|
||||
* @param paused Pause state being set.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlen);
|
||||
#endif
|
||||
public: //IConCommandBaseAccessor
|
||||
bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
};
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
23
msvc10/connect.sln
Normal file
23
msvc10/connect.sln
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "connect", "connect.vcxproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug - Orange Box Valve|Win32 = Debug - Orange Box Valve|Win32
|
||||
Release - Orange Box Valve|Win32 = Release - Orange Box Valve|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Orange Box Valve|Win32.ActiveCfg = Debug - Orange Box Valve|Win32
|
||||
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Orange Box Valve|Win32.Build.0 = Debug - Orange Box Valve|Win32
|
||||
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Orange Box Valve|Win32.ActiveCfg = Release - Orange Box Valve|Win32
|
||||
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Orange Box Valve|Win32.Build.0 = Release - Orange Box Valve|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
VisualSVNWorkingCopyRoot = ..
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
133
msvc10/connect.vcxproj
Normal file
133
msvc10/connect.vcxproj
Normal file
@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug - Orange Box Valve|Win32">
|
||||
<Configuration>Debug - Orange Box Valve</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release - Orange Box Valve|Win32">
|
||||
<Configuration>Release - Orange Box Valve</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B3E797CF-4E77-4C9D-B8A8-7589B6902206}</ProjectGuid>
|
||||
<RootNamespace>tf2items</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectName>connect</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'">$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'">false</LinkIncremental>
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'" />
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'" />
|
||||
<RunCodeAnalysis Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">false</RunCodeAnalysis>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">$(ProjectName).ext.2.ep2v</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'">$(ProjectName).ext.2.ep2v</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - Orange Box Valve|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/D SE_EPISODEONE=1 /D SE_DARKMESSIAH=2 /D SE_ORANGEBOX=3 /D SE_ORANGEBOXVALVE=4 /D SE_LEFT4DEAD=5 /D SE_LEFT4DEAD2=6 %(AdditionalOptions)</AdditionalOptions>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..;..\sdk;$(SOURCEMOD13)\public\;$(SOURCEMOD13)\public\sourcepawn\;$(HL2SDKOBVALVE)\game\shared\;$(HL2SDKOBVALVE)\game\server\;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(MMSOURCE18)\core;$(MMSOURCE18)\core\sourcehook;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=4;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(HL2SDKOBVALVE)\lib\public\tier0.lib;$(HL2SDKOBVALVE)\lib\public\tier1.lib;$(HL2SDKOBVALVE)\lib\public\vstdlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(ProjectName).ext.2.ep2v.dll</OutputFile>
|
||||
<IgnoreSpecificDefaultLibraries>LIBC;LIBCD;LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - Orange Box Valve|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/MP /D SE_EPISODEONE=1 /D SE_DARKMESSIAH=2 /D SE_ORANGEBOX=3 /D SE_ORANGEBOXVALVE=4 /D SE_LEFT4DEAD=5 /D SE_LEFT4DEAD2=6 %(AdditionalOptions)</AdditionalOptions>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..;..\sdk;$(SOURCEMOD13)\public\;$(SOURCEMOD13)\public\sourcepawn\;$(HL2SDKOBVALVE)\game\shared\;$(HL2SDKOBVALVE)\game\server\;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(MMSOURCE18)\core;$(MMSOURCE18)\core\sourcehook;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=4;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(HL2SDKOBVALVE)\lib\public\tier0.lib;$(HL2SDKOBVALVE)\lib\public\tier1.lib;$(HL2SDKOBVALVE)\lib\public\vstdlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ShowProgress>LinkVerbose</ShowProgress>
|
||||
<OutputFile>$(OutDir)$(ProjectName).ext.2.ep2v.dll</OutputFile>
|
||||
<IgnoreSpecificDefaultLibraries>LIBC;LIBCD;LIBCMTD;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\asm\asm.c" />
|
||||
<ClCompile Include="..\CDetour\detours.cpp" />
|
||||
<ClCompile Include="..\extension.cpp" />
|
||||
<ClCompile Include="..\sdk\smsdk_ext.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\asm\asm.h" />
|
||||
<ClInclude Include="..\CDetour\detourhelpers.h" />
|
||||
<ClInclude Include="..\CDetour\detours.h" />
|
||||
<ClInclude Include="..\extension.hpp" />
|
||||
<ClInclude Include="..\sdk\smsdk_config.hpp" />
|
||||
<ClInclude Include="..\sdk\smsdk_ext.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
50
msvc10/connect.vcxproj.filters
Normal file
50
msvc10/connect.vcxproj.filters
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="SourceMod SDK">
|
||||
<UniqueIdentifier>{31958233-BB2D-4e41-A8F9-CE8A4684F436}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\extension.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\sdk\smsdk_ext.cpp">
|
||||
<Filter>SourceMod SDK</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\CDetour\detours.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\asm\asm.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\extension.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\sdk\smsdk_config.hpp">
|
||||
<Filter>SourceMod SDK</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\sdk\smsdk_ext.hpp">
|
||||
<Filter>SourceMod SDK</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\CDetour\detourhelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\CDetour\detours.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\asm\asm.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
3
msvc10/connect.vcxproj.user
Normal file
3
msvc10/connect.vcxproj.user
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
78
sdk/smsdk_config.hpp
Normal file
78
sdk/smsdk_config.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* =============================================================================
|
||||
* connect Extension
|
||||
* Copyright (C) 2011 Asher Baker (asherkin). All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
|
||||
#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file smsdk_config.hpp
|
||||
* @brief Contains macros for configuring basic extension information.
|
||||
*/
|
||||
|
||||
/* Basic information exposed publicly */
|
||||
#define SMEXT_CONF_NAME "Connect"
|
||||
#define SMEXT_CONF_DESCRIPTION ""
|
||||
#define SMEXT_CONF_VERSION "1.0.0"
|
||||
#define SMEXT_CONF_AUTHOR "Asher \"asherkin\" Baker"
|
||||
#define SMEXT_CONF_URL "http://limetech.org/"
|
||||
#define SMEXT_CONF_LOGTAG "CONNECT"
|
||||
#define SMEXT_CONF_LICENSE "GPL"
|
||||
#define SMEXT_CONF_DATESTRING __DATE__
|
||||
|
||||
/**
|
||||
* @brief Exposes plugin's main interface.
|
||||
*/
|
||||
#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name;
|
||||
|
||||
/**
|
||||
* @brief Sets whether or not this plugin required Metamod.
|
||||
* NOTE: Uncomment to enable, comment to disable.
|
||||
*/
|
||||
#define SMEXT_CONF_METAMOD
|
||||
|
||||
/** Enable interfaces you want to use here by uncommenting lines */
|
||||
#define SMEXT_ENABLE_FORWARDSYS
|
||||
//#define SMEXT_ENABLE_HANDLESYS
|
||||
//#define SMEXT_ENABLE_PLAYERHELPERS
|
||||
//#define SMEXT_ENABLE_DBMANAGER
|
||||
#define SMEXT_ENABLE_GAMECONF
|
||||
//#define SMEXT_ENABLE_MEMUTILS
|
||||
//#define SMEXT_ENABLE_GAMEHELPERS
|
||||
//#define SMEXT_ENABLE_TIMERSYS
|
||||
//#define SMEXT_ENABLE_THREADER
|
||||
//#define SMEXT_ENABLE_LIBSYS
|
||||
//#define SMEXT_ENABLE_MENUS
|
||||
//#define SMEXT_ENABLE_ADTFACTORY
|
||||
//#define SMEXT_ENABLE_PLUGINSYS
|
||||
//#define SMEXT_ENABLE_ADMINSYS
|
||||
//#define SMEXT_ENABLE_TEXTPARSERS
|
||||
//#define SMEXT_ENABLE_USERMSGS
|
||||
//#define SMEXT_ENABLE_TRANSLATOR
|
||||
//#define SMEXT_ENABLE_NINVOKE
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
|
||||
465
sdk/smsdk_ext.cpp
Normal file
465
sdk/smsdk_ext.cpp
Normal file
@ -0,0 +1,465 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Base Extension Code
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "smsdk_ext.hpp"
|
||||
|
||||
/**
|
||||
* @file smsdk_ext.cpp
|
||||
* @brief Contains wrappers for making Extensions easier to write.
|
||||
*/
|
||||
|
||||
IExtension *myself = NULL; /**< Ourself */
|
||||
IShareSys *g_pShareSys = NULL; /**< Share system */
|
||||
IShareSys *sharesys = NULL; /**< Share system */
|
||||
ISourceMod *g_pSM = NULL; /**< SourceMod helpers */
|
||||
ISourceMod *smutils = NULL; /**< SourceMod helpers */
|
||||
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
IForwardManager *g_pForwards = NULL; /**< Forward system */
|
||||
IForwardManager *forwards = NULL; /**< Forward system */
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_HANDLESYS
|
||||
IHandleSys *g_pHandleSys = NULL; /**< Handle system */
|
||||
IHandleSys *handlesys = NULL; /**< Handle system */
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
IPlayerManager *playerhelpers = NULL; /**< Player helpers */
|
||||
#endif //SMEXT_ENABLE_PLAYERHELPERS
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
IDBManager *dbi = NULL; /**< DB Manager */
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
IGameConfigManager *gameconfs = NULL; /**< Game config manager */
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
IMemoryUtils *memutils = NULL;
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMEHELPERS
|
||||
IGameHelpers *gamehelpers = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TIMERSYS
|
||||
ITimerSystem *timersys = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADTFACTORY
|
||||
IADTFactory *adtfactory = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_THREADER
|
||||
IThreader *threader = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
ILibrarySys *libsys = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLUGINSYS
|
||||
SourceMod::IPluginManager *plsys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MENUS
|
||||
IMenuManager *menus = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADMINSYS
|
||||
IAdminSystem *adminsys = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TEXTPARSERS
|
||||
ITextParsers *textparsers = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
IUserMessages *usermsgs = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TRANSLATOR
|
||||
ITranslator *translator = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_NINVOKE
|
||||
INativeInterface *ninvoke = NULL;
|
||||
#endif
|
||||
|
||||
/** Exports the main interface */
|
||||
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
|
||||
{
|
||||
return g_pExtensionIface;
|
||||
}
|
||||
|
||||
SDKExtension::SDKExtension()
|
||||
{
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
m_SourceMMLoaded = false;
|
||||
m_WeAreUnloaded = false;
|
||||
m_WeGotPauseChange = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late)
|
||||
{
|
||||
g_pShareSys = sharesys = sys;
|
||||
myself = me;
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
m_WeAreUnloaded = true;
|
||||
|
||||
if (!m_SourceMMLoaded)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
snprintf(error, maxlength, "Metamod attach failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
SM_GET_IFACE(SOURCEMOD, g_pSM);
|
||||
smutils = g_pSM;
|
||||
#if defined SMEXT_ENABLE_HANDLESYS
|
||||
SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
|
||||
handlesys = g_pHandleSys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
SM_GET_IFACE(FORWARDMANAGER, g_pForwards);
|
||||
forwards = g_pForwards;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
SM_GET_IFACE(PLAYERMANAGER, playerhelpers);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
SM_GET_IFACE(DBI, dbi);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
SM_GET_IFACE(GAMECONFIG, gameconfs);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
SM_GET_IFACE(MEMORYUTILS, memutils);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_GAMEHELPERS
|
||||
SM_GET_IFACE(GAMEHELPERS, gamehelpers);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TIMERSYS
|
||||
SM_GET_IFACE(TIMERSYS, timersys);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADTFACTORY
|
||||
SM_GET_IFACE(ADTFACTORY, adtfactory);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_THREADER
|
||||
SM_GET_IFACE(THREADER, threader);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
SM_GET_IFACE(LIBRARYSYS, libsys);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLUGINSYS
|
||||
SM_GET_IFACE(PLUGINSYSTEM, plsys);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MENUS
|
||||
SM_GET_IFACE(MENUMANAGER, menus);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADMINSYS
|
||||
SM_GET_IFACE(ADMINSYS, adminsys);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TEXTPARSERS
|
||||
SM_GET_IFACE(TEXTPARSERS, textparsers);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
SM_GET_IFACE(USERMSGS, usermsgs);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TRANSLATOR
|
||||
SM_GET_IFACE(TRANSLATOR, translator);
|
||||
#endif
|
||||
|
||||
if (SDK_OnLoad(error, maxlength, late))
|
||||
{
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
m_WeAreUnloaded = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDKExtension::IsMetamodExtension()
|
||||
{
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SDKExtension::OnExtensionPauseChange(bool state)
|
||||
{
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
m_WeGotPauseChange = true;
|
||||
#endif
|
||||
SDK_OnPauseChange(state);
|
||||
}
|
||||
|
||||
void SDKExtension::OnExtensionsAllLoaded()
|
||||
{
|
||||
SDK_OnAllLoaded();
|
||||
}
|
||||
|
||||
void SDKExtension::OnExtensionUnload()
|
||||
{
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
m_WeAreUnloaded = true;
|
||||
#endif
|
||||
SDK_OnUnload();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionAuthor()
|
||||
{
|
||||
return SMEXT_CONF_AUTHOR;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionDateString()
|
||||
{
|
||||
return SMEXT_CONF_DATESTRING;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionDescription()
|
||||
{
|
||||
return SMEXT_CONF_DESCRIPTION;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionVerString()
|
||||
{
|
||||
return SMEXT_CONF_VERSION;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionName()
|
||||
{
|
||||
return SMEXT_CONF_NAME;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionTag()
|
||||
{
|
||||
return SMEXT_CONF_LOGTAG;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetExtensionURL()
|
||||
{
|
||||
return SMEXT_CONF_URL;
|
||||
}
|
||||
|
||||
bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDKExtension::SDK_OnUnload()
|
||||
{
|
||||
}
|
||||
|
||||
void SDKExtension::SDK_OnPauseChange(bool paused)
|
||||
{
|
||||
}
|
||||
|
||||
void SDKExtension::SDK_OnAllLoaded()
|
||||
{
|
||||
}
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
|
||||
PluginId g_PLID = 0; /**< Metamod plugin ID */
|
||||
ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */
|
||||
SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */
|
||||
ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */
|
||||
|
||||
IVEngineServer *engine = NULL; /**< IVEngineServer pointer */
|
||||
IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */
|
||||
|
||||
/** Exposes the extension to Metamod */
|
||||
SMM_API void *PL_EXPOSURE(const char *name, int *code)
|
||||
{
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
if (name && !strcmp(name, METAMOD_PLAPI_NAME))
|
||||
#else
|
||||
if (name && !strcmp(name, PLAPI_NAME))
|
||||
#endif
|
||||
{
|
||||
if (code)
|
||||
{
|
||||
*code = IFACE_OK;
|
||||
}
|
||||
return static_cast<void *>(g_pExtensionIface);
|
||||
}
|
||||
|
||||
if (code)
|
||||
{
|
||||
*code = IFACE_FAILED;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
#if !defined METAMOD_PLAPI_VERSION
|
||||
GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||
#else
|
||||
GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||
#endif
|
||||
|
||||
m_SourceMMLoaded = true;
|
||||
|
||||
return SDK_OnMetamodLoad(ismm, error, maxlen, late);
|
||||
}
|
||||
|
||||
bool SDKExtension::Unload(char *error, size_t maxlen)
|
||||
{
|
||||
if (!m_WeAreUnloaded)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
snprintf(error, maxlen, "This extension must be unloaded by SourceMod.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return SDK_OnMetamodUnload(error, maxlen);
|
||||
}
|
||||
|
||||
bool SDKExtension::Pause(char *error, size_t maxlen)
|
||||
{
|
||||
if (!m_WeGotPauseChange)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
snprintf(error, maxlen, "This extension must be paused by SourceMod.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_WeGotPauseChange = false;
|
||||
|
||||
return SDK_OnMetamodPauseChange(true, error, maxlen);
|
||||
}
|
||||
|
||||
bool SDKExtension::Unpause(char *error, size_t maxlen)
|
||||
{
|
||||
if (!m_WeGotPauseChange)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
snprintf(error, maxlen, "This extension must be unpaused by SourceMod.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_WeGotPauseChange = false;
|
||||
|
||||
return SDK_OnMetamodPauseChange(false, error, maxlen);
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetAuthor()
|
||||
{
|
||||
return GetExtensionAuthor();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetDate()
|
||||
{
|
||||
return GetExtensionDateString();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetDescription()
|
||||
{
|
||||
return GetExtensionDescription();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetLicense()
|
||||
{
|
||||
return SMEXT_CONF_LICENSE;
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetLogTag()
|
||||
{
|
||||
return GetExtensionTag();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetName()
|
||||
{
|
||||
return GetExtensionName();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetURL()
|
||||
{
|
||||
return GetExtensionURL();
|
||||
}
|
||||
|
||||
const char *SDKExtension::GetVersion()
|
||||
{
|
||||
return GetExtensionVerString();
|
||||
}
|
||||
|
||||
bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Overload a few things to prevent libstdc++ linking */
|
||||
#if defined __linux__ || defined __APPLE__
|
||||
extern "C" void __cxa_pure_virtual(void)
|
||||
{
|
||||
}
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
339
sdk/smsdk_ext.hpp
Normal file
339
sdk/smsdk_ext.hpp
Normal file
@ -0,0 +1,339 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Base Extension Code
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
|
||||
#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
|
||||
|
||||
/**
|
||||
* @file smsdk_ext.hpp
|
||||
* @brief Contains wrappers for making Extensions easier to write.
|
||||
*/
|
||||
|
||||
#include "smsdk_config.hpp"
|
||||
#include <IExtensionSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include <sm_platform.h>
|
||||
#include <ISourceMod.h>
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
#include <IForwardSys.h>
|
||||
#endif //SMEXT_ENABLE_FORWARDSYS
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
#include <IPlayerHelpers.h>
|
||||
#endif //SMEXT_ENABLE_PlAYERHELPERS
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
#include <IDBDriver.h>
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
#include <IGameConfigs.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
#include <IMemoryUtils.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_GAMEHELPERS
|
||||
#include <IGameHelpers.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TIMERSYS
|
||||
#include <ITimerSystem.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADTFACTORY
|
||||
#include <IADTFactory.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_THREADER
|
||||
#include <IThreader.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
#include <ILibrarySys.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLUGINSYS
|
||||
#include <IPluginSys.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MENUS
|
||||
#include <IMenuManager.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADMINSYS
|
||||
#include <IAdminSystem.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TEXTPARSERS
|
||||
#include <ITextParsers.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
#include <IUserMessages.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TRANSLATOR
|
||||
#include <ITranslator.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_NINVOKE
|
||||
#include <INativeInvoker.h>
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
#include <ISmmPlugin.h>
|
||||
#include <eiface.h>
|
||||
#endif
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
|
||||
class SDKExtension :
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
public ISmmPlugin,
|
||||
#endif
|
||||
public IExtensionInterface
|
||||
{
|
||||
public:
|
||||
/** Constructor */
|
||||
SDKExtension();
|
||||
public:
|
||||
/**
|
||||
* @brief This is called after the initial loading sequence has been processed.
|
||||
*
|
||||
* @param error Error message buffer.
|
||||
* @param maxlength Size of error message buffer.
|
||||
* @param late Whether or not the module was loaded after map load.
|
||||
* @return True to succeed loading, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
|
||||
|
||||
/**
|
||||
* @brief This is called right before the extension is unloaded.
|
||||
*/
|
||||
virtual void SDK_OnUnload();
|
||||
|
||||
/**
|
||||
* @brief This is called once all known extensions have been loaded.
|
||||
*/
|
||||
virtual void SDK_OnAllLoaded();
|
||||
|
||||
/**
|
||||
* @brief Called when the pause state is changed.
|
||||
*/
|
||||
virtual void SDK_OnPauseChange(bool paused);
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
/**
|
||||
* @brief Called when Metamod is attached, before the extension version is called.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @param late Whether or not Metamod considers this a late load.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod is detaching, after the extension version is called.
|
||||
* NOTE: By default this is blocked unless sent from SourceMod.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* @brief Called when Metamod's pause state is changing.
|
||||
* NOTE: By default this is blocked unless sent from SourceMod.
|
||||
*
|
||||
* @param paused Pause state being set.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of error buffer.
|
||||
* @return True to succeed, false to fail.
|
||||
*/
|
||||
virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
|
||||
#endif
|
||||
|
||||
public: //IExtensionInterface
|
||||
virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late);
|
||||
virtual void OnExtensionUnload();
|
||||
virtual void OnExtensionsAllLoaded();
|
||||
|
||||
/** Returns whether or not this is a Metamod-based extension */
|
||||
virtual bool IsMetamodExtension();
|
||||
|
||||
/**
|
||||
* @brief Called when the pause state changes.
|
||||
*
|
||||
* @param state True if being paused, false if being unpaused.
|
||||
*/
|
||||
virtual void OnExtensionPauseChange(bool state);
|
||||
|
||||
/** Returns name */
|
||||
virtual const char *GetExtensionName();
|
||||
/** Returns URL */
|
||||
virtual const char *GetExtensionURL();
|
||||
/** Returns log tag */
|
||||
virtual const char *GetExtensionTag();
|
||||
/** Returns author */
|
||||
virtual const char *GetExtensionAuthor();
|
||||
/** Returns version string */
|
||||
virtual const char *GetExtensionVerString();
|
||||
/** Returns description string */
|
||||
virtual const char *GetExtensionDescription();
|
||||
/** Returns date string */
|
||||
virtual const char *GetExtensionDateString();
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
public: //ISmmPlugin
|
||||
/** Called when the extension is attached to Metamod. */
|
||||
virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late);
|
||||
/** Returns the author to MM */
|
||||
virtual const char *GetAuthor();
|
||||
/** Returns the name to MM */
|
||||
virtual const char *GetName();
|
||||
/** Returns the description to MM */
|
||||
virtual const char *GetDescription();
|
||||
/** Returns the URL to MM */
|
||||
virtual const char *GetURL();
|
||||
/** Returns the license to MM */
|
||||
virtual const char *GetLicense();
|
||||
/** Returns the version string to MM */
|
||||
virtual const char *GetVersion();
|
||||
/** Returns the date string to MM */
|
||||
virtual const char *GetDate();
|
||||
/** Returns the logtag to MM */
|
||||
virtual const char *GetLogTag();
|
||||
/** Called on unload */
|
||||
virtual bool Unload(char *error, size_t maxlength);
|
||||
/** Called on pause */
|
||||
virtual bool Pause(char *error, size_t maxlength);
|
||||
/** Called on unpause */
|
||||
virtual bool Unpause(char *error, size_t maxlength);
|
||||
private:
|
||||
bool m_SourceMMLoaded;
|
||||
bool m_WeAreUnloaded;
|
||||
bool m_WeGotPauseChange;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern SDKExtension *g_pExtensionIface;
|
||||
extern IExtension *myself;
|
||||
|
||||
extern IShareSys *g_pShareSys;
|
||||
extern IShareSys *sharesys; /* Note: Newer name */
|
||||
extern ISourceMod *g_pSM;
|
||||
extern ISourceMod *smutils; /* Note: Newer name */
|
||||
|
||||
/* Optional interfaces are below */
|
||||
#if defined SMEXT_ENABLE_FORWARDSYS
|
||||
extern IForwardManager *g_pForwards;
|
||||
extern IForwardManager *forwards; /* Note: Newer name */
|
||||
#endif //SMEXT_ENABLE_FORWARDSYS
|
||||
#if defined SMEXT_ENABLE_HANDLESYS
|
||||
extern IHandleSys *g_pHandleSys;
|
||||
extern IHandleSys *handlesys; /* Note: Newer name */
|
||||
#endif //SMEXT_ENABLE_HANDLESYS
|
||||
#if defined SMEXT_ENABLE_PLAYERHELPERS
|
||||
extern IPlayerManager *playerhelpers;
|
||||
#endif //SMEXT_ENABLE_PLAYERHELPERS
|
||||
#if defined SMEXT_ENABLE_DBMANAGER
|
||||
extern IDBManager *dbi;
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_GAMECONF
|
||||
extern IGameConfigManager *gameconfs;
|
||||
#endif //SMEXT_ENABLE_DBMANAGER
|
||||
#if defined SMEXT_ENABLE_MEMUTILS
|
||||
extern IMemoryUtils *memutils;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_GAMEHELPERS
|
||||
extern IGameHelpers *gamehelpers;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TIMERSYS
|
||||
extern ITimerSystem *timersys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADTFACTORY
|
||||
extern IADTFactory *adtfactory;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_THREADER
|
||||
extern IThreader *threader;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
extern ILibrarySys *libsys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_PLUGINSYS
|
||||
extern SourceMod::IPluginManager *plsys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_MENUS
|
||||
extern IMenuManager *menus;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_ADMINSYS
|
||||
extern IAdminSystem *adminsys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
extern IUserMessages *usermsgs;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_TRANSLATOR
|
||||
extern ITranslator *translator;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_NINVOKE
|
||||
extern INativeInterface *ninvoke;
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
PLUGIN_GLOBALVARS();
|
||||
extern IVEngineServer *engine;
|
||||
extern IServerGameDLL *gamedll;
|
||||
#endif
|
||||
|
||||
/** Creates a SourceMod interface macro pair */
|
||||
#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION
|
||||
/** Automates retrieving SourceMod interfaces */
|
||||
#define SM_GET_IFACE(prefix, addr) \
|
||||
if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \
|
||||
{ \
|
||||
if (error != NULL && maxlength) \
|
||||
{ \
|
||||
size_t len = snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \
|
||||
if (len >= maxlength) \
|
||||
{ \
|
||||
error[maxlength - 1] = '\0'; \
|
||||
} \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */
|
||||
#define SM_GET_LATE_IFACE(prefix, addr) \
|
||||
g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)
|
||||
/** Validates a SourceMod interface pointer */
|
||||
#define SM_CHECK_IFACE(prefix, addr) \
|
||||
if (!addr) \
|
||||
{ \
|
||||
if (error != NULL && maxlength) \
|
||||
{ \
|
||||
size_t len = snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \
|
||||
if (len >= maxlength) \
|
||||
{ \
|
||||
error[maxlength - 1] = '\0'; \
|
||||
} \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
|
||||
Loading…
Reference in New Issue
Block a user