Merge pull request #15 from Kenzzer/ambuild2.2
Bring build scripts to AMBuild 2.2
This commit is contained in:
commit
7fc53679f0
165
.github/workflows/ci.yml
vendored
Normal file
165
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
name: Extension builder
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ action, master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ action, master ]
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-20.04, windows-2019, ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
cc: clang-10
|
||||||
|
cxx: clang++-10
|
||||||
|
- os: windows-2019
|
||||||
|
cc: msvc
|
||||||
|
- os: ubuntu-latest
|
||||||
|
cc: clang
|
||||||
|
cxx: clang++
|
||||||
|
- os: windows-latest
|
||||||
|
cc: msvc
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
|
||||||
|
name: ${{ matrix.os }} - ${{ matrix.cc }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
PROJECT: 'connect'
|
||||||
|
SDKS: 'css hl2dm dods tf2'
|
||||||
|
MMSOURCE_VERSION: '1.10'
|
||||||
|
SOURCEMOD_VERSION: '1.11'
|
||||||
|
CACHE_PATH: ${{ github.workspace }}/cache
|
||||||
|
steps:
|
||||||
|
- name: Concatenate SDK Names
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Paranoia
|
||||||
|
SDKS_VAR="${{env.SDKS}}"
|
||||||
|
# This will be used in our cache key
|
||||||
|
echo "SDKS_KEY=${SDKS_VAR//[[:blank:]]/}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Linux dependencies
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||||
|
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||||
|
linux-libc-dev:i386 lib32z1-dev ${{ matrix.cc }}
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
name: Setup Python 3.9
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
name: Repository checkout
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
path: extension
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
name: Cache dependencies
|
||||||
|
env:
|
||||||
|
cache-name: connect-cache
|
||||||
|
with:
|
||||||
|
path: ${{ env.CACHE_PATH }}
|
||||||
|
key: ${{ runner.os }}-build-${{ env.cache-name }}-sm${{ env.SOURCEMOD_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-${{ env.SDKS_KEY }}
|
||||||
|
|
||||||
|
- shell: bash
|
||||||
|
name: Install dependencies
|
||||||
|
run: |
|
||||||
|
mkdir -p "${{ env.CACHE_PATH }}"
|
||||||
|
cd "${{ env.CACHE_PATH }}"
|
||||||
|
shallow_checkout () {
|
||||||
|
# Param 1 is origin
|
||||||
|
# Param 2 is branch
|
||||||
|
# Param 3 is name
|
||||||
|
if [ ! -d "$3" ]; then
|
||||||
|
git clone "$1" --depth 1 --branch "$2" "$3"
|
||||||
|
fi
|
||||||
|
cd "$3"
|
||||||
|
git remote set-url origin "$1"
|
||||||
|
git fetch --depth 1 origin "$2"
|
||||||
|
git checkout --force --recurse-submodules FETCH_HEAD
|
||||||
|
git submodule init
|
||||||
|
git submodule update --depth 1
|
||||||
|
cd ..
|
||||||
|
}
|
||||||
|
# We are aware of what we are doing!
|
||||||
|
git config --global advice.detachedHead false
|
||||||
|
# Verify github cache, and see if we don't have the sdks already cloned and update them
|
||||||
|
for sdk in ${{ env.SDKS }}
|
||||||
|
do
|
||||||
|
shallow_checkout "https://github.com/alliedmodders/hl2sdk" "${sdk}" "hl2sdk-${sdk}"
|
||||||
|
done
|
||||||
|
shallow_checkout "https://github.com/alliedmodders/ambuild" "master" "ambuild"
|
||||||
|
shallow_checkout "https://github.com/alliedmodders/sourcemod" "${{env.SOURCEMOD_VERSION}}-dev" "sourcemod"
|
||||||
|
shallow_checkout "https://github.com/alliedmodders/metamod-source/" "${{env.MMSOURCE_VERSION}}-dev" "metamod-source"
|
||||||
|
# But maybe others aren't (also probably unnecessary because git actions but paranoia)
|
||||||
|
git config --global advice.detachedHead true
|
||||||
|
|
||||||
|
- name: Setup AMBuild
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd "${{ env.CACHE_PATH }}"
|
||||||
|
python -m pip install ./ambuild
|
||||||
|
|
||||||
|
- name: Select clang compiler
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
echo "CC=${{ matrix.cc }}" >> $GITHUB_ENV
|
||||||
|
echo "CXX=${{ matrix.cxx }}" >> $GITHUB_ENV
|
||||||
|
${{ matrix.cc }} --version
|
||||||
|
${{ matrix.cxx }} --version
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: bash
|
||||||
|
working-directory: extension
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
python ../configure.py --enable-auto-versioning --enable-optimize --sdks="${{ env.SDKS }}" --mms-path="${{ env.CACHE_PATH }}/metamod-source" --hl2sdk-root="${{ env.CACHE_PATH }}" --sm-path="${{ env.CACHE_PATH }}/sourcemod"
|
||||||
|
ambuild
|
||||||
|
|
||||||
|
PLATFORM="${{ runner.os }}"
|
||||||
|
FILENAME="$(cat ./includes/filename_versioning.txt)"
|
||||||
|
ZIP_FILENAME="${{ env.PROJECT }}-${FILENAME}-${PLATFORM,}.zip"
|
||||||
|
|
||||||
|
echo "ZIP_FILENAME=${ZIP_FILENAME}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Package release - Windows
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/action' && startsWith(matrix.os, 'windows-latest')
|
||||||
|
working-directory: extension/build/package
|
||||||
|
run: Compress-Archive -Path * -Destination ${{ env.ZIP_FILENAME }}
|
||||||
|
|
||||||
|
- name: Package release
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/action' && startsWith(matrix.os, 'ubuntu-latest')
|
||||||
|
working-directory: extension/build/package
|
||||||
|
run: zip -r "${{ env.ZIP_FILENAME }}" .
|
||||||
|
|
||||||
|
- name: Upload release
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/action' && (startsWith(matrix.os, 'ubuntu-latest') || startsWith(matrix.os, 'windows-latest'))
|
||||||
|
shell: bash
|
||||||
|
working-directory: extension/build/package
|
||||||
|
run: |
|
||||||
|
echo "Begin upload..."
|
||||||
|
AUTHORIZATION="$(echo -n '${{ secrets.USERNAME }}:${{ secrets.PASSWORD }}' | base64)"
|
||||||
|
echo "::add-mask::${AUTHORIZATION}"
|
||||||
|
|
||||||
|
HTTP_CODE=$(curl -XPOST -H "Authorization: Basic ${AUTHORIZATION}" -H "Content-Type: application/zip" --output /dev/null --silent --write-out "%{http_code}" --data-binary "@${{ env.ZIP_FILENAME }}" "https://builds.limetech.io/upload.php?project=${{ env.PROJECT }}&branch=action&filename=${{ env.ZIP_FILENAME }}")
|
||||||
|
if test ${HTTP_CODE} -ne 200; then
|
||||||
|
exit ${HTTP_CODE}
|
||||||
|
fi
|
||||||
|
echo "Upload successful!"
|
||||||
884
AMBuildScript
884
AMBuildScript
@ -1,364 +1,434 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os, sys
|
||||||
import sys
|
|
||||||
from ambuild.command import Command
|
|
||||||
from ambuild.command import ShellCommand
|
|
||||||
from ambuild.command import SymlinkCommand
|
|
||||||
|
|
||||||
class ExtractDebugInfoCommand(Command):
|
# Simple extensions do not need to modify this file.
|
||||||
def __init__(self, binary, outfile):
|
|
||||||
Command.__init__(self)
|
|
||||||
self.binary = binary
|
|
||||||
self.outfile = outfile
|
|
||||||
|
|
||||||
def run(self, runner, job):
|
class SDK(object):
|
||||||
if not self.binary.NeedsRelink(self.outfile):
|
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
||||||
return
|
self.folder = 'hl2sdk-' + dir
|
||||||
|
self.envvar = sdk
|
||||||
|
self.ext = ext
|
||||||
|
self.code = aDef
|
||||||
|
self.define = name
|
||||||
|
self.platform = platform
|
||||||
|
self.name = dir
|
||||||
|
self.path = None # Actual path
|
||||||
|
self.platformSpec = platform
|
||||||
|
|
||||||
if AMBuild.target['platform'] == 'linux':
|
# By default, nothing supports x64.
|
||||||
job.AddCommand(ShellCommand('objcopy --only-keep-debug ' + self.outfile + ' ' + self.outfile + '.dbg'))
|
if type(platform) is list:
|
||||||
job.AddCommand(ShellCommand('objcopy --strip-debug ' + self.outfile))
|
self.platformSpec = {p: ['x86'] for p in platform}
|
||||||
job.AddCommand(ShellCommand('objcopy --add-gnu-debuglink=' + os.path.basename(self.outfile) + '.dbg ' + self.outfile))
|
else:
|
||||||
elif AMBuild.target['platform'] == 'darwin':
|
self.platformSpec = platform
|
||||||
job.AddCommand(ShellCommand('dsymutil ' + self.outfile))
|
|
||||||
job.AddCommand(ShellCommand('strip -S ' + self.outfile))
|
|
||||||
|
|
||||||
class SM:
|
def shouldBuild(self, targets):
|
||||||
def __init__(self):
|
for cxx in targets:
|
||||||
self.compiler = Cpp.Compiler()
|
if cxx.target.platform in self.platformSpec:
|
||||||
|
if cxx.target.arch in self.platformSpec[cxx.target.platform]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
#Build SDK info
|
WinLinux = ['windows', 'linux']
|
||||||
self.possibleSdks = { }
|
TF2 = {
|
||||||
self.possibleSdks['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
|
'windows': ['x86', 'x86_64'],
|
||||||
'name': 'EPISODEONE', 'platform': []}
|
'linux': ['x86', 'x86_64']
|
||||||
self.possibleSdks['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
|
}
|
||||||
'name': 'ORANGEBOX', 'platform': []}
|
CSGO = {
|
||||||
self.possibleSdks['css'] = {'sdk': 'HL2SDKCSS', 'ext': '2.css', 'def': '6',
|
'windows': ['x86'],
|
||||||
'name': 'CSS', 'platform': []}
|
'linux': ['x86', 'x86_64']
|
||||||
self.possibleSdks['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '7',
|
|
||||||
'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin']}
|
|
||||||
self.possibleSdks['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '8',
|
|
||||||
'name': 'LEFT4DEAD', 'platform': []}
|
|
||||||
self.possibleSdks['l4d2'] = {'sdk': 'HL2SDKL4D2', 'ext': '2.l4d2', 'def': '9',
|
|
||||||
'name': 'LEFT4DEAD2', 'platform': []}
|
|
||||||
self.possibleSdks['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
|
|
||||||
'name': 'DARKMESSIAH', 'platform': []}
|
|
||||||
self.possibleSdks['swarm'] = {'sdk': 'HL2SDK-SWARM', 'ext': '2.swarm', 'def': '10',
|
|
||||||
'name': 'ALIENSWARM', 'platform': []}
|
|
||||||
self.possibleSdks['bgt'] = {'sdk': 'HL2SDK-BGT', 'ext': '2.bgt', 'def': '4',
|
|
||||||
'name': 'BLOODYGOODTIME', 'platform': []}
|
|
||||||
self.possibleSdks['eye'] = {'sdk': 'HL2SDK-EYE', 'ext': '2.eye', 'def': '5',
|
|
||||||
'name': 'EYE', 'platform': []}
|
|
||||||
self.possibleSdks['csgo'] = {'sdk': 'HL2SDKCSGO', 'ext': '2.csgo', 'def': '12',
|
|
||||||
'name': 'CSGO', 'platform': []}
|
|
||||||
|
|
||||||
self.sdkInfo = { }
|
|
||||||
|
|
||||||
if AMBuild.mode == 'config':
|
|
||||||
#Detect compilers
|
|
||||||
self.compiler.DetectAll(AMBuild)
|
|
||||||
|
|
||||||
#Detect variables
|
|
||||||
envvars = { 'MMSOURCE19': 'mmsource-1.9',
|
|
||||||
'SOURCEMOD14': 'sourcemod-1.7',
|
|
||||||
'HL2SDKCSS': 'hl2sdk-css',
|
|
||||||
'HL2SDKOBVALVE': 'hl2sdk-ob-valve',
|
|
||||||
'HL2SDKL4D': 'hl2sdk-l4d',
|
|
||||||
'HL2SDKL4D2': 'hl2sdk-l4d2',
|
|
||||||
'HL2SDKCSGO': 'hl2sdk-csgo'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if AMBuild.target['platform'] != 'darwin':
|
PossibleSDKs = {
|
||||||
envvars['HL2SDK'] = 'hl2sdk'
|
# 'episode1': SDK('HL2SDK', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
||||||
envvars['HL2SDKOB'] = 'hl2sdk-ob'
|
# 'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
|
||||||
|
# 'orangebox': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
||||||
|
# 'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
|
||||||
|
# 'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
||||||
|
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinux, 'css'),
|
||||||
|
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinux, 'hl2dm'),
|
||||||
|
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinux, 'dods'),
|
||||||
|
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinux, 'sdk2013'),
|
||||||
|
# 'bms': SDK('HL2SDKBMS', '2.bms', '11', 'BMS', WinLinux, 'bms'),
|
||||||
|
'tf2': SDK('HL2SDKTF2', '2.tf2', '12', 'TF2', TF2, 'tf2'),
|
||||||
|
'l4d': SDK('HL2SDKL4D', '2.l4d', '13', 'LEFT4DEAD', WinLinux, 'l4d'),
|
||||||
|
# 'nucleardawn': SDK('HL2SDKND', '2.nd', '14', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
|
||||||
|
# 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '15', 'CONTAGION', WinOnly, 'contagion'),
|
||||||
|
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '16', 'LEFT4DEAD2', WinLinux, 'l4d2'),
|
||||||
|
# 'swarm': SDK('HL2SDK-SWARM', '2.swarm', '17', 'ALIENSWARM', WinOnly, 'swarm'),
|
||||||
|
# 'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '18', 'PORTAL2', [], 'portal2'),
|
||||||
|
# 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
||||||
|
# 'blade': SDK('HL2SDKBLADE', '2.blade', '21', 'BLADE', WinLinux, 'blade'),
|
||||||
|
'csgo': SDK('HL2SDKCSGO', '2.csgo', '23', 'CSGO', CSGO, 'csgo'),
|
||||||
|
}
|
||||||
|
|
||||||
if AMBuild.target['platform'] == 'windows':
|
def ResolveEnvPath(env, folder):
|
||||||
envvars['HL2SDK-DARKM'] = 'hl2sdk-darkm'
|
if env in os.environ:
|
||||||
envvars['HL2SDK-SWARM'] = 'hl2sdk-swarm'
|
path = os.environ[env]
|
||||||
envvars['HL2SDK-BGT'] = 'hl2sdk-bgt'
|
if os.path.isdir(path):
|
||||||
envvars['HL2SDK-EYE'] = 'hl2sdk-eye'
|
return path
|
||||||
|
|
||||||
# Finds if a dict with `key` set to `value` is present on the dict of dicts `dictionary`
|
|
||||||
def findDictByKey(dictionary, key, value):
|
|
||||||
for index in dictionary:
|
|
||||||
elem = dictionary[index]
|
|
||||||
if elem[key] == value:
|
|
||||||
return (elem, index)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
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))
|
|
||||||
elif i.startswith('HL2SDK'):
|
|
||||||
(info, sdk) = findDictByKey(self.possibleSdks, 'sdk', i)
|
|
||||||
self.sdkInfo[sdk] = info
|
|
||||||
else:
|
|
||||||
head = os.getcwd()
|
head = os.getcwd()
|
||||||
oldhead = None
|
oldhead = None
|
||||||
while head != None and head != oldhead:
|
while head != None and head != oldhead:
|
||||||
path = os.path.join(head, envvars[i])
|
path = os.path.join(head, folder)
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
break
|
return path
|
||||||
oldhead = head
|
oldhead = head
|
||||||
head, tail = os.path.split(head)
|
head, tail = os.path.split(head)
|
||||||
if i.startswith('HL2SDK'):
|
|
||||||
if head != None and head != oldhead:
|
|
||||||
(info, sdk) = findDictByKey(self.possibleSdks, 'sdk', i)
|
|
||||||
self.sdkInfo[sdk] = info
|
|
||||||
elif head == None or head == oldhead:
|
|
||||||
raise Exception('Could not find a valid path for {0}'.format(i))
|
|
||||||
AMBuild.cache.CacheVariable(i, path)
|
|
||||||
|
|
||||||
if len(self.sdkInfo) < 1:
|
return None
|
||||||
raise Exception('At least one SDK must be available.')
|
|
||||||
|
|
||||||
AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
|
def Normalize(path):
|
||||||
|
return os.path.abspath(os.path.normpath(path))
|
||||||
|
|
||||||
#Set up defines
|
def SetArchFlags(compiler):
|
||||||
cxx = self.compiler.cxx
|
if compiler.behavior == 'gcc':
|
||||||
if isinstance(cxx, Cpp.CompatGCC):
|
if compiler.target.arch == 'x86_64':
|
||||||
if isinstance(cxx, Cpp.GCC):
|
compiler.cflags += ['-fPIC']
|
||||||
self.vendor = 'gcc'
|
elif compiler.like('msvc'):
|
||||||
elif isinstance(cxx, Cpp.Clang):
|
if compiler.target.arch == 'x86_64':
|
||||||
self.vendor = 'clang'
|
compiler.defines += ['WIN64']
|
||||||
self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
|
|
||||||
self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
|
class ExtensionConfig(object):
|
||||||
self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
|
def __init__(self):
|
||||||
self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
|
self.sdks = {}
|
||||||
self.compiler.AddToListVar('CFLAGS', '-pipe')
|
self.binaries = []
|
||||||
self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
|
self.extensions = []
|
||||||
if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
|
self.generated_headers = None
|
||||||
self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
|
self.productVersion = None
|
||||||
self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
|
self.mms_root = None
|
||||||
self.compiler.AddToListVar('CFLAGS', '-Wall')
|
self.sm_root = None
|
||||||
self.compiler.AddToListVar('CFLAGS', '-Werror')
|
self.all_targets = []
|
||||||
self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
|
self.target_archs = set()
|
||||||
self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
|
|
||||||
self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
|
if builder.options.targets:
|
||||||
self.compiler.AddToListVar('CFLAGS', '-msse')
|
target_archs = builder.options.targets.split(',')
|
||||||
self.compiler.AddToListVar('CFLAGS', '-g3')
|
|
||||||
self.compiler.AddToListVar('CFLAGS', '-m32')
|
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
|
|
||||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
|
|
||||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
|
|
||||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
|
|
||||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
|
|
||||||
if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 3) or \
|
|
||||||
(self.vendor == 'clang' and cxx.majorVersion >= 3):
|
|
||||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
|
|
||||||
self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
|
|
||||||
self.compiler.AddToListVar('CDEFINES', 'GNUC')
|
|
||||||
if self.vendor == 'gcc':
|
|
||||||
self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
|
|
||||||
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:
|
else:
|
||||||
self.compiler.AddToListVar('CFLAGS', '/MT')
|
target_archs = ['x86', 'x86_64']
|
||||||
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('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')
|
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'legacy_stdio_definitions.lib')
|
|
||||||
|
|
||||||
#Optimization
|
for arch in target_archs:
|
||||||
if AMBuild.options.opt == '1':
|
try:
|
||||||
self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
|
cxx = builder.DetectCxx(target_arch = arch)
|
||||||
if self.vendor == 'gcc' or self.vendor == 'clang':
|
self.target_archs.add(cxx.target.arch)
|
||||||
self.compiler.AddToListVar('CFLAGS', '-O3')
|
except Exception as e:
|
||||||
elif self.vendor == 'msvc':
|
# Error if archs were manually overridden.
|
||||||
self.compiler.AddToListVar('CFLAGS', '/Ox')
|
if builder.options.targets:
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
|
raise
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
|
print('Skipping target {}: {}'.format(arch, e))
|
||||||
|
continue
|
||||||
|
self.all_targets.append(cxx)
|
||||||
|
|
||||||
#Debugging
|
if not self.all_targets:
|
||||||
if AMBuild.options.debug == '1':
|
raise Exception('No suitable C/C++ compiler was found.')
|
||||||
self.compiler.AddToListVar('CDEFINES', 'DEBUG')
|
|
||||||
self.compiler.AddToListVar('CDEFINES', '_DEBUG')
|
|
||||||
if self.vendor == 'msvc':
|
|
||||||
self.compiler.AddToListVar('CFLAGS', '/Od')
|
|
||||||
self.compiler.AddToListVar('CFLAGS', '/RTC1')
|
|
||||||
|
|
||||||
#Platform-specifics
|
def use_auto_versioning(self):
|
||||||
if AMBuild.target['platform'] == 'linux':
|
return not getattr(builder.options, 'disable_auto_versioning', False)
|
||||||
self.compiler.AddToListVar('CDEFINES', 'POSIX')
|
|
||||||
self.compiler.AddToListVar('CDEFINES', '_LINUX')
|
def AddVersioning(self, binary):
|
||||||
if self.vendor == 'gcc':
|
if binary.compiler.target.platform == 'windows':
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
|
binary.sources += ['version.rc']
|
||||||
if self.vendor == 'clang':
|
binary.compiler.rcdefines += [
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
|
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
||||||
elif AMBuild.target['platform'] == 'darwin':
|
'RC_COMPILE',
|
||||||
self.compiler.AddToListVar('CDEFINES', 'OSX')
|
]
|
||||||
self.compiler.AddToListVar('CDEFINES', '_OSX')
|
elif binary.compiler.target.platform == 'mac':
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
|
if binary.type == 'library':
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
|
binary.compiler.postlink += [
|
||||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
|
'-compatibility_version', '1.0.0',
|
||||||
|
'-current_version', self.productVersion
|
||||||
|
]
|
||||||
|
if self.use_auto_versioning():
|
||||||
|
binary.compiler.sourcedeps += self.generated_headers
|
||||||
|
return binary
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tag(self):
|
||||||
|
if builder.options.debug == '1':
|
||||||
|
return 'Debug'
|
||||||
|
return 'Release'
|
||||||
|
|
||||||
|
def detectProductVersion(self):
|
||||||
|
builder.AddConfigureFile('product.version')
|
||||||
|
|
||||||
# For OS X dylib versioning
|
# For OS X dylib versioning
|
||||||
import re
|
import re
|
||||||
productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
|
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
||||||
productContents = productFile.read()
|
productContents = fp.read()
|
||||||
productFile.close()
|
m = re.match('(\\d+)\.(\\d+)\.(\\d+).*', productContents)
|
||||||
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
|
||||||
if m == None:
|
if m == None:
|
||||||
self.version = '1.0.0'
|
self.productVersion = '1.0.0'
|
||||||
else:
|
else:
|
||||||
major, minor, release = m.groups()
|
major, minor, release = m.groups()
|
||||||
self.version = '{0}.{1}.{2}'.format(major, minor, release)
|
self.productVersion = '{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
|
def detectSDKs(self):
|
||||||
self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
|
sdk_list = builder.options.sdks.split(' ')
|
||||||
self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
|
use_all = sdk_list[0] == 'all'
|
||||||
self.compiler.AddToListVar('CINCLUDES',
|
use_present = sdk_list[0] == 'present'
|
||||||
os.path.join(AMBuild.outputFolder, 'includes'))
|
|
||||||
self.compiler.ToConfig(AMBuild, 'compiler')
|
for sdk_name in PossibleSDKs:
|
||||||
AMBuild.cache.CacheVariable('vendor', self.vendor)
|
sdk = PossibleSDKs[sdk_name]
|
||||||
self.targetMap = { }
|
if sdk.shouldBuild(self.all_targets):
|
||||||
AMBuild.cache.CacheVariable('targetMap', self.targetMap)
|
if builder.options.hl2sdk_root:
|
||||||
|
sdk_path = os.path.join(os.path.realpath(builder.options.hl2sdk_root), sdk.folder)
|
||||||
else:
|
else:
|
||||||
self.sdkInfo = AMBuild.cache['sdkInfo']
|
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
||||||
self.compiler.FromConfig(AMBuild, 'compiler')
|
if sdk_path is None or not os.path.isdir(sdk_path):
|
||||||
self.targetMap = AMBuild.cache['targetMap']
|
if use_all or sdk_name in sdk_list:
|
||||||
|
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
||||||
|
continue
|
||||||
|
if use_all or use_present or sdk_name in sdk_list:
|
||||||
|
sdk.path = Normalize(sdk_path)
|
||||||
|
self.sdks[sdk_name] = sdk
|
||||||
|
|
||||||
if AMBuild.target['platform'] == 'windows':
|
if len(self.sdks) < 1:
|
||||||
self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'extension'))
|
raise Exception('At least one SDK must be available.')
|
||||||
self.mmsPath = AMBuild.cache['MMSOURCE19']
|
|
||||||
|
|
||||||
def DefaultCompiler(self):
|
if builder.options.sm_path:
|
||||||
return self.compiler.Clone()
|
self.sm_root = os.path.realpath(builder.options.sm_path)
|
||||||
|
|
||||||
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 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:
|
else:
|
||||||
return
|
self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod')
|
||||||
|
if not self.sm_root:
|
||||||
|
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central')
|
||||||
|
|
||||||
def ExtractDebugInfo(self, job, binary):
|
if not self.sm_root or not os.path.isdir(self.sm_root):
|
||||||
src = os.path.join('..', AMBuild.outputFolder, job.workFolder, binary.binaryFile)
|
raise Exception('Could not find a source copy of SourceMod')
|
||||||
job.AddCommand(ExtractDebugInfoCommand(binary, src))
|
self.sm_root = Normalize(self.sm_root)
|
||||||
|
|
||||||
def PreSetupHL2Job(self, job, builder, sdk):
|
if builder.options.mms_path:
|
||||||
info = self.sdkInfo[sdk]
|
self.mms_root = builder.options.mms_path
|
||||||
sdkPath = AMBuild.cache[info['sdk']]
|
|
||||||
if AMBuild.target['platform'] == 'linux':
|
|
||||||
if sdk == 'ep1':
|
|
||||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
|
||||||
else:
|
else:
|
||||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
||||||
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
|
if not self.mms_root:
|
||||||
if sdk in ['ep2v', 'css']:
|
self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source')
|
||||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib_srv.so', 'libtier0_srv.so']
|
if not self.mms_root:
|
||||||
for lib in libs:
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
|
||||||
link = os.path.join(workFolder, lib)
|
|
||||||
target = os.path.join(staticLibs, lib)
|
if not self.mms_root or not os.path.isdir(self.mms_root):
|
||||||
try:
|
raise Exception('Could not find a source copy of Metamod:Source')
|
||||||
os.lstat(link)
|
self.mms_root = Normalize(self.mms_root)
|
||||||
except:
|
|
||||||
job.AddCommand(SymlinkCommand(link, target))
|
def configure(self):
|
||||||
elif sdk in ['l4d', 'l4d2', 'csgo']:
|
|
||||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']
|
if not set(self.target_archs).issubset(['x86', 'x86_64']):
|
||||||
if sdk == 'csgo':
|
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
|
||||||
libs.append('interfaces_i486.a')
|
|
||||||
for lib in libs:
|
for cxx in self.all_targets:
|
||||||
link = os.path.join(workFolder, lib)
|
self.configure_cxx(cxx)
|
||||||
target = os.path.join(staticLibs, lib)
|
|
||||||
try:
|
def configure_cxx(self, cxx):
|
||||||
os.lstat(link)
|
if cxx.family == 'msvc':
|
||||||
except:
|
if cxx.version < 1900:
|
||||||
job.AddCommand(SymlinkCommand(link, target))
|
raise Exception('Only MSVC 2015 and later are supported, c++14 support is required.')
|
||||||
|
if cxx.family == 'gcc':
|
||||||
|
if cxx.version < 'gcc-4.9':
|
||||||
|
raise Exception('Only GCC versions 4.9 or greater are supported, c++14 support is required.')
|
||||||
|
if cxx.family == 'clang':
|
||||||
|
if cxx.version < 'clang-3.4':
|
||||||
|
raise Exception('Only clang versions 3.4 or greater are supported, c++14 support is required.')
|
||||||
|
|
||||||
|
if cxx.like('gcc'):
|
||||||
|
self.configure_gcc(cxx)
|
||||||
|
elif cxx.family == 'msvc':
|
||||||
|
self.configure_msvc(cxx)
|
||||||
|
cxx.defines += ['HAVE_STRING_H']
|
||||||
|
|
||||||
|
# Optimizaiton
|
||||||
|
if builder.options.opt == '1':
|
||||||
|
cxx.defines += ['NDEBUG']
|
||||||
|
|
||||||
|
# Debugging
|
||||||
|
if builder.options.debug == '1':
|
||||||
|
cxx.defines += ['DEBUG', '_DEBUG']
|
||||||
|
|
||||||
|
# Platform-specifics
|
||||||
|
if cxx.target.platform == 'linux':
|
||||||
|
self.configure_linux(cxx)
|
||||||
|
elif cxx.target.platform == 'mac':
|
||||||
|
self.configure_mac(cxx)
|
||||||
|
elif cxx.target.platform == 'windows':
|
||||||
|
self.configure_windows(cxx)
|
||||||
|
|
||||||
|
cxx.includes += [
|
||||||
|
os.path.join(self.sm_root, 'public'),
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.use_auto_versioning():
|
||||||
|
cxx.defines += ['SM_GENERATED_BUILD']
|
||||||
|
cxx.includes += [
|
||||||
|
os.path.join(builder.buildPath, 'includes')
|
||||||
|
]
|
||||||
|
|
||||||
|
def configure_gcc(self, cxx):
|
||||||
|
cxx.defines += [
|
||||||
|
'stricmp=strcasecmp',
|
||||||
|
'_stricmp=strcasecmp',
|
||||||
|
'_snprintf=snprintf',
|
||||||
|
'_vsnprintf=vsnprintf',
|
||||||
|
'typeof=__typeof__',
|
||||||
|
'HAVE_STDINT_H',
|
||||||
|
'GNUC',
|
||||||
|
]
|
||||||
|
cxx.cflags += [
|
||||||
|
'-pipe',
|
||||||
|
'-fno-strict-aliasing',
|
||||||
|
'-Wall',
|
||||||
|
'-Wno-unused',
|
||||||
|
'-Wno-switch',
|
||||||
|
'-Wno-array-bounds',
|
||||||
|
'-msse',
|
||||||
|
'-fvisibility=hidden',
|
||||||
|
]
|
||||||
|
cxx.cxxflags += [
|
||||||
|
'-std=c++14',
|
||||||
|
'-fno-threadsafe-statics',
|
||||||
|
'-Wno-non-virtual-dtor',
|
||||||
|
'-Wno-overloaded-virtual',
|
||||||
|
'-fvisibility-inlines-hidden',
|
||||||
|
'-fpermissive'
|
||||||
|
]
|
||||||
|
|
||||||
|
have_gcc = cxx.vendor == 'gcc'
|
||||||
|
have_clang = cxx.vendor == 'clang'
|
||||||
|
if cxx.version >= 'clang-3.9' or cxx.version == 'clang-3.4' or cxx.version > 'apple-clang-6.0':
|
||||||
|
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
||||||
|
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
||||||
|
cxx.cflags += ['-Wno-varargs']
|
||||||
|
if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0':
|
||||||
|
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
||||||
|
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
||||||
|
cxx.cxxflags += ['-Wno-null-dereference']
|
||||||
|
if have_clang or (cxx.version >= 'gcc-4.6'):
|
||||||
|
cxx.cflags += ['-Wno-narrowing']
|
||||||
|
if have_clang or (cxx.version >= 'gcc-4.7'):
|
||||||
|
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
|
||||||
|
if cxx.version >= 'gcc-4.8':
|
||||||
|
cxx.cflags += ['-Wno-unused-result']
|
||||||
|
if cxx.version >= 'gcc-9.0':
|
||||||
|
cxx.cxxflags += ['-Wno-class-memaccess', '-Wno-packed-not-aligned']
|
||||||
|
|
||||||
|
if have_clang:
|
||||||
|
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
|
||||||
|
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
|
||||||
|
cxx.cxxflags += ['-Wno-deprecated-register']
|
||||||
else:
|
else:
|
||||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']
|
cxx.cxxflags += ['-Wno-deprecated']
|
||||||
for lib in libs:
|
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||||
link = os.path.join(workFolder, lib)
|
|
||||||
target = os.path.join(staticLibs, lib)
|
|
||||||
try:
|
|
||||||
os.lstat(link)
|
|
||||||
except:
|
|
||||||
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)
|
|
||||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']
|
|
||||||
if sdk == 'csgo':
|
|
||||||
libs.append('interfaces_i486.a')
|
|
||||||
for lib in libs:
|
|
||||||
link = os.path.join(workFolder, lib)
|
|
||||||
target = os.path.join(staticLibs, lib)
|
|
||||||
try:
|
|
||||||
os.lstat(link)
|
|
||||||
except:
|
|
||||||
job.AddCommand(SymlinkCommand(link, target))
|
|
||||||
elif AMBuild.target['platform'] == 'windows':
|
|
||||||
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
|
||||||
if sdk in ['swarm', 'csgo']:
|
|
||||||
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):
|
# Work around SDK warnings.
|
||||||
if AMBuild.target['platform'] in ['linux', 'darwin']:
|
if cxx.version >= 'clang-10.0':
|
||||||
builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
|
cxx.cflags += ['-Wno-implicit-int-float-conversion', '-Wno-tautological-overlap-compare']
|
||||||
if sdk == 'csgo':
|
|
||||||
builder.AddObjectFiles(['interfaces_i486.a'])
|
|
||||||
|
|
||||||
def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
|
if have_gcc:
|
||||||
compiler = self.DefaultCompiler()
|
cxx.cflags += ['-mfpmath=sse']
|
||||||
|
|
||||||
mms = 'core'
|
if builder.options.opt == '1':
|
||||||
if sdk == 'ep1':
|
cxx.cflags += ['-O3']
|
||||||
mms += oldMms
|
|
||||||
|
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
|
def configure_msvc(self, cxx):
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
|
if builder.options.debug == '1':
|
||||||
|
cxx.cflags += ['/MTd']
|
||||||
|
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||||
|
else:
|
||||||
|
cxx.cflags += ['/MT']
|
||||||
|
cxx.defines += [
|
||||||
|
'_CRT_SECURE_NO_DEPRECATE',
|
||||||
|
'_CRT_SECURE_NO_WARNINGS',
|
||||||
|
'_CRT_NONSTDC_NO_DEPRECATE',
|
||||||
|
'_ITERATOR_DEBUG_LEVEL=0',
|
||||||
|
]
|
||||||
|
cxx.cflags += [
|
||||||
|
'/W3',
|
||||||
|
]
|
||||||
|
cxx.cxxflags += [
|
||||||
|
'/EHsc',
|
||||||
|
'/TP',
|
||||||
|
]
|
||||||
|
cxx.linkflags += [
|
||||||
|
'/MACHINE:X86',
|
||||||
|
'kernel32.lib',
|
||||||
|
'user32.lib',
|
||||||
|
'gdi32.lib',
|
||||||
|
'winspool.lib',
|
||||||
|
'comdlg32.lib',
|
||||||
|
'advapi32.lib',
|
||||||
|
'shell32.lib',
|
||||||
|
'ole32.lib',
|
||||||
|
'oleaut32.lib',
|
||||||
|
'uuid.lib',
|
||||||
|
'odbc32.lib',
|
||||||
|
'odbccp32.lib',
|
||||||
|
]
|
||||||
|
|
||||||
info = self.possibleSdks
|
if builder.options.opt == '1':
|
||||||
compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
|
cxx.cflags += ['/Ox', '/Zo']
|
||||||
|
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
|
||||||
|
|
||||||
paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'], ['public', 'tier0'], ['public', 'tier1']]
|
if builder.options.debug == '1':
|
||||||
if sdk == 'ep1' or sdk == 'darkm':
|
cxx.cflags += ['/Od', '/RTC1']
|
||||||
|
|
||||||
|
# This needs to be after our optimization flags which could otherwise disable it.
|
||||||
|
# Don't omit the frame pointer.
|
||||||
|
cxx.cflags += ['/Oy-']
|
||||||
|
|
||||||
|
def configure_linux(self, cxx):
|
||||||
|
cxx.defines += ['_LINUX', 'POSIX']
|
||||||
|
cxx.linkflags += ['-Wl,--exclude-libs,ALL', '-lm']
|
||||||
|
if cxx.vendor == 'gcc':
|
||||||
|
cxx.linkflags += ['-static-libgcc']
|
||||||
|
elif cxx.vendor == 'clang':
|
||||||
|
cxx.linkflags += ['-lgcc_eh']
|
||||||
|
cxx.linkflags += ['-static-libstdc++']
|
||||||
|
|
||||||
|
def configure_mac(self, cxx):
|
||||||
|
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
||||||
|
cxx.cflags += ['-mmacosx-version-min=10.7']
|
||||||
|
cxx.linkflags += [
|
||||||
|
'-mmacosx-version-min=10.7',
|
||||||
|
'-arch', 'i386',
|
||||||
|
'-lstdc++',
|
||||||
|
'-stdlib=libstdc++',
|
||||||
|
]
|
||||||
|
cxx.cxxflags += ['-stdlib=libstdc++']
|
||||||
|
|
||||||
|
def configure_windows(self, cxx):
|
||||||
|
cxx.defines += ['WIN32', '_WINDOWS']
|
||||||
|
|
||||||
|
def ConfigureForExtension(self, context, compiler):
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(context.currentSourcePath),
|
||||||
|
os.path.join(context.currentSourcePath, 'sdk'),
|
||||||
|
os.path.join(self.sm_root, 'public'),
|
||||||
|
os.path.join(self.sm_root, 'public', 'extensions'),
|
||||||
|
os.path.join(self.sm_root, 'sourcepawn', 'include'),
|
||||||
|
os.path.join(self.sm_root, 'public', 'amtl', 'amtl'),
|
||||||
|
os.path.join(self.sm_root, 'public', 'amtl'),
|
||||||
|
]
|
||||||
|
return compiler
|
||||||
|
|
||||||
|
def ConfigureForHL2(self, context, binary, sdk):
|
||||||
|
compiler = binary.compiler
|
||||||
|
SetArchFlags(compiler)
|
||||||
|
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(self.mms_root, 'core'),
|
||||||
|
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||||
|
]
|
||||||
|
|
||||||
|
defines = ['RAD_TELEMETRY_DISABLED']
|
||||||
|
defines += ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
||||||
|
compiler.defines += defines
|
||||||
|
|
||||||
|
paths = [
|
||||||
|
['public'],
|
||||||
|
['public', 'engine'],
|
||||||
|
['public', 'mathlib'],
|
||||||
|
['public', 'vstdlib'],
|
||||||
|
['public', 'tier0'],
|
||||||
|
['public', 'tier1']
|
||||||
|
]
|
||||||
|
if sdk.name == 'episode1' or sdk.name == 'darkm':
|
||||||
paths.append(['public', 'dlls'])
|
paths.append(['public', 'dlls'])
|
||||||
paths.append(['game_shared'])
|
paths.append(['game_shared'])
|
||||||
else:
|
else:
|
||||||
@ -367,59 +437,145 @@ class SM:
|
|||||||
paths.append(['game', 'shared'])
|
paths.append(['game', 'shared'])
|
||||||
paths.append(['common'])
|
paths.append(['common'])
|
||||||
|
|
||||||
info = self.sdkInfo[sdk]
|
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
|
||||||
sdkPath = AMBuild.cache[info['sdk']]
|
|
||||||
|
|
||||||
compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
|
if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
|
||||||
|
# The 2013 SDK already has these in public/tier0/basetypes.h
|
||||||
|
compiler.defines.remove('stricmp=strcasecmp')
|
||||||
|
compiler.defines.remove('_stricmp=strcasecmp')
|
||||||
|
compiler.defines.remove('_snprintf=snprintf')
|
||||||
|
compiler.defines.remove('_vsnprintf=vsnprintf')
|
||||||
|
|
||||||
if sdk in ['swarm','csgo']:
|
if compiler.like('msvc'):
|
||||||
if AMBuild.target['platform'] == 'windows':
|
compiler.defines += ['COMPILER_MSVC']
|
||||||
compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
|
if compiler.target.arch == 'x86':
|
||||||
|
compiler.defines += ['COMPILER_MSVC32']
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
compiler.defines += ['COMPILER_MSVC64']
|
||||||
|
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
||||||
else:
|
else:
|
||||||
compiler['CDEFINES'].extend(['COMPILER_GCC', 'POSIX'])
|
compiler.defines += ['COMPILER_GCC']
|
||||||
|
|
||||||
if sdk == 'ep1':
|
if compiler.target.arch == 'x86_64':
|
||||||
if AMBuild.target['platform'] == 'linux':
|
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
|
||||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
|
||||||
|
# For everything after Swarm, this needs to be defined for entity networking
|
||||||
|
# to work properly with sendprop value changes.
|
||||||
|
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
||||||
|
compiler.defines += ['NETWORK_VARS_ENABLED']
|
||||||
|
|
||||||
|
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
|
||||||
|
if compiler.target.platform in ['linux', 'mac']:
|
||||||
|
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||||
|
|
||||||
|
if compiler.target.platform == 'linux':
|
||||||
|
if sdk.name in ['csgo', 'blade']:
|
||||||
|
compiler.linkflags.remove('-static-libstdc++')
|
||||||
|
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||||
|
|
||||||
|
if compiler.target.platform == 'linux':
|
||||||
|
if sdk.name == 'episode1':
|
||||||
|
lib_folder = os.path.join(sdk.path, 'linux_sdk')
|
||||||
|
elif sdk.name in ['sdk2013', 'bms']:
|
||||||
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
|
||||||
else:
|
else:
|
||||||
if AMBuild.target['platform'] == 'linux':
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
||||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
elif compiler.target.platform == 'mac':
|
||||||
elif AMBuild.target['platform'] == 'darwin':
|
if sdk.name in ['sdk2013', 'bms']:
|
||||||
staticLibs = os.path.join(sdkPath, 'lib', 'mac')
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
for i in paths:
|
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
|
||||||
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', 'css']:
|
|
||||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0_srv.so']
|
|
||||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib_srv.so']
|
|
||||||
elif sdk in ['l4d', 'l4d2', 'csgo']:
|
|
||||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
|
|
||||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
|
|
||||||
else:
|
else:
|
||||||
compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
|
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
||||||
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
|
if compiler.target.platform in ['linux', 'mac']:
|
||||||
|
if sdk.name in ['sdk2013', 'bms'] or compiler.target.arch == 'x86_64':
|
||||||
sm = SM()
|
compiler.postlink += [
|
||||||
globals = {
|
os.path.join(lib_folder, 'tier1.a'),
|
||||||
'SM': sm
|
os.path.join(lib_folder, 'mathlib.a')
|
||||||
}
|
]
|
||||||
|
else:
|
||||||
AMBuild.Include(os.path.join('buildbot', 'Versioning'), globals)
|
compiler.postlink += [
|
||||||
|
os.path.join(lib_folder, 'tier1_i486.a'),
|
||||||
FileList = [
|
os.path.join(lib_folder, 'mathlib_i486.a')
|
||||||
['extension', 'AMBuilder'],
|
|
||||||
['buildbot', 'PackageScript'],
|
|
||||||
['buildbot', 'BreakpadSymbols']
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for parts in FileList:
|
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
||||||
AMBuild.Include(os.path.join(*parts), globals)
|
if compiler.target.arch == 'x86_64':
|
||||||
|
compiler.postlink += [os.path.join(lib_folder, 'interfaces.a')]
|
||||||
|
else:
|
||||||
|
compiler.postlink += [os.path.join(lib_folder, 'interfaces_i486.a')]
|
||||||
|
|
||||||
|
dynamic_libs = []
|
||||||
|
if compiler.target.platform == 'linux':
|
||||||
|
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
|
||||||
|
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
||||||
|
elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'mock']:
|
||||||
|
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
|
||||||
|
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
|
||||||
|
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
||||||
|
else:
|
||||||
|
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
||||||
|
elif compiler.target.platform == 'mac':
|
||||||
|
compiler.linkflags.append('-liconv')
|
||||||
|
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
||||||
|
elif compiler.target.platform == 'windows':
|
||||||
|
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||||
|
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
|
||||||
|
libs.append('interfaces')
|
||||||
|
for lib in libs:
|
||||||
|
if compiler.target.arch == 'x86':
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'public', 'win64', lib) + '.lib'
|
||||||
|
compiler.linkflags.append(lib_path)
|
||||||
|
|
||||||
|
for library in dynamic_libs:
|
||||||
|
source_path = os.path.join(lib_folder, library)
|
||||||
|
output_path = os.path.join(binary.localFolder, library)
|
||||||
|
|
||||||
|
# Ensure the output path exists.
|
||||||
|
context.AddFolder(binary.localFolder)
|
||||||
|
output = context.AddSymlink(source_path, output_path)
|
||||||
|
|
||||||
|
compiler.weaklinkdeps += [output]
|
||||||
|
compiler.linkflags[0:0] = [library]
|
||||||
|
|
||||||
|
return binary
|
||||||
|
|
||||||
|
def HL2Config(self, project, context, compiler, name, sdk):
|
||||||
|
binary = project.Configure(compiler, name,
|
||||||
|
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
|
||||||
|
self.AddVersioning(binary)
|
||||||
|
return self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
|
||||||
|
def HL2ExtConfig(self, project, context, compiler, name, sdk):
|
||||||
|
binary = project.Configure(compiler, name,
|
||||||
|
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
|
||||||
|
self.AddVersioning(binary)
|
||||||
|
self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
|
return binary
|
||||||
|
|
||||||
|
Extension = ExtensionConfig()
|
||||||
|
Extension.detectProductVersion()
|
||||||
|
Extension.detectSDKs()
|
||||||
|
Extension.configure()
|
||||||
|
|
||||||
|
if Extension.use_auto_versioning():
|
||||||
|
Extension.generated_headers = builder.Build('buildbot/Versioning')
|
||||||
|
|
||||||
|
builder.targets = builder.CloneableList(Extension.all_targets)
|
||||||
|
# Add additional buildscripts here
|
||||||
|
BuildScripts = [
|
||||||
|
'extension/AMBuilder',
|
||||||
|
'buildbot/PackageScript',
|
||||||
|
'buildbot/BreakpadSymbols'
|
||||||
|
]
|
||||||
|
|
||||||
|
builder.Build(BuildScripts, {'Extension': Extension})
|
||||||
@ -1,41 +1,39 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||||
import os
|
import os, sys
|
||||||
import urllib.request
|
|
||||||
from ambuild.command import Command
|
|
||||||
from ambuild.command import ShellCommand
|
|
||||||
|
|
||||||
class IterateDebugInfoCommand(Command):
|
UPLOAD_SCRIPT = os.path.join(Extension.sm_root, 'tools', 'buildbot', 'upload_symbols.py')
|
||||||
def run(self, master, job):
|
|
||||||
pdblog = open(os.path.join(AMBuild.outputFolder, 'pdblog.txt'), 'rt')
|
|
||||||
for debug_info in pdblog:
|
|
||||||
debug_info = os.path.join(AMBuild.outputFolder, debug_info.strip())
|
|
||||||
job.AddCommand(SymbolCommand(debug_info, symbolServer))
|
|
||||||
pdblog.close()
|
|
||||||
|
|
||||||
class SymbolCommand(ShellCommand):
|
|
||||||
def __init__(self, debugFile, symbolServer):
|
|
||||||
self.serverResponse = None
|
|
||||||
self.symbolServer = symbolServer
|
|
||||||
if AMBuild.target['platform'] == 'linux':
|
|
||||||
cmdstring = "dump_syms {0} {1}".format(debugFile, os.path.dirname(debugFile))
|
|
||||||
elif AMBuild.target['platform'] == 'darwin':
|
|
||||||
cmdstring = "dump_syms {0}".format(debugFile)
|
|
||||||
elif AMBuild.target['platform'] == 'windows':
|
|
||||||
cmdstring = "dump_syms.exe {0}".format(debugFile)
|
|
||||||
ShellCommand.__init__(self, cmdstring)
|
|
||||||
def run(self, master, job):
|
|
||||||
ShellCommand.run(self, master, job)
|
|
||||||
if self.stdout != None and len(self.stdout) > 0:
|
|
||||||
request = urllib.request.Request(symbolServer, self.stdout.encode('utf-8'))
|
|
||||||
request.add_header("Content-Type", "text/plain")
|
|
||||||
self.serverResponse = urllib.request.urlopen(request).read().decode('utf-8')
|
|
||||||
def spew(self, runner):
|
|
||||||
if self.stderr != None and len(self.stderr) > 0:
|
|
||||||
runner.PrintOut(self.stderr)
|
|
||||||
if self.serverResponse != None and len(self.serverResponse) > 0:
|
|
||||||
runner.PrintOut(self.serverResponse)
|
|
||||||
|
|
||||||
if 'BREAKPAD_SYMBOL_SERVER' in os.environ:
|
if 'BREAKPAD_SYMBOL_SERVER' in os.environ:
|
||||||
symbolServer = os.environ['BREAKPAD_SYMBOL_SERVER']
|
symbolServer = os.environ['BREAKPAD_SYMBOL_SERVER']
|
||||||
job = AMBuild.AddJob('breakpad-symbols')
|
builder.SetBuildFolder('breakpad-symbols')
|
||||||
job.AddCommand(IterateDebugInfoCommand())
|
|
||||||
|
for cxx_task in Extension.extensions:
|
||||||
|
if cxx_task.target.platform in ['windows']:
|
||||||
|
debug_entry = cxx_task.debug
|
||||||
|
else:
|
||||||
|
debug_entry = cxx_task.binary
|
||||||
|
|
||||||
|
debug_file = os.path.join(builder.buildPath, debug_entry.path)
|
||||||
|
if cxx_task.target.platform == 'linux':
|
||||||
|
argv = ['dump_syms', debug_file, os.path.dirname(debug_file)]
|
||||||
|
elif cxx_task.target.platform == 'mac':
|
||||||
|
# Required once dump_syms is updated on the slaves.
|
||||||
|
#argv = ['dump_syms', '-g', debug_file + '.dSYM', debug_file]
|
||||||
|
argv = ['dump_syms', debug_file + '.dSYM']
|
||||||
|
elif cxx_task.target.platform == 'windows':
|
||||||
|
argv = ['dump_syms.exe', debug_file]
|
||||||
|
|
||||||
|
plat_dir = os.path.dirname(debug_file)
|
||||||
|
bin_dir = os.path.split(plat_dir)[0]
|
||||||
|
|
||||||
|
symbol_file = '{}-{}-{}.breakpad'.format(
|
||||||
|
os.path.split(bin_dir)[1],
|
||||||
|
cxx_task.target.platform,
|
||||||
|
cxx_task.target.arch)
|
||||||
|
|
||||||
|
argv = [sys.executable, UPLOAD_SCRIPT, symbol_file] + argv
|
||||||
|
builder.AddCommand(
|
||||||
|
inputs = [UPLOAD_SCRIPT, debug_entry],
|
||||||
|
argv = argv,
|
||||||
|
outputs = [symbol_file]
|
||||||
|
)
|
||||||
@ -4,112 +4,44 @@ import shutil
|
|||||||
import ambuild.osutil as osutil
|
import ambuild.osutil as osutil
|
||||||
from ambuild.command import Command
|
from ambuild.command import Command
|
||||||
|
|
||||||
job = AMBuild.AddJob('package')
|
builder.SetBuildFolder('package')
|
||||||
|
|
||||||
class DestroyPath(Command):
|
def CreateFolders(folders):
|
||||||
def __init__(self, folder):
|
dict = {}
|
||||||
Command.__init__(self)
|
for folder in folders:
|
||||||
self.folder = folder
|
path = os.path.normpath(folder)
|
||||||
|
dict[folder] = builder.AddFolder(path)
|
||||||
|
return dict
|
||||||
|
|
||||||
def destroy(self, path):
|
def CopyFiles(src, dest, filter_ext=None):
|
||||||
entries = os.listdir(path)
|
source_path = os.path.join(builder.sourcePath, src)
|
||||||
for entry in entries:
|
if os.path.isfile(source_path):
|
||||||
newpath = os.path.join(path, entry)
|
builder.AddCopy(source_path, dest)
|
||||||
if os.path.isdir(newpath):
|
return
|
||||||
self.destroy(newpath)
|
for entry in os.listdir(source_path):
|
||||||
os.rmdir(newpath)
|
entry_path = os.path.join(source_path, entry)
|
||||||
elif os.path.isfile(newpath):
|
if not os.path.isfile(entry_path):
|
||||||
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
|
continue
|
||||||
path = os.path.join(self.fromPath, entry)
|
if filter_ext:
|
||||||
if not os.path.isfile(path):
|
_, ext = os.path.splitext(entry)
|
||||||
|
if filter_ext != ext:
|
||||||
continue
|
continue
|
||||||
runner.PrintOut('copy {0} to {1}'.format(path, self.toPath))
|
builder.AddCopy(entry_path, dest)
|
||||||
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']]
|
folders = CreateFolders(['addons/sourcemod/extensions', 'addons/sourcemod/extensions/x64', 'addons/sourcemod/gamedata', 'addons/sourcemod/scripting', 'addons/sourcemod/scripting/include'])
|
||||||
|
|
||||||
#Setup
|
pdblog = open(os.path.join(builder.buildPath, 'pdblog.txt'), 'wt')
|
||||||
job.AddCommand(DestroyPath(os.path.join(AMBuild.outputFolder, 'package')))
|
for cxx_task in Extension.extensions:
|
||||||
job.AddCommand(CreateFolders(folders))
|
if cxx_task.target.arch == 'x86_64':
|
||||||
|
builder.AddCopy(cxx_task.binary, folders['addons/sourcemod/extensions/x64'])
|
||||||
#Copy Files
|
else:
|
||||||
job.AddCommand(CopyFile(os.path.join(AMBuild.sourceFolder, 'connect.games.txt'),
|
builder.AddCopy(cxx_task.binary, folders['addons/sourcemod/extensions'])
|
||||||
os.path.join('addons', 'sourcemod', 'gamedata')))
|
pdblog.write(cxx_task.debug.path + '\n')
|
||||||
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))
|
|
||||||
|
|
||||||
# Each platform's version of dump_syms needs the path in a different format.
|
|
||||||
if AMBuild.target['platform'] == 'linux':
|
|
||||||
debug_info.append(name + '/' + name + '.so')
|
|
||||||
elif AMBuild.target['platform'] == 'darwin':
|
|
||||||
debug_info.append(name + '/' + name + '.dylib.dSYM')
|
|
||||||
elif AMBuild.target['platform'] == 'windows':
|
|
||||||
debug_info.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)
|
|
||||||
|
|
||||||
debug_info = []
|
|
||||||
|
|
||||||
AddHL2Library('connect', 'extensions')
|
|
||||||
|
|
||||||
job.AddCommandGroup(bincopies)
|
|
||||||
|
|
||||||
pdblog = open(os.path.join(AMBuild.outputFolder, 'pdblog.txt'), 'wt')
|
|
||||||
for pdb in debug_info:
|
|
||||||
pdblog.write(pdb + '\n')
|
|
||||||
pdblog.close()
|
pdblog.close()
|
||||||
|
|
||||||
|
CopyFiles('connect.games.txt', folders['addons/sourcemod/gamedata'])
|
||||||
|
CopyFiles('connect.inc', folders['addons/sourcemod/scripting/include'])
|
||||||
|
CopyFiles('connect.sp', folders['addons/sourcemod/scripting'])
|
||||||
|
|
||||||
|
debug_info = []
|
||||||
@ -1,55 +1,50 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
# vim: set ts=8 sts=2 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os, sys
|
||||||
import re
|
import re
|
||||||
import subprocess
|
|
||||||
from ambuild.cache import Cache
|
|
||||||
import ambuild.command as command
|
|
||||||
|
|
||||||
#Quickly try to ascertain the current repository revision
|
builder.SetBuildFolder('/')
|
||||||
def GetVersion():
|
includes = builder.AddFolder('includes')
|
||||||
args = ['hg', 'parent', '-R', AMBuild.sourceFolder]
|
|
||||||
p = command.RunDirectCommand(AMBuild, args)
|
|
||||||
m = re.match('changeset:\s+(\d+):(.+)', p.stdoutText)
|
|
||||||
if m == None:
|
|
||||||
raise Exception('Could not determine repository version')
|
|
||||||
return m.groups()
|
|
||||||
|
|
||||||
def PerformReversioning():
|
argv = [
|
||||||
rev, cset = GetVersion()
|
sys.executable,
|
||||||
cacheFile = os.path.join(AMBuild.outputFolder, '.ambuild', 'hgcache')
|
os.path.join(builder.sourcePath, 'buildbot', 'generate_header.py'),
|
||||||
cache = Cache(cacheFile)
|
os.path.join(builder.sourcePath),
|
||||||
if os.path.isfile(cacheFile):
|
os.path.join(builder.buildPath, 'includes'),
|
||||||
cache.LoadCache()
|
]
|
||||||
if cache.HasVariable('cset') and cache['cset'] == cset:
|
|
||||||
return False
|
|
||||||
cache.CacheVariable('cset', cset)
|
|
||||||
|
|
||||||
productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
|
outputs = [
|
||||||
productContents = productFile.read()
|
os.path.join(builder.buildFolder, 'includes', 'version_auto.h')
|
||||||
productFile.close()
|
]
|
||||||
m = re.match('(\d+)\.(\d+)\.(\d+)(.*)', productContents)
|
|
||||||
if m == None:
|
|
||||||
raise Exception('Could not detremine product version')
|
|
||||||
major, minor, release, tag = m.groups()
|
|
||||||
|
|
||||||
incFolder = os.path.join(AMBuild.sourceFolder, 'extension')
|
repo_head_path = os.path.join(builder.sourcePath, 'product.version')
|
||||||
incFile = open(os.path.join(incFolder, 'version_auto.h'), 'w')
|
if os.path.exists(os.path.join(builder.sourcePath, '.git')):
|
||||||
incFile.write("""
|
with open(os.path.join(builder.sourcePath, '.git', 'HEAD')) as fp:
|
||||||
#ifndef _AUTO_VERSION_INFORMATION_H_
|
head_contents = fp.read().strip()
|
||||||
#define _AUTO_VERSION_INFORMATION_H_
|
if re.search('^[a-fA-F0-9]{40}$', head_contents):
|
||||||
|
repo_head_path = os.path.join(builder.sourcePath, '.git', 'HEAD')
|
||||||
|
else:
|
||||||
|
git_state = head_contents.split(':')[1].strip()
|
||||||
|
repo_head_path = os.path.join(builder.sourcePath, '.git', git_state)
|
||||||
|
if not os.path.exists(repo_head_path):
|
||||||
|
repo_head_path = os.path.join(builder.sourcePath, '.git', 'HEAD')
|
||||||
|
|
||||||
#define SM_BUILD_TAG \"{0}\"
|
sources = [
|
||||||
#define SM_BUILD_UNIQUEID \"{1}:{2}\" SM_BUILD_TAG
|
os.path.join(builder.sourcePath, 'product.version'),
|
||||||
#define SM_VERSION \"{3}.{4}.{5}\"
|
repo_head_path,
|
||||||
#define SM_FULL_VERSION SM_VERSION SM_BUILD_TAG
|
argv[1]
|
||||||
#define SM_FILE_VERSION {6},{7},{8},0
|
]
|
||||||
|
|
||||||
#endif /* _AUTO_VERSION_INFORMATION_H_ */
|
for source in sources:
|
||||||
|
if not os.path.exists(source):
|
||||||
""".format(tag, rev, cset, major, minor, release, major, minor, release))
|
print(source)
|
||||||
incFile.close()
|
for source in sources:
|
||||||
cache.WriteCache()
|
if not os.path.exists(source):
|
||||||
|
print(source)
|
||||||
PerformReversioning()
|
|
||||||
|
|
||||||
|
output_nodes = builder.AddCommand(
|
||||||
|
inputs=sources,
|
||||||
|
argv=argv,
|
||||||
|
outputs=outputs
|
||||||
|
)
|
||||||
|
|
||||||
|
rvalue = output_nodes
|
||||||
61
buildbot/generate_header.py
Normal file
61
buildbot/generate_header.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||||
|
import os, sys
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
if len(argv) < 2:
|
||||||
|
sys.stderr.write('Usage: generate_header.py <source_path> <output_folder>\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
SourceFolder = os.path.abspath(os.path.normpath(argv[0]))
|
||||||
|
OutputFolder = os.path.normpath(argv[1])
|
||||||
|
|
||||||
|
def run_and_return(argv):
|
||||||
|
text = subprocess.check_output(argv)
|
||||||
|
if str != bytes:
|
||||||
|
text = str(text, 'utf-8')
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
def GetGHVersion():
|
||||||
|
p = run_and_return(['hg', 'parent', '-R', SourceFolder])
|
||||||
|
m = re.match('changeset:\s+(\d+):(.+)', p.stdoutText)
|
||||||
|
if m == None:
|
||||||
|
raise Exception('Could not determine repository version')
|
||||||
|
return m.groups()
|
||||||
|
|
||||||
|
def GetGitVersion():
|
||||||
|
revision_count = run_and_return(['git', 'rev-list', '--count', 'HEAD'])
|
||||||
|
revision_hash = run_and_return(['git', 'log', '--pretty=format:%h:%H', '-n', '1'])
|
||||||
|
shorthash, longhash = revision_hash.split(':')
|
||||||
|
|
||||||
|
return revision_count, shorthash
|
||||||
|
|
||||||
|
rev = None
|
||||||
|
cset = None
|
||||||
|
rev, cset = GetGitVersion()
|
||||||
|
|
||||||
|
productFile = open(os.path.join(SourceFolder, 'product.version'), 'r')
|
||||||
|
productContents = productFile.read()
|
||||||
|
productFile.close()
|
||||||
|
m = re.match('(\d+)\.(\d+)\.(\d+)(.*)', productContents)
|
||||||
|
if m == None:
|
||||||
|
raise Exception('Could not detremine product version')
|
||||||
|
major, minor, release, tag = m.groups()
|
||||||
|
|
||||||
|
incFile = open(os.path.join(OutputFolder, 'version_auto.h'), 'w')
|
||||||
|
incFile.write("""
|
||||||
|
#ifndef _AUTO_VERSION_INFORMATION_H_
|
||||||
|
#define _AUTO_VERSION_INFORMATION_H_
|
||||||
|
#define SM_BUILD_TAG \"{0}\"
|
||||||
|
#define SM_BUILD_UNIQUEID \"{1}:{2}\" SM_BUILD_TAG
|
||||||
|
#define SM_VERSION \"{3}.{4}.{5}\"
|
||||||
|
#define SM_FULL_VERSION SM_VERSION SM_BUILD_TAG
|
||||||
|
#define SM_FILE_VERSION {6},{7},{8},0
|
||||||
|
#endif /* _AUTO_VERSION_INFORMATION_H_ */
|
||||||
|
""".format(tag, rev, cset, major, minor, release, major, minor, release))
|
||||||
|
incFile.close()
|
||||||
|
|
||||||
|
filename_versioning = open(os.path.join(OutputFolder, 'filename_versioning.txt'), 'w')
|
||||||
|
filename_versioning.write("{0}.{1}.{2}-git{3}-{4}".format(major, minor, release, rev, cset))
|
||||||
|
filename_versioning.close()
|
||||||
28
configure.py
28
configure.py
@ -1,10 +1,26 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et:
|
||||||
import sys
|
import sys
|
||||||
import ambuild.runner as runner
|
from ambuild2 import run
|
||||||
|
|
||||||
run = runner.Runner()
|
# Simple extensions do not need to modify this file.
|
||||||
run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
|
||||||
|
parser = run.BuildParser(sourcePath = sys.path[0], api='2.2')
|
||||||
|
|
||||||
|
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||||
|
help='Root search folder for HL2SDKs')
|
||||||
|
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||||
|
help='Path to Metamod:Source')
|
||||||
|
parser.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
|
||||||
|
help='Path to SourceMod')
|
||||||
|
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
|
||||||
help='Enable debugging symbols')
|
help='Enable debugging symbols')
|
||||||
run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||||
help='Enable optimization')
|
help='Enable optimization')
|
||||||
run.Configure(sys.path[0])
|
parser.options.add_argument('--enable-auto-versioning', action='store_false', dest='disable_auto_versioning',
|
||||||
|
default=True, help='Enables the auto versioning script')
|
||||||
|
parser.options.add_argument('-s', '--sdks', default='all', dest='sdks',
|
||||||
|
help='Build against specified SDKs; valid args are "all", "present", or '
|
||||||
|
'space-delimited list of engine names (default: %default)')
|
||||||
|
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
|
||||||
|
help="Override the target architecture (use commas to separate multiple targets).")
|
||||||
|
parser.Configure()
|
||||||
@ -15,14 +15,14 @@
|
|||||||
"ISteamGameServer__BeginAuthSession"
|
"ISteamGameServer__BeginAuthSession"
|
||||||
{
|
{
|
||||||
"linux" "29"
|
"linux" "29"
|
||||||
"mac" "29"
|
"linux64" "29"
|
||||||
"windows" "29"
|
"windows" "29"
|
||||||
}
|
}
|
||||||
|
|
||||||
"ISteamGameServer__EndAuthSession"
|
"ISteamGameServer__EndAuthSession"
|
||||||
{
|
{
|
||||||
"linux" "30"
|
"linux" "30"
|
||||||
"mac" "30"
|
"linux64" "30"
|
||||||
"windows" "30"
|
"windows" "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@
|
|||||||
{
|
{
|
||||||
"library" "engine"
|
"library" "engine"
|
||||||
"linux" "@_Z12Steam3Serverv"
|
"linux" "@_Z12Steam3Serverv"
|
||||||
"mac" "@_Z12Steam3Serverv"
|
"linux64" "@_Z12Steam3Serverv"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +102,7 @@
|
|||||||
{
|
{
|
||||||
"library" "engine"
|
"library" "engine"
|
||||||
"linux" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i"
|
"linux" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i"
|
||||||
"mac" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i"
|
"linux64" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i"
|
||||||
"windows" "\x55\x8B\xEC\x81\xEC\x24\x05\x00\x00"
|
"windows" "\x55\x8B\xEC\x81\xEC\x24\x05\x00\x00"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@
|
|||||||
{
|
{
|
||||||
"library" "engine"
|
"library" "engine"
|
||||||
"linux" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc"
|
"linux" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc"
|
||||||
"mac" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc"
|
"linux64" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc"
|
||||||
"windows" "\x55\x8B\xEC\x81\xEC\x04\x05\x00\x00\x57"
|
"windows" "\x55\x8B\xEC\x81\xEC\x04\x05\x00\x00\x57"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@
|
|||||||
{
|
{
|
||||||
"library" "engine"
|
"library" "engine"
|
||||||
"linux" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
|
"linux" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
|
||||||
"mac" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
|
"linux64" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
|
||||||
"windows" "\x55\x8B\xEC\x56\x57\x8B\x7D\x08\x8B\xF1\x8D\x4E\x04"
|
"windows" "\x55\x8B\xEC\x56\x57\x8B\x7D\x08\x8B\xF1\x8D\x4E\x04"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@
|
|||||||
{
|
{
|
||||||
"library" "engine"
|
"library" "engine"
|
||||||
"linux" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
|
"linux" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
|
||||||
"mac" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
|
"linux64" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
|
||||||
"windows" "\x55\x8B\xEC\x83\xEC\x14\x53\x8B\x5D\x14"
|
"windows" "\x55\x8B\xEC\x83\xEC\x14\x53\x8B\x5D\x14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +1,29 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os, sys
|
||||||
|
|
||||||
for i in SM.sdkInfo:
|
projectname = 'connect'
|
||||||
sdk = SM.sdkInfo[i]
|
|
||||||
if AMBuild.target['platform'] not in sdk['platform']:
|
project = builder.LibraryProject(projectname + '.ext')
|
||||||
|
project.sources = [
|
||||||
|
'extension.cpp',
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'smsdk_ext.cpp'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'CDetour', 'detours.cpp'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'asm', 'asm.c'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'libudis86', 'decode.c'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'libudis86', 'itab.c'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'libudis86', 'syn-att.c'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'libudis86', 'syn-intel.c'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'libudis86', 'syn.c'),
|
||||||
|
os.path.join(Extension.sm_root, 'public', 'libudis86', 'udis86.c')
|
||||||
|
]
|
||||||
|
|
||||||
|
for sdk_name in Extension.sdks:
|
||||||
|
sdk = Extension.sdks[sdk_name]
|
||||||
|
|
||||||
|
for cxx in builder.targets:
|
||||||
|
if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
compiler = SM.DefaultHL2Compiler('extension', i)
|
binary = Extension.HL2ExtConfig(project, builder, cxx, projectname + '.ext.' + sdk.ext, sdk)
|
||||||
|
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'extension'))
|
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'extension', 'sdk'))
|
|
||||||
|
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD14'], 'public'))
|
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD14'], 'extensions'))
|
|
||||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD14'], 'public', 'sourcepawn'))
|
|
||||||
|
|
||||||
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', [
|
|
||||||
'extension.cpp',
|
|
||||||
'asm/asm.c',
|
|
||||||
'CDetour/detours.cpp',
|
|
||||||
'sdk/smsdk_ext.cpp'
|
|
||||||
])
|
|
||||||
SM.PostSetupHL2Job(extension, binary, i)
|
|
||||||
SM.AutoVersion('extension', binary)
|
|
||||||
SM.ExtractDebugInfo(extension, binary)
|
|
||||||
binary.SendToJob()
|
|
||||||
|
|
||||||
|
Extension.extensions = builder.Add(project)
|
||||||
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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_POSIX
|
|
||||||
#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_POSIX
|
|
||||||
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_
|
|
||||||
@ -1,192 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,300 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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_
|
|
||||||
@ -1,421 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
#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__
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "extension.hpp"
|
#include "extension.h"
|
||||||
#include "CDetour/detours.h"
|
#include "CDetour/detours.h"
|
||||||
|
|
||||||
#include "steam/steamclientpublic.h"
|
#include "steam/steamclientpublic.h"
|
||||||
@ -44,6 +44,7 @@ typedef enum EAuthProtocol
|
|||||||
k_EAuthProtocolSteam = 3,
|
k_EAuthProtocolSteam = 3,
|
||||||
} EAuthProtocol;
|
} EAuthProtocol;
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE < SE_SDK2013 || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||||
typedef enum EBeginAuthSessionResult
|
typedef enum EBeginAuthSessionResult
|
||||||
{
|
{
|
||||||
k_EBeginAuthSessionResultOK = 0, // Ticket is valid for this game and this steamID.
|
k_EBeginAuthSessionResultOK = 0, // Ticket is valid for this game and this steamID.
|
||||||
@ -53,6 +54,7 @@ typedef enum EBeginAuthSessionResult
|
|||||||
k_EBeginAuthSessionResultGameMismatch = 4, // Ticket is not for this game
|
k_EBeginAuthSessionResultGameMismatch = 4, // Ticket is not for this game
|
||||||
k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired
|
k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired
|
||||||
} EBeginAuthSessionResult;
|
} EBeginAuthSessionResult;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct netadr_s
|
typedef struct netadr_s
|
||||||
{
|
{
|
||||||
@ -74,7 +76,11 @@ public:
|
|||||||
const char *CSteamID::Render() const
|
const char *CSteamID::Render() const
|
||||||
{
|
{
|
||||||
static char szSteamID[64];
|
static char szSteamID[64];
|
||||||
|
#if SOURCE_ENGINE < SE_SDK2013 || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||||
V_snprintf(szSteamID, sizeof(szSteamID), "STEAM_0:%u:%u", (m_unAccountID % 2) ? 1 : 0, (int32)m_unAccountID/2);
|
V_snprintf(szSteamID, sizeof(szSteamID), "STEAM_0:%u:%u", (m_unAccountID % 2) ? 1 : 0, (int32)m_unAccountID/2);
|
||||||
|
#else
|
||||||
|
V_snprintf(szSteamID, sizeof(szSteamID), "STEAM_0:%u:%u", (m_steamid.m_comp.m_unAccountID % 2) ? 1 : 0, (int32)m_steamid.m_comp.m_unAccountID/2);
|
||||||
|
#endif
|
||||||
return szSteamID;
|
return szSteamID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,9 +217,9 @@ void EndAuthSession(CSteamID steamID)
|
|||||||
return (void)(reinterpret_cast<VFuncEmptyClass*>(this_ptr)->*u.mfpnew)(steamID);
|
return (void)(reinterpret_cast<VFuncEmptyClass*>(this_ptr)->*u.mfpnew)(steamID);
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_DETOUR(CBaseServer__ConnectClient);
|
CDetour* detourCBaseServer__ConnectClient = nullptr;
|
||||||
DECL_DETOUR(CBaseServer__RejectConnection)
|
CDetour* detourCBaseServer__RejectConnection = nullptr;
|
||||||
DECL_DETOUR(CBaseServer__CheckChallengeType);
|
CDetour* detourCBaseServer__CheckChallengeType = nullptr;
|
||||||
|
|
||||||
bool g_bEndAuthSessionOnRejectConnection = false;
|
bool g_bEndAuthSessionOnRejectConnection = false;
|
||||||
CSteamID g_lastClientSteamID;
|
CSteamID g_lastClientSteamID;
|
||||||
@ -221,6 +227,17 @@ CSteamID g_lastClientSteamID;
|
|||||||
bool g_bSuppressCheckChallengeType = false;
|
bool g_bSuppressCheckChallengeType = false;
|
||||||
|
|
||||||
char passwordBuffer[255];
|
char passwordBuffer[255];
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
if (nAuthProtocol != k_EAuthProtocolSteam)
|
if (nAuthProtocol != k_EAuthProtocolSteam)
|
||||||
@ -379,9 +396,9 @@ bool Connect::SDK_OnLoad(char *error, size_t maxlen, bool late)
|
|||||||
|
|
||||||
CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
|
CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
|
||||||
|
|
||||||
CREATE_DETOUR(CBaseServer__ConnectClient);
|
detourCBaseServer__ConnectClient = DETOUR_CREATE_MEMBER(CBaseServer__ConnectClient, "CBaseServer__ConnectClient");
|
||||||
CREATE_DETOUR(CBaseServer__RejectConnection);
|
detourCBaseServer__RejectConnection = DETOUR_CREATE_MEMBER(CBaseServer__RejectConnection, "CBaseServer__RejectConnection");
|
||||||
CREATE_DETOUR(CBaseServer__CheckChallengeType);
|
detourCBaseServer__CheckChallengeType = DETOUR_CREATE_MEMBER(CBaseServer__CheckChallengeType, "CBaseServer__CheckChallengeType");
|
||||||
|
|
||||||
g_pConnectForward = g_pForwards->CreateForward("OnClientPreConnectEx", ET_LowEvent, 5, NULL, Param_String, Param_String, Param_String, Param_String, Param_String);
|
g_pConnectForward = g_pForwards->CreateForward("OnClientPreConnectEx", ET_LowEvent, 5, NULL, Param_String, Param_String, Param_String, Param_String, Param_String);
|
||||||
|
|
||||||
@ -406,9 +423,21 @@ void Connect::SDK_OnUnload()
|
|||||||
|
|
||||||
bool Connect::SDK_OnMetamodUnload(char *error, size_t maxlen)
|
bool Connect::SDK_OnMetamodUnload(char *error, size_t maxlen)
|
||||||
{
|
{
|
||||||
DESTROY_DETOUR(CBaseServer__ConnectClient);
|
if (detourCBaseServer__ConnectClient)
|
||||||
DESTROY_DETOUR(CBaseServer__RejectConnection);
|
{
|
||||||
DESTROY_DETOUR(CBaseServer__CheckChallengeType);
|
detourCBaseServer__ConnectClient->DisableDetour();
|
||||||
|
delete detourCBaseServer__ConnectClient;
|
||||||
|
}
|
||||||
|
if (detourCBaseServer__RejectConnection)
|
||||||
|
{
|
||||||
|
detourCBaseServer__RejectConnection->DisableDetour();
|
||||||
|
delete detourCBaseServer__RejectConnection;
|
||||||
|
}
|
||||||
|
if (detourCBaseServer__CheckChallengeType)
|
||||||
|
{
|
||||||
|
detourCBaseServer__CheckChallengeType->DisableDetour();
|
||||||
|
delete detourCBaseServer__CheckChallengeType;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
* @brief Connect extension code header.
|
* @brief Connect extension code header.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "smsdk_ext.hpp"
|
#include "smsdk_ext.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sample implementation of the SDK Extension.
|
* @brief Sample implementation of the SDK Extension.
|
||||||
@ -1,475 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete[](void * ptr, size_t size)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,339 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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_
|
|
||||||
@ -1 +1 @@
|
|||||||
1.2.1
|
1.3.0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user