mirror of
https://github.com/accelerator74/l4dtoolz.git
synced 2026-10-10 04:03:16 +08:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 07535e118f | |||
| dedf217b61 | |||
| 178640b3e7 | |||
| ae7d3d5c2b | |||
| 63c9b19e9a | |||
| 6590795d4f | |||
| 3041183422 | |||
| c895db9e78 | |||
| ef2a8df7e0 | |||
| aa143fb0e0 | |||
| 44ee0e7a02 | |||
| 11ab6e1e54 | |||
| e235106c86 | |||
| 763fbf3b96 | |||
| 3295b7aeae | |||
| c510965a8a | |||
| e5e9bac1c0 | |||
| e1a6182665 | |||
| 679b6f54c0 | |||
| a7e01138c7 | |||
| 5b19701a0e | |||
| c7ee545ce9 | |||
| 93ae32eea5 | |||
| 057e6ce671 | |||
| f665622521 | |||
| f77ced2d2d | |||
| 3f6694b148 | |||
| a5ebdd6e82 |
@@ -0,0 +1,166 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- LICENSE
|
||||
- README.md
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths-ignore:
|
||||
- LICENSE
|
||||
- README.md
|
||||
schedule:
|
||||
- cron: '30 03 01 */3 *' # Artifacts expire every 3 months
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build with mms${{ matrix.mm_version }} on ${{ matrix.os_short }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- ubuntu-22.04
|
||||
- windows-latest
|
||||
|
||||
mm_version:
|
||||
- "1.12"
|
||||
|
||||
include:
|
||||
- mm_version: "1.12"
|
||||
mm_branch: "1.12-dev"
|
||||
|
||||
- os: ubuntu-latest
|
||||
os_short: linux
|
||||
|
||||
- os: ubuntu-22.04
|
||||
os_short: oldlinux
|
||||
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install (Linux)
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang g++-multilib
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "CXX=clang++" >> $GITHUB_ENV
|
||||
|
||||
- name: Checking out MM:Source
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: alliedmodders/metamod-source
|
||||
ref: ${{ matrix.mm_branch }}
|
||||
path: metamod-${{ matrix.mm_version }}
|
||||
|
||||
- name: Setting up Python
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Setting up ambuild
|
||||
run: |
|
||||
python -m pip install wheel
|
||||
pip install git+https://github.com/accelerator74/ambuild@nog3
|
||||
|
||||
- name: Checking out hl2sdk-l4d
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk
|
||||
ref: l4d
|
||||
path: hl2sdk-l4d
|
||||
|
||||
- name: Checking out hl2sdk-l4d2
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk
|
||||
ref: l4d2
|
||||
path: hl2sdk-l4d2
|
||||
|
||||
- name: Checking out hl2sdk-manifests
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk-manifests
|
||||
path: hl2sdk-manifests
|
||||
|
||||
- name: Checking out own repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
path: src
|
||||
|
||||
- name: Compiling ${{ github.event.repository.name }}-l4d files
|
||||
working-directory: src
|
||||
run: |
|
||||
mkdir build_l4d
|
||||
cd build_l4d
|
||||
python ../configure.py --enable-optimize --sdks="l4d" --hl2sdk-manifest-path="${{ github.workspace }}/hl2sdk-manifests" --mms-path="${{ github.workspace }}/metamod-${{ matrix.mm_version }}"
|
||||
ambuild
|
||||
|
||||
- name: Compiling ${{ github.event.repository.name }}-l4d2 files
|
||||
working-directory: src
|
||||
run: |
|
||||
mkdir build_l4d2
|
||||
cd build_l4d2
|
||||
python ../configure.py --enable-optimize --sdks="l4d2" --hl2sdk-manifest-path="${{ github.workspace }}/hl2sdk-manifests" --mms-path="${{ github.workspace }}/metamod-${{ matrix.mm_version }}"
|
||||
ambuild
|
||||
|
||||
- name: Uploading l4d package
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ github.event.repository.name }}-l4d-${{ matrix.os_short }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: src/build_l4d/package
|
||||
|
||||
- name: Uploading l4d2 package
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ github.event.repository.name }}-l4d2-${{ matrix.os_short }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: src/build_l4d2/package
|
||||
|
||||
release:
|
||||
name: Release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
version=`echo $GITHUB_REF | sed "s/refs\/tags\///"`
|
||||
ls -Rall
|
||||
for folder in ${{ github.event.repository.name }}*; do
|
||||
if [ -d "$folder" ]; then
|
||||
echo "Processing folder: $folder"
|
||||
cd $folder
|
||||
tar -czf ../$folder.tar.gz -T <(\ls -1)
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: '*.tar.gz'
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
@@ -1,120 +0,0 @@
|
||||
name: l4d2-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- LICENSE
|
||||
- README.md
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths-ignore:
|
||||
- LICENSE
|
||||
- README.md
|
||||
schedule:
|
||||
- cron: '30 03 01 */3 *' # Artifacts expire every 3 months
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build with mms${{ matrix.mm_version }} on ${{ matrix.os_short }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
|
||||
mm_version:
|
||||
- "master"
|
||||
|
||||
include:
|
||||
- mm_version: "master"
|
||||
mm_branch: "master"
|
||||
|
||||
- os: ubuntu-latest
|
||||
os_short: linux
|
||||
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install (Linux)
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang g++-multilib
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "CXX=clang++" >> $GITHUB_ENV
|
||||
|
||||
- name: Add msbuild to PATH (Windows)
|
||||
if: startsWith(runner.os, 'Windows')
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Install (Windows)
|
||||
if: startsWith(runner.os, 'Windows')
|
||||
shell: cmd
|
||||
run: |
|
||||
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
|
||||
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
|
||||
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x86 -host_arch=x64
|
||||
)
|
||||
:: Loop over all environment variables and make them global.
|
||||
for /f "delims== tokens=1,2" %%a in ('set') do (
|
||||
echo>>"%GITHUB_ENV%" %%a=%%b
|
||||
)
|
||||
|
||||
- name: Checking out MM:Source
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alliedmodders/metamod-source
|
||||
ref: ${{ matrix.mm_branch }}
|
||||
path: metamod-${{ matrix.mm_version }}
|
||||
|
||||
- name: Setting up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Setting up ambuild
|
||||
run: |
|
||||
python -m pip install wheel
|
||||
pip install git+https://github.com/accelerator74/ambuild
|
||||
|
||||
- name: Checking out hl2sdk-l4d2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk
|
||||
ref: l4d2
|
||||
path: hl2sdk-l4d2
|
||||
|
||||
- name: Checking out own repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: src
|
||||
|
||||
- name: Compiling ${{ github.event.repository.name }} files
|
||||
working-directory: src
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
python ../configure.py --enable-optimize --sdks="l4d2" --mms-path="${{ github.workspace }}/metamod-${{ matrix.mm_version }}"
|
||||
ambuild
|
||||
|
||||
- name: Uploading package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.event.repository.name }}-l4d2-${{ matrix.os_short }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: src/build/package
|
||||
@@ -1,120 +0,0 @@
|
||||
name: l4d-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- LICENSE
|
||||
- README.md
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths-ignore:
|
||||
- LICENSE
|
||||
- README.md
|
||||
schedule:
|
||||
- cron: '30 03 01 */3 *' # Artifacts expire every 3 months
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build with mms${{ matrix.mm_version }} on ${{ matrix.os_short }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
|
||||
mm_version:
|
||||
- "master"
|
||||
|
||||
include:
|
||||
- mm_version: "master"
|
||||
mm_branch: "master"
|
||||
|
||||
- os: ubuntu-latest
|
||||
os_short: linux
|
||||
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install (Linux)
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang g++-multilib
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "CXX=clang++" >> $GITHUB_ENV
|
||||
|
||||
- name: Add msbuild to PATH (Windows)
|
||||
if: startsWith(runner.os, 'Windows')
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Install (Windows)
|
||||
if: startsWith(runner.os, 'Windows')
|
||||
shell: cmd
|
||||
run: |
|
||||
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
|
||||
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
|
||||
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x86 -host_arch=x64
|
||||
)
|
||||
:: Loop over all environment variables and make them global.
|
||||
for /f "delims== tokens=1,2" %%a in ('set') do (
|
||||
echo>>"%GITHUB_ENV%" %%a=%%b
|
||||
)
|
||||
|
||||
- name: Checking out MM:Source
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alliedmodders/metamod-source
|
||||
ref: ${{ matrix.mm_branch }}
|
||||
path: metamod-${{ matrix.mm_version }}
|
||||
|
||||
- name: Setting up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Setting up ambuild
|
||||
run: |
|
||||
python -m pip install wheel
|
||||
pip install git+https://github.com/accelerator74/ambuild
|
||||
|
||||
- name: Checking out hl2sdk-l4d
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk
|
||||
ref: l4d
|
||||
path: hl2sdk-l4d
|
||||
|
||||
- name: Checking out own repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: src
|
||||
|
||||
- name: Compiling ${{ github.event.repository.name }} files
|
||||
working-directory: src
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
python ../configure.py --enable-optimize --sdks="l4d" --mms-path="${{ github.workspace }}/metamod-${{ matrix.mm_version }}"
|
||||
ambuild
|
||||
|
||||
- name: Uploading package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.event.repository.name }}-l4d-${{ matrix.os_short }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: src/build/package
|
||||
+209
-208
@@ -1,27 +1,5 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import os, sys
|
||||
|
||||
# Simple extensions do not need to modify this file.
|
||||
|
||||
class SDK(object):
|
||||
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
||||
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
|
||||
|
||||
WinOnly = ['windows']
|
||||
WinLinux = ['windows', 'linux']
|
||||
WinLinuxMac = ['windows', 'linux', 'mac']
|
||||
|
||||
PossibleSDKs = {
|
||||
'l4d': SDK('HL2SDKL4D', '_mm', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
|
||||
'l4d2': SDK('HL2SDKL4D2', '_mm', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
|
||||
}
|
||||
import os, sys, shutil
|
||||
|
||||
def ResolveEnvPath(env, folder):
|
||||
if env in os.environ:
|
||||
@@ -44,13 +22,65 @@ def ResolveEnvPath(env, folder):
|
||||
def Normalize(path):
|
||||
return os.path.abspath(os.path.normpath(path))
|
||||
|
||||
def SetArchFlags(compiler):
|
||||
if compiler.behavior == 'gcc':
|
||||
if compiler.target.arch == 'x86_64':
|
||||
compiler.cflags += ['-fPIC']
|
||||
elif compiler.like('msvc'):
|
||||
if compiler.target.arch == 'x86_64':
|
||||
compiler.defines += ['WIN64']
|
||||
|
||||
hl2sdk_manifests_path = None
|
||||
|
||||
# First we check if the manifest exists in the current path
|
||||
hl2sdk_manifests_path = os.path.join(builder.sourcePath, 'hl2sdk-manifests/SdkHelpers.ambuild')
|
||||
|
||||
if not os.path.exists(hl2sdk_manifests_path):
|
||||
# manifests does not exists in the project file, use the path from --hl2sdk-manifest-path
|
||||
if not builder.options.hl2sdk_manifest:
|
||||
raise Exception('HL2SDK Manifest root path not set! (--hl2sdk-manifest-path)')
|
||||
else:
|
||||
hl2sdk_manifests_path = os.path.join(builder.options.hl2sdk_manifest, 'SdkHelpers.ambuild')
|
||||
|
||||
if not os.path.exists(hl2sdk_manifests_path):
|
||||
raise Exception('Could not find SdkHelpers.ambuild in the given HL2SDK Manifest path!')
|
||||
|
||||
|
||||
SdkHelpers = builder.Eval(hl2sdk_manifests_path, {
|
||||
'Project': 'l4dtoolz'
|
||||
})
|
||||
|
||||
class ExtensionConfig(object):
|
||||
def __init__(self):
|
||||
self.sdk_manifests = []
|
||||
self.sdks = {}
|
||||
self.sdk_targets = []
|
||||
self.binaries = []
|
||||
self.extensions = []
|
||||
self.generated_headers = None
|
||||
self.mms_root = None
|
||||
self.all_targets = []
|
||||
self.target_archs = set()
|
||||
|
||||
if builder.options.targets:
|
||||
target_archs = builder.options.targets.split(',')
|
||||
else:
|
||||
target_archs = ['x86', 'x86_64']
|
||||
|
||||
for arch in target_archs:
|
||||
try:
|
||||
cxx = builder.DetectCxx(target_arch = arch)
|
||||
self.target_archs.add(cxx.target.arch)
|
||||
except Exception as e:
|
||||
# Error if archs were manually overridden.
|
||||
if builder.options.targets:
|
||||
raise
|
||||
print('Skipping target {}: {}'.format(arch, e))
|
||||
continue
|
||||
self.all_targets.append(cxx)
|
||||
|
||||
if not self.all_targets:
|
||||
raise Exception('No suitable C/C++ compiler was found.')
|
||||
|
||||
@property
|
||||
def tag(self):
|
||||
@@ -58,35 +88,35 @@ class ExtensionConfig(object):
|
||||
return 'Debug'
|
||||
return 'Release'
|
||||
|
||||
def findSdkPath(self, sdk_name):
|
||||
dir_name = 'hl2sdk-{}'.format(sdk_name)
|
||||
if builder.options.hl2sdk_root:
|
||||
sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
|
||||
if os.path.exists(sdk_path):
|
||||
return sdk_path
|
||||
return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
|
||||
|
||||
def shouldIncludeSdk(self, sdk):
|
||||
return not sdk.get('source2', False)
|
||||
|
||||
def detectSDKs(self):
|
||||
sdk_list = builder.options.sdks.split(',')
|
||||
use_all = sdk_list[0] == 'all'
|
||||
use_present = sdk_list[0] == 'present'
|
||||
sdk_list = [s for s in builder.options.sdks.split(',') if s]
|
||||
SdkHelpers.sdk_filter = self.shouldIncludeSdk
|
||||
SdkHelpers.find_sdk_path = self.findSdkPath
|
||||
SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
|
||||
|
||||
for sdk_name in PossibleSDKs:
|
||||
sdk = PossibleSDKs[sdk_name]
|
||||
if builder.target_platform in sdk.platform:
|
||||
if builder.options.hl2sdk_root:
|
||||
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
||||
else:
|
||||
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
||||
if sdk_path is None or not os.path.isdir(sdk_path):
|
||||
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 len(self.sdks) < 1:
|
||||
raise Exception('At least one SDK must be available.')
|
||||
self.sdks = SdkHelpers.sdks
|
||||
self.sdk_manifests = SdkHelpers.sdk_manifests
|
||||
self.sdk_targets = SdkHelpers.sdk_targets
|
||||
|
||||
if builder.options.mms_path:
|
||||
self.mms_root = builder.options.mms_path
|
||||
else:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
|
||||
if not self.mms_root:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source')
|
||||
if not self.mms_root:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||
if not self.mms_root:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
|
||||
|
||||
@@ -95,14 +125,32 @@ class ExtensionConfig(object):
|
||||
self.mms_root = Normalize(self.mms_root)
|
||||
|
||||
def configure(self):
|
||||
cxx = builder.DetectCompilers()
|
||||
|
||||
allowed_archs = ['x86','x86_64']
|
||||
|
||||
if not set(self.target_archs).issubset(allowed_archs):
|
||||
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
|
||||
|
||||
for cxx in self.all_targets:
|
||||
self.configure_cxx(cxx)
|
||||
|
||||
def configure_cxx(self, cxx):
|
||||
if cxx.family == 'msvc':
|
||||
if cxx.version < 1928 and builder.options.generator != 'vs':
|
||||
raise Exception(f'Only MSVC 2022 and later are supported, full C++20 support is required. ({str(cxx.version)} < 1928)')
|
||||
elif cxx.family == 'gcc':
|
||||
if cxx.version < 'gcc-11':
|
||||
raise Exception('Only GCC versions 11 or later are supported, full C++20 support is required.')
|
||||
elif cxx.family == 'clang':
|
||||
if cxx.version < 'clang-14':
|
||||
raise Exception('Only clang versions 14 or later are supported, full C++20 support is required.')
|
||||
|
||||
if cxx.like('gcc'):
|
||||
self.configure_gcc(cxx)
|
||||
elif cxx.vendor == 'msvc':
|
||||
elif cxx.family == 'msvc':
|
||||
self.configure_msvc(cxx)
|
||||
|
||||
# Optimizaiton
|
||||
# Optimization
|
||||
if builder.options.opt == '1':
|
||||
cxx.defines += ['NDEBUG']
|
||||
|
||||
@@ -111,11 +159,11 @@ class ExtensionConfig(object):
|
||||
cxx.defines += ['DEBUG', '_DEBUG']
|
||||
|
||||
# Platform-specifics
|
||||
if builder.target_platform == 'linux':
|
||||
if cxx.target.platform == 'linux':
|
||||
self.configure_linux(cxx)
|
||||
elif builder.target_platform == 'mac':
|
||||
elif cxx.target.platform == 'mac':
|
||||
self.configure_mac(cxx)
|
||||
elif builder.target_platform == 'windows':
|
||||
elif cxx.target.platform == 'windows':
|
||||
self.configure_windows(cxx)
|
||||
|
||||
def configure_gcc(self, cxx):
|
||||
@@ -135,34 +183,41 @@ class ExtensionConfig(object):
|
||||
'-Wno-unused',
|
||||
'-Wno-switch',
|
||||
'-Wno-array-bounds',
|
||||
'-msse',
|
||||
'-m32',
|
||||
'-Wno-unknown-pragmas',
|
||||
'-Wno-dangling-else',
|
||||
'-fvisibility=hidden',
|
||||
]
|
||||
|
||||
if cxx.target.arch in ['x86', 'x86_64']:
|
||||
cxx.cflags += ['-msse']
|
||||
|
||||
cxx.cxxflags += [
|
||||
'-std=c++17',
|
||||
'-fno-exceptions',
|
||||
'-fno-threadsafe-statics',
|
||||
'-Wno-non-virtual-dtor',
|
||||
'-Wno-overloaded-virtual',
|
||||
'-Wno-register',
|
||||
'-fvisibility-inlines-hidden',
|
||||
'-std=c++20',
|
||||
]
|
||||
cxx.linkflags += ['-m32']
|
||||
|
||||
have_gcc = cxx.vendor == 'gcc'
|
||||
have_clang = cxx.vendor == 'clang'
|
||||
if cxx.version >= 'clang-3.9' or cxx.version >= 'apple-clang-10.0':
|
||||
have_gcc = cxx.family == 'gcc'
|
||||
have_clang = cxx.family == '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.6':
|
||||
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':
|
||||
@@ -172,14 +227,24 @@ class ExtensionConfig(object):
|
||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||
|
||||
# Work around SDK warnings.
|
||||
if cxx.version >= 'clang-10.0':
|
||||
cxx.cflags += [
|
||||
'-Wno-implicit-int-float-conversion',
|
||||
'-Wno-tautological-overlap-compare',
|
||||
]
|
||||
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
|
||||
cxx.cflags += [
|
||||
'-Wno-implicit-int-float-conversion',
|
||||
'-Wno-tautological-overlap-compare',
|
||||
]
|
||||
|
||||
if cxx.version >= 'clang-21.0':
|
||||
cxx.cflags += ['-Wno-uninitialized-const-pointer']
|
||||
|
||||
if cxx.version >= 'clang-16.0' or cxx.version >= 'apple-clang-15.0':
|
||||
cxx.cxxflags += ['-Wno-deprecated-anon-enum-enum-conversion']
|
||||
|
||||
if cxx.version >= 'clang-12.0' or cxx.version >= 'apple-clang-13.0':
|
||||
cxx.cxxflags += ['-Wno-deprecated-volatile']
|
||||
|
||||
if have_gcc:
|
||||
cxx.cflags += ['-mfpmath=sse']
|
||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||
|
||||
if builder.options.opt == '1':
|
||||
cxx.cflags += ['-O3']
|
||||
@@ -206,10 +271,9 @@ class ExtensionConfig(object):
|
||||
'/EHsc',
|
||||
'/GR-',
|
||||
'/TP',
|
||||
'/std:c++17',
|
||||
'/std:c++20',
|
||||
]
|
||||
cxx.linkflags += [
|
||||
'/MACHINE:X86',
|
||||
'kernel32.lib',
|
||||
'user32.lib',
|
||||
'gdi32.lib',
|
||||
@@ -236,26 +300,61 @@ class ExtensionConfig(object):
|
||||
cxx.cflags += ['/Oy-']
|
||||
|
||||
def configure_linux(self, cxx):
|
||||
cxx.defines += ['_LINUX', 'POSIX']
|
||||
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||
cxx.linkflags += ['-lm']
|
||||
if cxx.vendor == 'gcc':
|
||||
if cxx.family == 'gcc':
|
||||
cxx.linkflags += ['-static-libgcc']
|
||||
elif cxx.vendor == 'clang':
|
||||
elif cxx.family == 'clang':
|
||||
cxx.linkflags += ['-lgcc_eh']
|
||||
|
||||
def configure_mac(self, cxx):
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.15']
|
||||
cxx.linkflags += [
|
||||
'-mmacosx-version-min=10.5',
|
||||
'-arch', 'i386',
|
||||
'-lstdc++',
|
||||
'-stdlib=libstdc++',
|
||||
'-mmacosx-version-min=10.15',
|
||||
'-stdlib=libc++',
|
||||
'-lc++',
|
||||
]
|
||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
||||
cxx.cxxflags += ['-stdlib=libc++']
|
||||
|
||||
def configure_windows(self, cxx):
|
||||
cxx.defines += ['WIN32', '_WINDOWS']
|
||||
|
||||
def LibraryBuilder(self, compiler, name):
|
||||
binary = compiler.Library(name)
|
||||
if binary.compiler.like('msvc'):
|
||||
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
||||
return binary
|
||||
|
||||
def ProgramBuilder(self, compiler, name):
|
||||
binary = compiler.Program(name)
|
||||
if '-static-libgcc' in binary.compiler.linkflags:
|
||||
binary.compiler.linkflags.remove('-static-libgcc')
|
||||
if '-lgcc_eh' in binary.compiler.linkflags:
|
||||
binary.compiler.linkflags.remove('-lgcc_eh')
|
||||
if binary.compiler.like('gcc'):
|
||||
binary.compiler.linkflags += ['-lstdc++', '-lpthread']
|
||||
if binary.compiler.like('msvc'):
|
||||
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
|
||||
return binary
|
||||
|
||||
def StaticLibraryBuilder(self, compiler, name):
|
||||
return compiler.StaticLibrary(name)
|
||||
|
||||
def Library(self, context, compiler, name):
|
||||
compiler = compiler.clone()
|
||||
SetArchFlags(compiler)
|
||||
return self.LibraryBuilder(compiler, name)
|
||||
|
||||
def Program(self, context, compiler, name):
|
||||
compiler = compiler.clone()
|
||||
SetArchFlags(compiler)
|
||||
return self.ProgramBuilder(compiler, name)
|
||||
|
||||
def StaticLibrary(self, context, compiler, name):
|
||||
compiler = compiler.clone()
|
||||
SetArchFlags(compiler)
|
||||
return self.StaticLibraryBuilder(compiler, name)
|
||||
|
||||
def ConfigureForExtension(self, context, compiler):
|
||||
compiler.cxxincludes += [
|
||||
@@ -263,157 +362,59 @@ class ExtensionConfig(object):
|
||||
]
|
||||
return compiler
|
||||
|
||||
def ConfigureForHL2(self, binary, sdk):
|
||||
compiler = binary.compiler
|
||||
def ExtLibrary(self, context, compiler, name):
|
||||
binary = self.Library(context, compiler, name)
|
||||
SetArchFlags(compiler)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return binary
|
||||
|
||||
if sdk.name == 'episode1':
|
||||
mms_path = os.path.join(self.mms_root, 'core-legacy')
|
||||
else:
|
||||
mms_path = os.path.join(self.mms_root, 'core')
|
||||
def ConfigureForHL2(self, context, binary, sdk):
|
||||
compiler = binary.compiler
|
||||
SetArchFlags(compiler)
|
||||
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(mms_path),
|
||||
os.path.join(mms_path, 'sourcehook'),
|
||||
os.path.join(self.mms_root, 'core'),
|
||||
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||
]
|
||||
|
||||
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
||||
compiler.defines += defines
|
||||
for other_sdk in self.sdk_manifests:
|
||||
compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
|
||||
|
||||
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(['game_shared'])
|
||||
else:
|
||||
paths.append(['public', 'game', 'server'])
|
||||
paths.append(['public', 'toolframework'])
|
||||
paths.append(['game', 'shared'])
|
||||
paths.append(['common'])
|
||||
|
||||
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
|
||||
|
||||
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 compiler.like('msvc'):
|
||||
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
|
||||
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
||||
else:
|
||||
compiler.defines += ['COMPILER_GCC']
|
||||
|
||||
# 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', 'csgo', 'dota']:
|
||||
compiler.defines += ['NETWORK_VARS_ENABLED']
|
||||
|
||||
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']:
|
||||
if builder.target_platform in ['linux', 'mac']:
|
||||
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||
|
||||
if sdk.name == 'csgo' and builder.target_platform == 'linux':
|
||||
compiler.linkflags += ['-lstdc++']
|
||||
|
||||
for path in paths:
|
||||
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||
|
||||
if builder.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')
|
||||
else:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
||||
elif builder.target_platform == 'mac':
|
||||
if sdk.name in ['sdk2013', 'bms']:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
||||
else:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
||||
|
||||
if builder.target_platform in ['linux', 'mac']:
|
||||
if sdk.name in ['sdk2013', 'bms']:
|
||||
compiler.postlink += [
|
||||
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
|
||||
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
|
||||
]
|
||||
else:
|
||||
compiler.postlink += [
|
||||
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
|
||||
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
|
||||
]
|
||||
|
||||
if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']:
|
||||
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
|
||||
|
||||
dynamic_libs = []
|
||||
if builder.target_platform == 'linux':
|
||||
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency']:
|
||||
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
||||
elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota']:
|
||||
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
||||
else:
|
||||
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
||||
elif builder.target_platform == 'mac':
|
||||
compiler.linkflags.append('-liconv')
|
||||
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
||||
elif builder.target_platform == 'windows':
|
||||
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||
if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']:
|
||||
libs.append('interfaces')
|
||||
for lib in libs:
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
|
||||
compiler.linkflags.append(compiler.Dep(lib_path))
|
||||
|
||||
for library in dynamic_libs:
|
||||
source_path = os.path.join(lib_folder, library)
|
||||
output_path = os.path.join(binary.localFolder, library)
|
||||
|
||||
def make_linker(source_path, output_path):
|
||||
def link(context, binary):
|
||||
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
|
||||
return output
|
||||
return link
|
||||
|
||||
linker = make_linker(source_path, output_path)
|
||||
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
|
||||
SdkHelpers.configureCxx(context, binary, sdk)
|
||||
|
||||
return binary
|
||||
|
||||
def HL2Library(self, context, name, sdk):
|
||||
binary = context.compiler.Library(name)
|
||||
def HL2Library(self, context, compiler, name, sdk):
|
||||
binary = self.Library(context, compiler, name)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return self.ConfigureForHL2(binary, sdk)
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2Project(self, context, name):
|
||||
project = context.compiler.LibraryProject(name)
|
||||
self.ConfigureForExtension(context, project.compiler)
|
||||
return project
|
||||
def HL2Config(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2Config(self, project, name, sdk):
|
||||
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
|
||||
return self.ConfigureForHL2(binary, sdk)
|
||||
if getattr(builder, 'target', None) is not None:
|
||||
sys.stderr.write("Your output folder was configured for AMBuild 2.1.\n")
|
||||
sys.stderr.write("Please remove your output folder and reconfigure to continue.\n")
|
||||
os._exit(1)
|
||||
|
||||
Extension = ExtensionConfig()
|
||||
Extension.detectSDKs()
|
||||
Extension.configure()
|
||||
|
||||
# This will clone the list and each cxx object as we recurse, preventing child
|
||||
# scripts from messing up global state.
|
||||
builder.targets = builder.CloneableList(Extension.all_targets)
|
||||
|
||||
# Add additional buildscripts here
|
||||
BuildScripts = [
|
||||
'AMBuilder',
|
||||
'AMBuilder',
|
||||
]
|
||||
|
||||
if builder.backend == 'amb2':
|
||||
BuildScripts += [
|
||||
'PackageScript',
|
||||
]
|
||||
BuildScripts += [
|
||||
'PackageScript',
|
||||
]
|
||||
|
||||
builder.RunBuildScripts(BuildScripts, { 'Extension': Extension})
|
||||
builder.Build(BuildScripts, { 'Extension': Extension })
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
projectName = 'l4dtoolz'
|
||||
import os
|
||||
|
||||
# smsdk_ext.cpp will be automatically added later
|
||||
sourceFiles = [
|
||||
project = builder.LibraryProject('l4dtoolz')
|
||||
project.sources += [
|
||||
'l4dtoolz_mm.cpp',
|
||||
'signature.cpp',
|
||||
'memutils.cpp',
|
||||
]
|
||||
|
||||
###############
|
||||
# Make sure to edit PackageScript, which copies your files to their appropriate locations
|
||||
# Simple extensions do not need to modify past this point.
|
||||
|
||||
project = Extension.HL2Project(builder, projectName)
|
||||
|
||||
project.sources += sourceFiles
|
||||
|
||||
for sdk_name in Extension.sdks:
|
||||
sdk = Extension.sdks[sdk_name]
|
||||
|
||||
binary = Extension.HL2Config(project, projectName + sdk.ext, sdk)
|
||||
if sdk['name'] in ['mock']:
|
||||
continue
|
||||
|
||||
Extension.extensions = builder.Add(project)
|
||||
for cxx in builder.targets:
|
||||
if not cxx.target.arch in sdk['platforms'][cxx.target.platform]:
|
||||
continue
|
||||
|
||||
binary = Extension.HL2Config(project, builder, cxx, 'l4dtoolz_mm', sdk)
|
||||
|
||||
Extension.extensions += builder.Add(project)
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# Makefile
|
||||
|
||||
HX_SDK = ../hl2sdk-l4d2
|
||||
HX_METAMOD = ../mmsource
|
||||
#
|
||||
# l4dtoolz_mm.so
|
||||
#
|
||||
HX_INCLUDE = -I. \
|
||||
-I$(HX_METAMOD)/core \
|
||||
-I$(HX_METAMOD)/core/sourcehook \
|
||||
-I$(HX_SDK)/public \
|
||||
-I$(HX_SDK)/public/tier0 \
|
||||
-I$(HX_SDK)/public/tier1 \
|
||||
-I$(HX_SDK)/public/engine \
|
||||
-I$(HX_SDK)/public/mathlib
|
||||
|
||||
#
|
||||
HX_FLAGS = -DSOURCE_ENGINE=9
|
||||
|
||||
#
|
||||
HX_FLAGS += -DSE_EPISODEONE=1 \
|
||||
-DSE_DARKMESSIAH=2 \
|
||||
-DSE_ORANGEBOX=3 \
|
||||
-DSE_BLOODYGOODTIME=4 \
|
||||
-DSE_EYE=5 \
|
||||
-DSE_CSS=6 \
|
||||
-DSE_ORANGEBOXVALVE=7 \
|
||||
-DSE_LEFT4DEAD=8 \
|
||||
-DSE_LEFT4DEAD2=9 \
|
||||
-DSE_ALIENSWARM=10 \
|
||||
-DSE_PORTAL2=11 \
|
||||
-DSE_CSGO=12
|
||||
|
||||
#
|
||||
HX_FLAGS += -DPOSIX \
|
||||
-Dstricmp=strcasecmp \
|
||||
-D_stricmp=strcasecmp \
|
||||
-D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf \
|
||||
-D_vsnprintf=vsnprintf \
|
||||
-D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Wno-switch \
|
||||
-Wno-unused \
|
||||
-msse \
|
||||
-DHAVE_STDINT_H \
|
||||
-m32 \
|
||||
-DNDEBUG \
|
||||
-O3 \
|
||||
-funroll-loops \
|
||||
-pipe \
|
||||
-fno-strict-aliasing \
|
||||
-D_LINUX \
|
||||
-mfpmath=sse \
|
||||
-fvisibility=hidden \
|
||||
-Wno-non-virtual-dtor \
|
||||
-Wno-overloaded-virtual \
|
||||
-Wno-deprecated-register \
|
||||
-fno-exceptions \
|
||||
-fno-rtti \
|
||||
-fvisibility-inlines-hidden
|
||||
|
||||
#
|
||||
HX_LIB = Release/l4dtoolz_mm.o \
|
||||
Release/signature.o \
|
||||
$(HX_SDK)/lib/linux/tier1_i486.a \
|
||||
libvstdlib_srv.so \
|
||||
libtier0_srv.so
|
||||
|
||||
#
|
||||
all:
|
||||
mkdir -p Release
|
||||
ln -sf $(HX_SDK)/lib/linux/libvstdlib_srv.so libvstdlib_srv.so;
|
||||
ln -sf $(HX_SDK)/lib/linux/libtier0_srv.so libtier0_srv.so;
|
||||
#
|
||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/l4dtoolz_mm.o -c l4dtoolz_mm.cpp
|
||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/signature.o -c signature.cpp
|
||||
clang $(HX_INCLUDE) $(HX_LIB) -m32 -shared -static-libgcc -ldl -lm -o Release/l4dtoolz_mm.so
|
||||
#
|
||||
rm -rf Release/*.o
|
||||
@@ -1,83 +0,0 @@
|
||||
# Makefile
|
||||
|
||||
HX_SDK = ../hl2sdk-l4d
|
||||
HX_METAMOD = ../mmsource
|
||||
#
|
||||
# l4dtoolz_mm.so
|
||||
#
|
||||
HX_INCLUDE = -I. \
|
||||
-I$(HX_METAMOD)/core \
|
||||
-I$(HX_METAMOD)/core/sourcehook \
|
||||
-I$(HX_SDK)/public \
|
||||
-I$(HX_SDK)/public/tier0 \
|
||||
-I$(HX_SDK)/public/tier1 \
|
||||
-I$(HX_SDK)/public/engine \
|
||||
-I$(HX_SDK)/public/mathlib
|
||||
|
||||
#
|
||||
HX_FLAGS = -DSOURCE_ENGINE=8
|
||||
|
||||
#
|
||||
HX_FLAGS += -DSE_EPISODEONE=1 \
|
||||
-DSE_DARKMESSIAH=2 \
|
||||
-DSE_ORANGEBOX=3 \
|
||||
-DSE_BLOODYGOODTIME=4 \
|
||||
-DSE_EYE=5 \
|
||||
-DSE_CSS=6 \
|
||||
-DSE_ORANGEBOXVALVE=7 \
|
||||
-DSE_LEFT4DEAD=8 \
|
||||
-DSE_LEFT4DEAD2=9 \
|
||||
-DSE_ALIENSWARM=10 \
|
||||
-DSE_PORTAL2=11 \
|
||||
-DSE_CSGO=12
|
||||
|
||||
#
|
||||
HX_FLAGS += -DPOSIX \
|
||||
-Dstricmp=strcasecmp \
|
||||
-D_stricmp=strcasecmp \
|
||||
-D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf \
|
||||
-D_vsnprintf=vsnprintf \
|
||||
-D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Wno-switch \
|
||||
-Wno-unused \
|
||||
-msse \
|
||||
-DHAVE_STDINT_H \
|
||||
-m32 \
|
||||
-DNDEBUG \
|
||||
-O3 \
|
||||
-funroll-loops \
|
||||
-pipe \
|
||||
-fno-strict-aliasing \
|
||||
-D_LINUX \
|
||||
-mfpmath=sse \
|
||||
-fvisibility=hidden \
|
||||
-Wno-non-virtual-dtor \
|
||||
-Wno-overloaded-virtual \
|
||||
-Wno-deprecated-register \
|
||||
-fno-exceptions \
|
||||
-fno-rtti \
|
||||
-fvisibility-inlines-hidden
|
||||
|
||||
#
|
||||
HX_LIB = Release/l4dtoolz_mm.o \
|
||||
Release/signature.o \
|
||||
$(HX_SDK)/lib/linux/tier1_i486.a \
|
||||
libvstdlib.so \
|
||||
libtier0.so
|
||||
|
||||
#
|
||||
all:
|
||||
mkdir -p Release
|
||||
ln -sf $(HX_SDK)/lib/linux/libvstdlib.so libvstdlib.so;
|
||||
ln -sf $(HX_SDK)/lib/linux/libtier0.so libtier0.so;
|
||||
#
|
||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/l4dtoolz_mm.o -c l4dtoolz_mm.cpp
|
||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/signature.o -c signature.cpp
|
||||
clang $(HX_INCLUDE) $(HX_LIB) -m32 -shared -static-libgcc -ldl -lm -o Release/l4dtoolz_mm.so
|
||||
#
|
||||
rm -rf Release/*.o
|
||||
@@ -1,4 +1,4 @@
|
||||
# L4DToolz by ivailosp
|
||||
# L4DToolz
|
||||
|
||||
https://forums.alliedmods.net/showthread.php?t=93600
|
||||
|
||||
@@ -7,5 +7,4 @@ Metamod plugin to unlock the max player limit on L4D and L4D2.
|
||||
# CVARS
|
||||
|
||||
- sv_maxplayers - max human players that can join your server. -1 to disable and use standart check (range 0 to 32).
|
||||
- sv_removehumanlimit - remove kick for players (only L4D) when they are more than 8 for vs and 4 for coop(0 to disable, 1 to enable).
|
||||
- sv_force_unreserved - if you set it to 1 before connection from lobby your server will stay unreserved and allow players to connect using connect command, this command sets.
|
||||
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
// CBaseServer vtable for l4d1 and l4d2 games
|
||||
// Header file created by - A1m`
|
||||
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* Left 4 Downtown SourceMod Extension
|
||||
* Copyright (C) 2021-2023 A1m`;
|
||||
* =============================================================================
|
||||
*
|
||||
* 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 BASESERVER_H
|
||||
#define BASESERVER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <iserver.h>
|
||||
#include <netadr.h>
|
||||
#include <irecipientfilter.h>
|
||||
#include <bitbuf.h>
|
||||
#include <utlvector.h>
|
||||
#include <checksum_crc.h>
|
||||
|
||||
class IClient;
|
||||
class CBaseClient;
|
||||
class CClientFrame;
|
||||
class CFrameSnapshot;
|
||||
class CLC_SplitPlayerConnect;
|
||||
class CNetworkStringTableContainer;
|
||||
class INetworkStringTable;
|
||||
|
||||
enum server_state_t
|
||||
{
|
||||
ss_dead = 0, // Dead
|
||||
ss_loading, // Spawning
|
||||
ss_active, // Running
|
||||
ss_paused, // Running, but paused
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
netadr_t adr; // Address where challenge value was sent to.
|
||||
int challenge; // To connect, adr IP address must respond with this #
|
||||
float time; // # is valid for only a short duration.
|
||||
} challenge_t;
|
||||
|
||||
class CBaseServer :
|
||||
public IServer
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CBaseServer() = 0;
|
||||
|
||||
public: // IConnectionlessPacketHandler implementation
|
||||
|
||||
virtual bool ProcessConnectionlessPacket( netpacket_t *packet ) = 0;
|
||||
|
||||
public: // IServer implementation
|
||||
|
||||
virtual int GetNumClients( void ) const = 0;
|
||||
virtual int GetNumProxies( void ) const = 0;
|
||||
virtual int GetNumFakeClients( void ) const = 0;
|
||||
virtual int GetMaxClients( void ) const = 0;
|
||||
virtual IClient* GetClient( int index ) = 0;
|
||||
virtual int GetClientCount( void ) const = 0;
|
||||
virtual int GetUDPPort( void ) const = 0;
|
||||
virtual float GetTime( void ) const = 0;
|
||||
virtual int GetTick( void ) const = 0;
|
||||
virtual float GetTickInterval( void ) const = 0;
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
virtual float GetTimescale( void ) const = 0; // l4d2 only
|
||||
#endif
|
||||
|
||||
virtual const char* GetName( void ) const = 0;
|
||||
virtual const char* GetMapName( void ) const = 0;
|
||||
virtual int GetSpawnCount( void ) const = 0;
|
||||
virtual int GetNumClasses( void ) const = 0;
|
||||
virtual int GetClassBits( void ) const = 0;
|
||||
virtual void GetNetStats( float &avgIn, float &avgOut ) = 0;
|
||||
virtual int GetNumPlayers( void ) = 0;
|
||||
virtual bool GetPlayerInfo( int nClientIndex, player_info_t *pinfo ) = 0;
|
||||
virtual bool IsActive( void ) const = 0;
|
||||
virtual bool IsLoading( void ) const = 0;
|
||||
virtual bool IsDedicated( void ) const = 0;
|
||||
virtual bool IsPaused( void ) const = 0;
|
||||
virtual bool IsMultiplayer( void ) const = 0;
|
||||
virtual bool IsPausable( void ) const = 0;
|
||||
virtual bool IsHLTV( void ) const = 0;
|
||||
virtual const char* GetPassword( void ) const = 0;
|
||||
virtual void SetPaused( bool paused ) = 0;
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
virtual void SetTimescale( float flTimescale ) = 0; // l4d2 only
|
||||
#endif
|
||||
|
||||
virtual void SetPassword( const char *password ) = 0;
|
||||
virtual void BroadcastMessage( INetMessage &msg, bool onlyActive = false, bool reliable = false ) = 0;
|
||||
virtual void BroadcastMessage( INetMessage &msg, IRecipientFilter &filter ) = 0;
|
||||
virtual void DisconnectClient( IClient *client, const char *reason ) = 0;
|
||||
virtual float GetCPUUsage( void ) = 0;
|
||||
|
||||
public: // Other
|
||||
|
||||
virtual void BroadcastPrintf( const char *fmt, ... ) = 0;
|
||||
virtual void SetMaxClients( int number ) = 0;
|
||||
virtual void WriteDeltaEntities( CBaseClient *client, CClientFrame *to, CClientFrame *from, bf_write &pBuf ) = 0;
|
||||
virtual void WriteTempEntities( CBaseClient *client, CFrameSnapshot *to, CFrameSnapshot *from, bf_write &pBuf, int nMaxEnts ) = 0;
|
||||
virtual void Init( bool isDedicated ) = 0;
|
||||
virtual void Clear( void ) = 0;
|
||||
virtual void Shutdown( void ) = 0;
|
||||
virtual CBaseClient* CreateFakeClient( const char *name ) = 0;
|
||||
virtual void RemoveClientFromGame( CBaseClient* client ) = 0;
|
||||
virtual void SendClientMessages( bool bSendSnapshots ) = 0;
|
||||
virtual void FillServerInfo( SVC_ServerInfo &serverinfo ) = 0;
|
||||
virtual void UserInfoChanged( int nClientIndex ) = 0;
|
||||
virtual void RejectConnection( const netadr_t &adr, char *fmt, ... ) = 0;
|
||||
virtual bool CheckIPRestrictions( const netadr_t &adr, int nAuthProtocol ) = 0;
|
||||
|
||||
virtual IClient* ConnectClient( netadr_t &adr, int protocol, int challenge, int authProtocol,
|
||||
const char *name, const char *password, const char *hashedCDkey, int cdKeyLen,
|
||||
CUtlVector< CLC_SplitPlayerConnect * > &splitScreenClients, bool isClientLowViolence ) = 0;
|
||||
|
||||
virtual CBaseClient* CreateNewClient( int slot ) = 0;
|
||||
virtual bool FinishCertificateCheck( netadr_t &adr, int nAuthProtocol, const char *szRawCertificate ) = 0;
|
||||
virtual int GetChallengeNr( netadr_t &adr ) = 0;
|
||||
virtual int GetChallengeType( netadr_t &adr ) = 0;
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
virtual bool CheckHostVersion( netadr_t &adr, int checkVersion ) = 0; // l4d2 only
|
||||
#else
|
||||
virtual bool CheckProtocol( netadr_t& adr, int nProtocol ) = 0; // l4d1
|
||||
#endif
|
||||
|
||||
virtual bool CheckChallengeNr( netadr_t &adr, int nChallengeValue ) = 0;
|
||||
virtual bool CheckChallengeType( CBaseClient *client, int nNewUserID, netadr_t &adr, int nAuthProtocol, const char *pchLogonCookie, int cbCookie ) = 0;
|
||||
virtual bool CheckPassword(netadr_t &adr, const char *password, const char *name ) = 0;
|
||||
virtual void ReplyChallenge(netadr_t &adr, bf_read &msg ) = 0;
|
||||
virtual void ReplyServerChallenge( netadr_t &adr ) = 0;
|
||||
virtual void ReplyReservationRequest( netadr_t &adr, bf_read &msg ) = 0;
|
||||
virtual void CalculateCPUUsage( void ) = 0;
|
||||
virtual bool ShouldUpdateMasterServer( void ) = 0;
|
||||
virtual void UpdateMasterServerPlayers( void ) = 0;
|
||||
|
||||
// vtable offset - 0
|
||||
server_state_t m_State; // 4, some actions are only valid during load (CBaseServer::IsActive)
|
||||
int m_Socket; // 8, network socket (CBaseServer::GetUDPPort)
|
||||
int m_nTickCount; // 12, current server tick (CBaseServer::GetTick)
|
||||
char m_szMapname[64]; // 16, map name without path and extension (CBaseServer::Clear)
|
||||
char m_szSkyname[64]; // 80, skybox name (CBaseServer::Clear)
|
||||
char m_Password[32]; // 144, server password (CBaseServer::SetPassword)
|
||||
|
||||
CRC32_t worldmapCRC; // 176, For detecting that client has a hacked local copy of map, the client will be dropped if this occurs. (CGameServer::SpawnServer)
|
||||
CRC32_t clientDllCRC; // 180, The dll that this server is expecting clients to be using. (CGameServer::SpawnServer)
|
||||
CRC32_t stringTableCRC; // 184, (CGameServer::SpawnServer)
|
||||
|
||||
CNetworkStringTableContainer* m_StringTables; // 188, newtork string table container (CBaseServer::GetUserInfoTable)
|
||||
|
||||
INetworkStringTable* m_pInstanceBaselineTable; // 192, (CBaseServer::GetInstanceBaselineTable)
|
||||
INetworkStringTable* m_pLightStyleTable; // 196, (CBaseServer::GetLightStyleTable)
|
||||
INetworkStringTable* m_pUserInfoTable; // 200, (CBaseServer::GetUserInfoTable)
|
||||
INetworkStringTable* m_pServerStartupTable; // 204, (CGameServer::SetQueryPortFromSteamServer)
|
||||
INetworkStringTable* m_pDownloadableFileTable; // 208, (CGameServer::CreateEngineStringTables)
|
||||
|
||||
bf_write m_Signon; // 212, (24 byte) (CBaseServer::Clear)
|
||||
CUtlMemory<byte> m_SignonBuffer; // 236, (12 byte) (CBaseServer::Clear)
|
||||
|
||||
int serverclasses; // 248, number of unique server classes (CBaseServer::Clear)
|
||||
int serverclassbits; // 252, log2 of serverclasses (CBaseServer::Clear)
|
||||
|
||||
int m_nUserid; // 256, increases by one with every new client (CBaseServer::GetNextUserID)
|
||||
|
||||
int m_nMaxclients; // 260, Current max # (CBaseServer::SetMaxClients)
|
||||
int m_nSpawnCount; // 264, Number of servers spawned since start, used to check late spawns (e.g., when d/l'ing lots of data) (CBaseServer::GetSpawnCount)
|
||||
|
||||
float m_flTickInterval; // 268, time for 1 tick in seconds (CBaseServer::GetTickInterval)
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
float m_flTimescale; // 272, the game time scale (multiplied in conjunction with host_timescale) (CBaseServer::GetTimescale)
|
||||
#endif
|
||||
|
||||
CUtlVector<CBaseClient*> m_Clients; // l4d2 - 276 (20 byte), l4d1 - 272, array of up to [maxclients] client slots. (CBaseServer::GetClient)
|
||||
|
||||
bool m_bIsDedicated; // l4d2 - 296, l4d1 - 292, (CBaseServer::IsDedicated)
|
||||
// 3 byte alignment
|
||||
|
||||
CUtlVector<challenge_t> m_ServerQueryChallenges; // l4d2 - 300 (20 byte), l4d1 - 296, prevent spoofed IP's from server queries/connecting (CBaseServer::GetChallengeNr)
|
||||
|
||||
float m_fCPUPercent; // l4d2 - 320, l4d1 - 316, (CBaseServer::GetCPUUsage)
|
||||
float m_fStartTime; // l4d2 - 324, l4d1 - 320, (CBaseServer::CalculateCPUUsage)
|
||||
float m_fLastCPUCheckTime; // l4d2 - 328, l4d1 - 324, (CBaseServer::CalculateCPUUsage)
|
||||
|
||||
// This is only used for Steam's master server updater to refer to this server uniquely.
|
||||
bool m_bRestartOnLevelChange; // l4d2 - 332, l4d1 - 328, (CBaseServer::CheckMasterServerRequestRestart)
|
||||
bool m_bMasterServerRulesDirty; // l4d2 - 333, l4d1 - 329, (CBaseServer::UpdateMasterServerRules)
|
||||
|
||||
// 3 byte alignment
|
||||
double m_flLastMasterServerUpdateTime; // l4d2 - 336 (8 byte), l4d1 - 332, (CBaseServer::UpdateMasterServer)
|
||||
|
||||
struct SplitDisconnect_t
|
||||
{
|
||||
CBaseClient* m_pUser;
|
||||
CBaseClient* m_pSplit;
|
||||
};
|
||||
|
||||
CUtlVector< SplitDisconnect_t > m_QueuedForDisconnect; // l4d2 - 344 (20 byte), l4d1 - 340, (CBaseServer::QueueSplitScreenDisconnect)
|
||||
|
||||
uint64 m_nReservationCookie; // l4d2 - 364 (8 byte), l4d1 - 360, if this server has been reserved, cookie that connecting clients must present (CBaseServer::GetReservationCookie)
|
||||
float m_flReservationExpiryTime; // l4d2 - 372, l4d1 - 368, time at which reservation expires (CBaseServer::UpdateReservedState)
|
||||
float m_flTimeLastClientLeft; // l4d2 - 376, l4d1 - 372, time when last client left server (CGameServer::UpdateHibernationState)
|
||||
int m_numGameSlots; // l4d2 - 380, l4d1 - 376, number of game slots allocated (CBaseServer::ConnectClient)
|
||||
CUtlString m_GameType; // l4d2 - 384 (16 byte ?), l4d1 - 380, (CBaseServer::ClearTagStrings)
|
||||
|
||||
CUtlVector<char> m_GameData; // l4d2 - 400 (20 byte), l4d1 - 396, (CBaseServer::GetGameData)
|
||||
int m_GameDataVersion; // l4d2 - 420, l4d1 - 416, (CBaseServer::GetGameDataVersion)
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD // l4d1
|
||||
bool m_bSteamMasterHeartbeatsEnabled; // l4d1 - 420 (CBaseServer::UpdateMasterServer)
|
||||
// 3 byte alignment
|
||||
#endif
|
||||
|
||||
float m_flTimeReservationGraceStarted; // l4d2 - 424, l4d1 - 424, time when client attempted to connect and was granted a reservation grace period (CBaseServer::CanAcceptChallengesFrom)
|
||||
netadr_t m_adrReservationGraceStarted; // l4d2 - 428 (12 byte), l4d1 - 428, netadr of the client for whom reservation grace has been given (CBaseServer::CanAcceptChallengesFrom)
|
||||
|
||||
struct ReservationStatus_t
|
||||
{
|
||||
ReservationStatus_t() : m_bActive(false), m_bSuccess(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool m_bActive;
|
||||
bool m_bSuccess;
|
||||
// 2 byte alignment
|
||||
netadr_t m_Remote;
|
||||
};
|
||||
|
||||
ReservationStatus_t m_ReservationStatus; // l4d2 - 440 (16 byte?), l4d1 - 440, (CBaseServer::ClearReservationStatus)
|
||||
};
|
||||
// size 456 l4d2 and l4d1
|
||||
|
||||
#endif // BASESERVER_H
|
||||
+30
-14
@@ -1,21 +1,37 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et:
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
from ambuild2 import run
|
||||
try:
|
||||
from ambuild2 import run, util
|
||||
except:
|
||||
try:
|
||||
import ambuild
|
||||
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
|
||||
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
|
||||
except:
|
||||
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
||||
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
||||
sys.exit(1)
|
||||
|
||||
# Simple extensions do not need to modify this file.
|
||||
# Hack to show a decent upgrade message, which wasn't done until 2.2.
|
||||
ambuild_version = getattr(run, 'CURRENT_API', '2.1')
|
||||
if ambuild_version.startswith('2.1'):
|
||||
sys.stderr.write("AMBuild 2.2 or higher is required; please update\n")
|
||||
sys.exit(1)
|
||||
|
||||
builder = run.PrepareBuild(sourcePath = sys.path[0])
|
||||
|
||||
builder.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||
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')
|
||||
builder.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
|
||||
parser.options.add_argument('--hl2sdk-manifest-path', type=str, dest='hl2sdk_manifest', default=None,
|
||||
help='Path to HL2SDK Manifests')
|
||||
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||
help='Path to Metamod:Source')
|
||||
builder.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
help='Enable debugging symbols')
|
||||
builder.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')
|
||||
builder.options.add_option('-s', '--sdks', default='all', dest='sdks',
|
||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
||||
'comma-delimited list of engine names (default: %default)')
|
||||
|
||||
builder.Configure()
|
||||
parser.options.add_argument('-s', '--sdks', default='l4d2', dest='sdks',
|
||||
help='Build against specified SDKs; valid args are "none", "all", "present",'
|
||||
' or comma-delimited list of engine names')
|
||||
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
|
||||
help="Override the target architecture (use commas to separate multiple targets).")
|
||||
parser.Configure()
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef _INCLUDE_GAME_OFFSETS_
|
||||
#define _INCLUDE_GAME_OFFSETS_
|
||||
|
||||
#if SH_SYS == SH_SYS_WIN32
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
const int sv_offs = 6; // IServer pointer (in IVEngineServer::CreateFakeClient)
|
||||
const int maxhuman_idx = 131; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||
#else
|
||||
const int sv_offs = 8; // IServer pointer (in IVEngineServer::CreateFakeClient)
|
||||
const int maxhuman_idx = 136; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||
#endif
|
||||
#else
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
const char* engine_dll = "engine.so";
|
||||
const int maxhuman_idx = 132; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||
#else
|
||||
const char* engine_dll = "engine_srv.so";
|
||||
const int maxhuman_idx = 137; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif //_INCLUDE_GAME_OFFSETS_
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef _INCLUDE_GAME_SIGNATURE_
|
||||
#define _INCLUDE_GAME_SIGNATURE_
|
||||
|
||||
#ifdef WIN32
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
#include "l4d1_signature_win32.h"
|
||||
#else
|
||||
#include "l4d2_signature_win32.h"
|
||||
#endif
|
||||
#else
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
#include "l4d1_signature_linux.h"
|
||||
#else
|
||||
#include "l4d2_signature_linux.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif //_INCLUDE_GAME_SIGNATURE_
|
||||
@@ -1,57 +0,0 @@
|
||||
#ifndef _INCLUDE_L4D1_SIGNATURE_LINUX_
|
||||
#define _INCLUDE_L4D1_SIGNATURE_LINUX_
|
||||
|
||||
const char* server_dll[] = {"server.so", 0};
|
||||
const char* engine_dll[] = {"engine.so", 0};
|
||||
const char* matchmaking_dll[] = {"matchmaking_ds.so", "matchmaking.so", 0};
|
||||
|
||||
//CBaseServer::GetMaxHumanPlayers(void)const
|
||||
//function is in engine.so
|
||||
const char* friends_lobby = "\x0F\x53\x83\xEC\x18\xE8\xC3\xC3\xC3\xC3\x81\xC3\xB9\xB8\x23\x00";
|
||||
unsigned char friends_lobby_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
||||
void* friends_lobby_org = NULL;
|
||||
|
||||
//CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int, CUtlVector<CLC_SplitPlayerConnect, CUtlMemory<CLC_SplitPlayerConnect, int>> &, bool)
|
||||
//function is in engine.so, loc jz/jnz, above #Valve_Reject_Hidden_Game
|
||||
const char* lobby_sux = "\x0A\x8B\xAE\x78\x01\x00\x00\x85\xED\x0F\x85";
|
||||
const char* lobby_sux_new = "\x06\x00\xB8\x01\x00\x00\x00\x90";
|
||||
void* lobby_sux_org = NULL;
|
||||
|
||||
//CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int, CUtlVector<CLC_SplitPlayerConnect, CUtlMemory<CLC_SplitPlayerConnect, int>> &, bool)
|
||||
//function is in engine.so, above #Valve_Reject_Server_Full
|
||||
const char* max_players = "\x0F\xFF\x50\xC3\x29\xC7\x01\xFD\x3B\xC3\xC3\xC3\x00\x00\x0F\x8E";
|
||||
unsigned char max_players_new[]= {0x06, 0x07, 0x83, 0xFF, 0x3C, 0x90, 0x90, 0x90};
|
||||
void* max_players_org = NULL;
|
||||
|
||||
//CServerGameClients::GetMaxHumanPlayers(void)
|
||||
//function is in server.so
|
||||
const char* server_bplayers = "\x1F\x53\x83\xEC\xC3\xE8\xC3\xC3\xC3\xC3\x81\xC3\xC3\xC3\xC3\xC3\x8B\x83\xC3\xC3\xC3\xC3\x8B\x00\x85\xC0\x74\x10\x8B\x10\x89\x04";
|
||||
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
||||
void* server_bplayers_org = NULL;
|
||||
|
||||
//CTerrorGameRules::ClientConnected(edict_t *, char const*, char const*, char *, int)
|
||||
//function is in server.so
|
||||
const char* human_limit = "\x12\x8B\x00\xC3\xC3\x24\x40\x89\x14\xC3\xFF\x90\xC3\x02\x00\x00\x39\xF0\x7E";
|
||||
const char* human_limit_new = "\x02\x11\x90\x90";
|
||||
void* human_limit_org = NULL;
|
||||
|
||||
//CGameServer::SetMaxClients(int)
|
||||
//function is in engine.so
|
||||
const char* players = "\x13\x83\xBB\xC3\xC3\xC3\xC3\x01\x7F\xC3\x8B\x80\x0C\xC3\xC3\x00\x89\xC3\xC3\xE8";
|
||||
const char* players_new = "\x03\x1D\x89\xC2\xEB";
|
||||
void* players_org = NULL;
|
||||
|
||||
//CBaseServer::SetReservationCookie(unsigned long long, char const*, ...)
|
||||
//function in engine.so
|
||||
const char* unreserved = "\x15\x55\x57\x56\x53\x81\xEC\x3C\x01\x00\x00\xE8\xC3\xC3\xC3\xC3\x81\xC3\x33\x8E\x23\x00";
|
||||
const char* unreserved_new = "\x01\x00\xC3";
|
||||
void* unreserved_org = NULL;
|
||||
|
||||
//CMatchTitle::GetTotalNumPlayersSupported(void)
|
||||
//function in matchmaking_ds.so
|
||||
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
|
||||
unsigned char lobby_match_new[] = {0x01, 0x02, 0xC3};
|
||||
void* lobby_match_org = NULL;
|
||||
|
||||
#endif //_INCLUDE_L4D1_SIGNATURE_LINUX_
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef _INCLUDE_L4D1_SIGNATURE_WIN32_
|
||||
#define _INCLUDE_L4D1_SIGNATURE_WIN32_
|
||||
|
||||
const char* server_dll[] = {"server.dll", 0};
|
||||
const char* engine_dll[] = {"engine.dll", 0};
|
||||
const char* matchmaking_dll[] = {"matchmaking_ds.dll", "matchmaking.dll", 0};
|
||||
|
||||
const char* friends_lobby = "\x12\x56\x8B\xF1\x8B\x0D\xC3\xC3\xC3\xC3\x85\xC9\x74\xC3\x8B\x01\x8B\x50\x48";
|
||||
unsigned char friends_lobby_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
||||
void* friends_lobby_org = NULL;
|
||||
|
||||
const char* max_players = "\x28\x83\xBE\xC3\xC3\x00\x00\x00\x74\xC3\x8B\x54\xC3\xC3\x8B\x06\x8B\x7A\xC3\x8B\x50\x10\x8B\xCE\xFF\xD2\x2B\xF8\x8B\x06\x8B\x50\x08\x8B\xCE\xFF\xD2\x03\xC7\x3B\x86";
|
||||
unsigned char max_players_new[]= {0x06, 0x26, 0x83, 0xF8, 0x3C, 0x90, 0x90, 0x90};
|
||||
void* max_players_org = NULL;
|
||||
|
||||
const char* lobby_sux_new = "\x02\x07\x90\x90";
|
||||
void* lobby_sux_org = NULL;
|
||||
|
||||
const char* server_bplayers = "\x1D\x56\x8B\xF1\xE8\xC3\xC3\xC3\xC3\x8B\x4C\x24\x08\x89\x01\x8B\x0D\xC3\xC3\xC3\xC3\x85\xC9\x74\xC3\x8B\x11\x8B\x42\x48";
|
||||
unsigned char server_bplayers_new[] = {0x05, 0x1A, 0xB8, 0x3C, 0x00, 0x00, 0x00};
|
||||
void* server_bplayers_org = NULL;
|
||||
|
||||
const char* human_limit = "\x15\x8B\x13\x8B\x82\xC3\xC3\x00\x00\x8B\xCB\xFF\xD0\x3B\xF8\x7C\xC3\x8B\xC3\xC3\xC3\x8B";
|
||||
const char* human_limit_new = "\x01\x0E\xEB";
|
||||
void* human_limit_org = NULL;
|
||||
|
||||
const char* players = "\x10\x56\x8B\xF1\x8B\x86\xC3\x02\x00\x00\x8B\x4C\x24\x08\x3B\xC8\x7F";
|
||||
const char* players_new = "\x02\x0F\x90\x90";
|
||||
void* players_org = NULL;
|
||||
|
||||
const char* unreserved = "\x1E\x81\xEC\xC3\xC3\x00\x00\x55\x8B\xAC\xC3\xC3\xC3\x00\x00\x56\x8B\xB4\xC3\xC3\xC3\x00\x00\x57\x8B\xBC\xC3\xC3\xC3\x00\x00";
|
||||
const char* unreserved_new = "\x01\x00\xC3";
|
||||
void* unreserved_org = NULL;
|
||||
|
||||
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
|
||||
unsigned char lobby_match_new[] = {0x01, 0x01, 0xC3};
|
||||
void* lobby_match_org = NULL;
|
||||
|
||||
#endif //_INCLUDE_L4D1_SIGNATURE_WIN32_
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef _INCLUDE_L4D2_SIGNATURE_LINUX_
|
||||
#define _INCLUDE_L4D2_SIGNATURE_LINUX_
|
||||
|
||||
const char* server_dll[] = {"server_srv.so", "server.so", 0};
|
||||
const char* engine_dll[] = {"engine_srv.so", "engine.so", 0};
|
||||
const char* matchmaking_dll[] = {"matchmaking_ds_srv.so", "matchmaking_srv.so", "matchmaking_ds.so", "matchmaking.so", 0};
|
||||
|
||||
const char* lobby_sux = "\x13\xFF\x50\xC3\x84\xC0\x0F\x84\xC3\xC3\xC3\xC3\x8B\x87\xC3\x01\x00\x00\x85\xC0";
|
||||
const char* lobby_sux_new = "\x06\x0B\xBE\x01\x00\x00\x00\x90";
|
||||
void *lobby_sux_org = NULL;
|
||||
|
||||
const char* max_players = "\x15\x89\xC6\x8B\x07\x89\x3C\x24\xFF\x50\xC3\x29\xC6\x01\xF3\x3B\x9F\xC3\x01\x00\x00\x0F";
|
||||
unsigned char max_players_new[]= {0x06, 0x0E, 0x83, 0xFB, 0x3C, 0x90, 0x90, 0x90};
|
||||
void *max_players_org = NULL;
|
||||
|
||||
const char* server_bplayers = "\x16\x55\x89\xE5\x83\xEC\x08\xE8\xC3\xC3\xC3\xC3\xC9\x3C\x01\x19\xC0\x83\xE0\xFC\x83\xC0\x08";
|
||||
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
||||
void *server_bplayers_org = NULL;
|
||||
|
||||
const char* players = "\x23\x55\x89\xE5\x53\x83\xEC\xC3\x8B\x5D\x08\x8B\x55\x0C\x8B\x83\xC3\xC3\x00\x00\x39\xD0\x7C\x0B\x8B\x83\xC3\xC3\x00\x00\x39\xC2\x0F\x4D\xC2\x8B";
|
||||
const char* players_new = "\x03\x13\x89\xD0\xEB";
|
||||
void *players_org = NULL;
|
||||
|
||||
const char* unreserved = "\x0F\x55\x89\xE5\x57\x56\x53\x81\xEC\x3C\x01\x00\x00\x8B\x5D\x08";
|
||||
const char* unreserved_new = "\x01\x00\xC3";
|
||||
void *unreserved_org = NULL;
|
||||
|
||||
const char* lobby_match = "\x0A\x55\xB8\x08\x00\x00\x00\x89\xE5\x5D\xC3";
|
||||
unsigned char lobby_match_new[] = {0x01, 0x02, 0xC3};
|
||||
void *lobby_match_org = NULL;
|
||||
|
||||
#endif //_INCLUDE_L4D2_SIGNATURE_LINUX_
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef _INCLUDE_L4D2_SIGNATURE_WIN32_
|
||||
#define _INCLUDE_L4D2_SIGNATURE_WIN32_
|
||||
|
||||
const char* server_dll[] = {"server.dll", 0};
|
||||
const char* engine_dll[] = {"engine.dll", 0};
|
||||
const char* matchmaking_dll[] = {"matchmaking_ds.dll", "matchmaking.dll", 0};
|
||||
|
||||
const char* max_players = "\x27\x83\xBE\xC3\xC3\x00\x00\x00\x74\xC3\x8B\xC3\xC3\x8B\x06\x8B\x7A\xC3\x8B\x50\x10\x8B\xCE\xFF\xD2\x2B\xF8\x8B\x06\x8B\x50\x08\x8B\xCE\xFF\xD2\x03\xC7\x3B\x86";
|
||||
unsigned char max_players_new[]= {0x06, 0x25, 0x83, 0xF8, 0x3C, 0x90, 0x90, 0x90};
|
||||
void* max_players_org = NULL;
|
||||
|
||||
const char* lobby_sux_new = "\x02\x07\x90\x90";
|
||||
void* lobby_sux_org = NULL;
|
||||
|
||||
const char* server_bplayers = "\x36\xF7\x05\xC3\xC3\xC3\xC3\x00\x10\x00\x00\x74\x07\xB8\xC3\xC3\xC3\xC3\xEB\x11\xA1\xC3\xC3\xC3\xC3\x8B\x40\x24\x85\xC0\x75\x05\xB8\xC3\xC3\xC3\xC3\x8B\x0D\xC3\xC3\xC3\xC3\x8B\x11\x50\x8B\x42\x10\xFF\xD0\x85\xC0\x74\x17";
|
||||
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
||||
void* server_bplayers_org = NULL;
|
||||
|
||||
const char* players = "\x0F\x56\x8B\xF1\x8B\x86\xC3\x02\x00\x00\x8B\x4D\xC3\x3B\xC8\x7F";
|
||||
const char* players_new = "\x02\x0E\x90\x90";
|
||||
void* players_org = NULL;
|
||||
|
||||
const char* unreserved = "\x21\x55\x8B\xEC\x81\xEC\xC3\xC3\x00\x00\xA1\xC3\xC3\xC3\xC3\x33\xC5\x89\xC3\xC3\x53\x8B\xC3\xC3\x56\x8B\xC3\xC3\x57\x8B\xC3\xC3\x3B\xBE";
|
||||
const char* unreserved_new = "\x01\x00\xC3";
|
||||
void* unreserved_org = NULL;
|
||||
|
||||
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
|
||||
unsigned char lobby_match_new[] = {0x01, 0x01, 0xC3};
|
||||
void* lobby_match_org = NULL;
|
||||
|
||||
#endif //_INCLUDE_L4D2_SIGNATURE_WIN32_
|
||||
|
||||
+142
-179
@@ -1,110 +1,95 @@
|
||||
#include "l4dtoolz_mm.h"
|
||||
#include "signature.h"
|
||||
#include "game_signature.h"
|
||||
#include "game_offsets.h"
|
||||
#include "baseserver.h"
|
||||
#include "memutils.h"
|
||||
#include "icommandline.h"
|
||||
#include "server_class.h"
|
||||
#include "sourcehook.h"
|
||||
#include "matchmaking/imatchframework.h"
|
||||
|
||||
l4dtoolz g_l4dtoolz;
|
||||
IServerGameDLL* gamedll = NULL;
|
||||
IServerGameClients* gameclients = NULL;
|
||||
IVEngineServer* engine = NULL;
|
||||
IMatchFramework* g_pMatchFramework = NULL;
|
||||
ICvar* g_pCVar = NULL;
|
||||
CBaseServer* g_pGameIServer = NULL;
|
||||
void* g_pGameRules = nullptr;
|
||||
int g_nGameSlots = -1;
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
void* l4dtoolz::max_players_friend_lobby = NULL;
|
||||
void* l4dtoolz::chuman_limit = NULL;
|
||||
#endif
|
||||
SH_DECL_HOOK1_void(IServerGameDLL, ApplyGameSettings, SH_NOATTRIB, 0, KeyValues*);
|
||||
SH_DECL_HOOK0(IMatchTitle, GetTotalNumPlayersSupported, SH_NOATTRIB, 0, int);
|
||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
|
||||
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, 0);
|
||||
SH_DECL_MANUALHOOK0(CTerrorGameRules_GetMaxHumanPlayers, maxhuman_idx, 0, 0, int);
|
||||
SH_DECL_HOOK2_void(CBaseServer, ReplyReservationRequest, SH_NOATTRIB, 0, netadr_t&, bf_read&);
|
||||
|
||||
void* l4dtoolz::max_players_connect = NULL;
|
||||
void* l4dtoolz::max_players_server_browser = NULL;
|
||||
void* l4dtoolz::lobby_sux_ptr = NULL;
|
||||
void* l4dtoolz::tmp_player = NULL;
|
||||
void* l4dtoolz::unreserved_ptr = NULL;
|
||||
void* l4dtoolz::lobby_match_ptr = NULL;
|
||||
ConVar sv_maxplayers("sv_maxplayers", "-1", FCVAR_SPONLY|FCVAR_NOTIFY, "Max Human Players", true, -1, true, 32, l4dtoolz::OnChangeMaxplayers);
|
||||
ConVar sv_force_unreserved("sv_force_unreserved", "0", FCVAR_SPONLY|FCVAR_NOTIFY, "Disallow lobby reservation cookie", true, 0, true, 1, l4dtoolz::OnChangeUnreserved);
|
||||
|
||||
ConVar sv_maxplayers("sv_maxplayers", "-1", 0, "Max Human Players", true, -1, true, 32, l4dtoolz::OnChangeMaxplayers);
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
ConVar sv_removehumanlimit("sv_removehumanlimit", "0", 0, "Remove Human limit reached kick", true, 0, true, 1, l4dtoolz::OnChangeRemovehumanlimit);
|
||||
#endif
|
||||
ConVar sv_force_unreserved("sv_force_unreserved", "0", 0, "Disallow lobby reservation cookie", true, 0, true, 1, l4dtoolz::OnChangeUnreserved);
|
||||
|
||||
void l4dtoolz::OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue )
|
||||
void l4dtoolz::OnChangeMaxplayers(IConVar *var, const char *pOldValue, float flOldValue)
|
||||
{
|
||||
int new_value = ((ConVar*)var)->GetInt();
|
||||
int old_value = atoi(pOldValue);
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
if (max_players_friend_lobby == NULL || max_players_connect == NULL || max_players_server_browser == NULL || lobby_sux_ptr == NULL) {
|
||||
#else
|
||||
if (max_players_connect == NULL || max_players_server_browser == NULL || lobby_sux_ptr == NULL) {
|
||||
#endif
|
||||
Msg("sv_maxplayers init error\n");
|
||||
if (g_pGameIServer == NULL) {
|
||||
Msg("g_pGameIServer pointer is not available\n");
|
||||
return;
|
||||
}
|
||||
if(new_value != old_value) {
|
||||
if(new_value >= 0) {
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
max_players_new[4] = friends_lobby_new[3] = server_bplayers_new[3] = (unsigned char)new_value;
|
||||
#else
|
||||
max_players_new[4] = server_bplayers_new[3] = (unsigned char)new_value;
|
||||
#endif
|
||||
if(lobby_match_ptr) {
|
||||
lobby_match_new[2] = (unsigned char)new_value;
|
||||
write_signature(lobby_match_ptr, lobby_match_new);
|
||||
} else {
|
||||
Msg("sv_maxplayers MS init error\n");
|
||||
}
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
write_signature(max_players_friend_lobby, friends_lobby_new);
|
||||
#endif
|
||||
write_signature(max_players_connect, max_players_new);
|
||||
write_signature(lobby_sux_ptr, lobby_sux_new);
|
||||
write_signature(max_players_server_browser, server_bplayers_new);
|
||||
if (new_value != old_value) {
|
||||
if (new_value >= 0) {
|
||||
g_nGameSlots = new_value;
|
||||
g_pGameIServer->m_numGameSlots = g_nGameSlots;
|
||||
} else {
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
write_signature(max_players_friend_lobby, friends_lobby_org);
|
||||
#endif
|
||||
write_signature(max_players_connect, max_players_org);
|
||||
write_signature(lobby_sux_ptr, lobby_sux_org);
|
||||
write_signature(max_players_server_browser, server_bplayers_org);
|
||||
|
||||
if(lobby_match_ptr)
|
||||
write_signature(lobby_match_ptr, lobby_match_org);
|
||||
g_nGameSlots = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
void l4dtoolz::OnChangeRemovehumanlimit ( IConVar *var, const char *pOldValue, float flOldValue )
|
||||
void l4dtoolz::OnChangeUnreserved(IConVar *var, const char *pOldValue, float flOldValue)
|
||||
{
|
||||
int new_value = ((ConVar*)var)->GetInt();
|
||||
int old_value = atoi(pOldValue);
|
||||
if(chuman_limit == NULL) {
|
||||
Msg( "sv_removehumanlimit init error\n");
|
||||
if (g_pGameIServer == NULL) {
|
||||
Msg("g_pGameIServer pointer is not available\n");
|
||||
return;
|
||||
}
|
||||
if(new_value != old_value) {
|
||||
if(new_value == 1) {
|
||||
write_signature(chuman_limit, human_limit_new);
|
||||
}else{
|
||||
write_signature(chuman_limit, human_limit_org);
|
||||
if (new_value != old_value) {
|
||||
if (new_value == 1) {
|
||||
g_pCVar->FindVar("sv_allow_lobby_connect_only")->SetValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void l4dtoolz::OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue )
|
||||
void Hook_ApplyGameSettings(KeyValues *pKV)
|
||||
{
|
||||
int new_value = ((ConVar*)var)->GetInt();
|
||||
int old_value = atoi(pOldValue);
|
||||
if(unreserved_ptr == NULL ) {
|
||||
Msg("unreserved_ptr init error\n");
|
||||
if (!pKV) {
|
||||
return;
|
||||
}
|
||||
if(new_value != old_value) {
|
||||
if(new_value == 1) {
|
||||
write_signature(unreserved_ptr, unreserved_new);
|
||||
engine->ServerCommand("sv_allow_lobby_connect_only 0\n");
|
||||
} else {
|
||||
write_signature(unreserved_ptr, unreserved_org);
|
||||
}
|
||||
g_nGameSlots = sv_maxplayers.GetInt();
|
||||
if (g_nGameSlots == -1) {
|
||||
return;
|
||||
}
|
||||
pKV->SetInt("members/numSlots", g_nGameSlots);
|
||||
}
|
||||
|
||||
void Hook_ReplyReservationRequest(netadr_t& adr, bf_read& inmsg)
|
||||
{
|
||||
if (sv_force_unreserved.GetInt()) {
|
||||
if (g_pGameIServer != NULL) {
|
||||
if (g_pGameIServer->m_nReservationCookie != 0)
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
int Hook_GetMaxHumanPlayers()
|
||||
{
|
||||
if (g_nGameSlots > 0) {
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, g_nGameSlots);
|
||||
}
|
||||
RETURN_META_VALUE(MRES_IGNORED, g_nGameSlots);
|
||||
}
|
||||
|
||||
PLUGIN_EXPOSE(l4dtoolz, g_l4dtoolz);
|
||||
@@ -113,134 +98,112 @@ bool l4dtoolz::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
GET_V_IFACE_CURRENT(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
GET_V_IFACE_CURRENT(GetServerFactory, gameclients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_pMatchFramework, IMatchFramework, IMATCHFRAMEWORK_VERSION_STRING);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
|
||||
|
||||
ConVar_Register(0, this);
|
||||
|
||||
struct base_addr_t base_addr;
|
||||
base_addr.addr = NULL;
|
||||
base_addr.len = 0;
|
||||
|
||||
find_base_from_list(matchmaking_dll, &base_addr);
|
||||
|
||||
if(!lobby_match_ptr) {
|
||||
lobby_match_ptr = find_signature(lobby_match, &base_addr, 1);
|
||||
get_original_signature(lobby_match_ptr, lobby_match_new, lobby_match_org);
|
||||
}
|
||||
|
||||
find_base_from_list(engine_dll, &base_addr);
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
if(!max_players_friend_lobby) {
|
||||
max_players_friend_lobby = find_signature(friends_lobby, &base_addr, 0);
|
||||
get_original_signature(max_players_friend_lobby, friends_lobby_new, friends_lobby_org);
|
||||
}
|
||||
#endif
|
||||
if(!max_players_connect) {
|
||||
max_players_connect = find_signature(max_players, &base_addr, 0);
|
||||
get_original_signature(max_players_connect, max_players_new, max_players_org);
|
||||
}
|
||||
if(!lobby_sux_ptr) {
|
||||
#ifdef WIN32
|
||||
lobby_sux_ptr = max_players_connect;
|
||||
void* handle = NULL;
|
||||
#if SH_SYS == SH_SYS_WIN32
|
||||
if (!(handle=SH_GET_ORIG_VFNPTR_ENTRY(engine, &IVEngineServer::CreateFakeClient))) {
|
||||
Warning("Failed to get address 'IVEngineServer::CreateFakeClient'\n");
|
||||
} else {
|
||||
g_pGameIServer = *reinterpret_cast<CBaseServer **>(reinterpret_cast<unsigned char *>(handle)+sv_offs);
|
||||
#else
|
||||
lobby_sux_ptr = find_signature(lobby_sux, &base_addr, 0);
|
||||
if (!(handle=dlopen(engine_dll, RTLD_LAZY))) {
|
||||
Warning("Could't open library '%s'\n", engine_dll);
|
||||
} else {
|
||||
g_pGameIServer = (CBaseServer *)g_MemUtils.ResolveSymbol(handle, "sv");
|
||||
dlclose(handle);
|
||||
#endif
|
||||
get_original_signature(lobby_sux_ptr, lobby_sux_new, lobby_sux_org);
|
||||
}
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
#ifdef WIN32
|
||||
if(!max_players_server_browser) {
|
||||
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
|
||||
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
if(!tmp_player) {
|
||||
tmp_player = find_signature(players, &base_addr, 0);
|
||||
if(tmp_player) {
|
||||
get_original_signature(tmp_player, players_new, players_org);
|
||||
write_signature(tmp_player, players_new);
|
||||
const char *pszCmdLineMax;
|
||||
if(CommandLine()->CheckParm("-maxplayers", &pszCmdLineMax) || CommandLine()->CheckParm("+maxplayers", &pszCmdLineMax)) {
|
||||
char command[32];
|
||||
UTIL_Format(command, sizeof(command), "maxplayers %d\n", clamp(atoi(pszCmdLineMax), 1, 32));
|
||||
engine->ServerCommand(command);
|
||||
} else {
|
||||
engine->ServerCommand("maxplayers 31\n");
|
||||
}
|
||||
engine->ServerExecute();
|
||||
write_signature(tmp_player, players_org);
|
||||
free(players_org);
|
||||
players_org = NULL;
|
||||
const char *pszCmdLineMax;
|
||||
if (CommandLine()->CheckParm("-maxplayers", &pszCmdLineMax)) {
|
||||
g_pGameIServer->m_nMaxclients = clamp(atoi(pszCmdLineMax), 1, 32);
|
||||
} else {
|
||||
g_pGameIServer->m_nMaxclients = 31;
|
||||
}
|
||||
}
|
||||
if(!unreserved_ptr) {
|
||||
unreserved_ptr = find_signature(unreserved, &base_addr, 0);
|
||||
get_original_signature(unreserved_ptr, unreserved_new, unreserved_org);
|
||||
|
||||
SH_ADD_HOOK(IServerGameDLL, ApplyGameSettings, gamedll, SH_STATIC(Hook_ApplyGameSettings), true);
|
||||
SH_ADD_HOOK(IMatchTitle, GetTotalNumPlayersSupported, g_pMatchFramework->GetMatchTitle(), SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &l4dtoolz::LevelInit, true);
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &l4dtoolz::LevelShutdown, false);
|
||||
|
||||
if (g_pGameIServer) {
|
||||
SH_ADD_HOOK(CBaseServer, ReplyReservationRequest, g_pGameIServer, SH_STATIC(Hook_ReplyReservationRequest), false);
|
||||
} else {
|
||||
Warning("g_pGameIServer pointer is not available\n");
|
||||
}
|
||||
|
||||
find_base_from_list(server_dll, &base_addr);
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
if(!chuman_limit) {
|
||||
chuman_limit = find_signature(human_limit, &base_addr, 0);
|
||||
get_original_signature(chuman_limit, human_limit_new, human_limit_org);
|
||||
}
|
||||
#ifndef WIN32
|
||||
if(!max_players_server_browser) {
|
||||
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
|
||||
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if(!max_players_server_browser) {
|
||||
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
|
||||
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
|
||||
}
|
||||
#endif
|
||||
ConVar_Register(0, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool l4dtoolz::Unload(char *error, size_t maxlen)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
write_signature(max_players_friend_lobby, friends_lobby_org);
|
||||
write_signature(chuman_limit, human_limit_org);
|
||||
free(friends_lobby_org);
|
||||
free(human_limit_org);
|
||||
#endif
|
||||
SH_REMOVE_HOOK(IServerGameDLL, ApplyGameSettings, gamedll, SH_STATIC(Hook_ApplyGameSettings), true);
|
||||
SH_REMOVE_HOOK(IMatchTitle, GetTotalNumPlayersSupported, g_pMatchFramework->GetMatchTitle(), SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &l4dtoolz::LevelInit, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &l4dtoolz::LevelShutdown, false);
|
||||
|
||||
write_signature(max_players_connect, max_players_org);
|
||||
write_signature(lobby_sux_ptr, lobby_sux_org);
|
||||
write_signature(max_players_server_browser, server_bplayers_org);
|
||||
write_signature(unreserved_ptr, unreserved_org);
|
||||
write_signature(lobby_match_ptr, lobby_match_org);
|
||||
if (g_pGameIServer) {
|
||||
SH_REMOVE_HOOK(CBaseServer, ReplyReservationRequest, g_pGameIServer, SH_STATIC(Hook_ReplyReservationRequest), false);
|
||||
}
|
||||
|
||||
free(max_players_org);
|
||||
free(lobby_sux_org);
|
||||
free(server_bplayers_org);
|
||||
free(unreserved_org);
|
||||
free(lobby_match_org);
|
||||
LevelShutdown();
|
||||
ConVar_Unregister();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||
bool l4dtoolz::LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
|
||||
{
|
||||
va_list ap;
|
||||
g_pGameRules = nullptr;
|
||||
|
||||
va_start(ap, fmt);
|
||||
size_t len = vsnprintf(buffer, maxlength, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len >= maxlength)
|
||||
{
|
||||
len = maxlength - 1;
|
||||
buffer[len] = '\0';
|
||||
ServerClass *pServerClass = UTIL_FindServerClass("CTerrorGameRulesProxy");
|
||||
if (pServerClass) {
|
||||
int i, iCount;
|
||||
iCount = pServerClass->m_pTable->GetNumProps();
|
||||
for (i = 0; i < iCount; i++) {
|
||||
if (stricmp(pServerClass->m_pTable->GetProp(i)->GetName(), "terror_gamerules_data") == 0) {
|
||||
g_pGameRules = (*pServerClass->m_pTable->GetProp(i)->GetDataTableProxyFn())(NULL, NULL, NULL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
if (g_pGameRules) {
|
||||
SH_ADD_MANUALHOOK(CTerrorGameRules_GetMaxHumanPlayers, g_pGameRules, SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||
} else {
|
||||
Warning("g_pGameRules pointer is not available\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void l4dtoolz::LevelShutdown()
|
||||
{
|
||||
if (g_pGameRules) {
|
||||
SH_REMOVE_MANUALHOOK(CTerrorGameRules_GetMaxHumanPlayers, g_pGameRules, SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||
g_pGameRules = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ServerClass *UTIL_FindServerClass(const char *classname)
|
||||
{
|
||||
ServerClass *sc = gamedll->GetAllServerClasses();
|
||||
while (sc)
|
||||
{
|
||||
if (strcmp(classname, sc->GetName()) == 0)
|
||||
{
|
||||
return sc;
|
||||
}
|
||||
sc = sc->m_pNext;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *l4dtoolz::GetLicense()
|
||||
@@ -250,7 +213,7 @@ const char *l4dtoolz::GetLicense()
|
||||
|
||||
const char *l4dtoolz::GetVersion()
|
||||
{
|
||||
return "1.1.0.2";
|
||||
return "2.2.0";
|
||||
}
|
||||
|
||||
const char *l4dtoolz::GetDate()
|
||||
|
||||
+3
-15
@@ -8,6 +8,8 @@ class l4dtoolz : public ISmmPlugin, public IConCommandBaseAccessor
|
||||
public:
|
||||
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||
bool Unload(char *error, size_t maxlen);
|
||||
bool LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||
void LevelShutdown();
|
||||
public:
|
||||
const char *GetAuthor();
|
||||
const char *GetName();
|
||||
@@ -20,25 +22,11 @@ public:
|
||||
public: //IConCommandBaseAccessor
|
||||
bool RegisterConCommandBase(ConCommandBase *pVar);
|
||||
public:
|
||||
|
||||
static void OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue );
|
||||
static void OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue );
|
||||
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
static void OnChangeRemovehumanlimit ( IConVar *var, const char *pOldValue, float flOldValue );
|
||||
static void* max_players_friend_lobby;
|
||||
static void* chuman_limit;
|
||||
#endif
|
||||
|
||||
static void* max_players_connect;
|
||||
static void* max_players_server_browser;
|
||||
static void* lobby_sux_ptr;
|
||||
static void* tmp_player;
|
||||
static void* unreserved_ptr;
|
||||
static void* lobby_match_ptr;
|
||||
};
|
||||
|
||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
||||
ServerClass *UTIL_FindServerClass(const char *classname);
|
||||
|
||||
extern l4dtoolz g_l4dtoolz;
|
||||
|
||||
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* MemoryUtils
|
||||
* Copyright (C) 2004-2011 AlliedModders LLC., 2011 Prodigysim
|
||||
* 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, the authors give 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>.
|
||||
*/
|
||||
|
||||
#include "memutils.h"
|
||||
#include <string.h>
|
||||
|
||||
#if SH_SYS == SH_SYS_LINUX
|
||||
#include <fcntl.h>
|
||||
#include <link.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||
#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
|
||||
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
||||
#endif
|
||||
|
||||
#if SH_SYS == SH_SYS_APPLE
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
|
||||
/* Define things from 10.6 SDK for older SDKs */
|
||||
#ifndef MAC_OS_X_VERSION_10_6
|
||||
struct task_dyld_info
|
||||
{
|
||||
mach_vm_address_t all_image_info_addr;
|
||||
mach_vm_size_t all_image_info_size;
|
||||
};
|
||||
typedef struct task_dyld_info task_dyld_info_data_t;
|
||||
#define TASK_DYLD_INFO 17
|
||||
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
|
||||
#endif // MAC_OS_X_VERSION_10_6
|
||||
#endif // SH_SYS_APPLE
|
||||
|
||||
MemoryUtils g_MemUtils;
|
||||
|
||||
MemoryUtils::MemoryUtils()
|
||||
{
|
||||
#if SH_SYS == SH_SYS_APPLE
|
||||
|
||||
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
|
||||
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
|
||||
|
||||
/* Get pointer to struct that describes all loaded mach-o images in process */
|
||||
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
|
||||
{
|
||||
task_dyld_info_data_t dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
|
||||
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct nlist list[2];
|
||||
memset(list, 0, sizeof(list));
|
||||
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
|
||||
nlist("/usr/lib/dyld", list);
|
||||
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
MemoryUtils::~MemoryUtils()
|
||||
{
|
||||
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||
{
|
||||
delete m_SymTables[i];
|
||||
}
|
||||
m_SymTables.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
{
|
||||
#if SH_SYS == SH_SYS_WIN32
|
||||
|
||||
return GetProcAddress((HMODULE)handle, symbol);
|
||||
|
||||
#elif SH_SYS == SH_SYS_LINUX
|
||||
|
||||
struct link_map *dlmap;
|
||||
struct stat dlstat;
|
||||
int dlfile;
|
||||
uintptr_t map_base;
|
||||
Elf32_Ehdr *file_hdr;
|
||||
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
|
||||
Elf32_Sym *symtab;
|
||||
const char *shstrtab, *strtab;
|
||||
uint16_t section_count;
|
||||
uint32_t symbol_count;
|
||||
LibSymbolTable *libtable;
|
||||
SymbolTable *table;
|
||||
Symbol *symbol_entry;
|
||||
|
||||
dlmap = (struct link_map *)handle;
|
||||
symtab_hdr = NULL;
|
||||
strtab_hdr = NULL;
|
||||
table = NULL;
|
||||
|
||||
/* See if we already have a symbol table for this library */
|
||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||
{
|
||||
libtable = m_SymTables[i];
|
||||
if (libtable->lib_base == dlmap->l_addr)
|
||||
{
|
||||
table = &libtable->table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we don't have a symbol table for this library, then create one */
|
||||
if (table == NULL)
|
||||
{
|
||||
libtable = new LibSymbolTable();
|
||||
libtable->table.Initialize();
|
||||
libtable->lib_base = dlmap->l_addr;
|
||||
libtable->last_pos = 0;
|
||||
table = &libtable->table;
|
||||
m_SymTables.push_back(libtable);
|
||||
}
|
||||
|
||||
/* See if the symbol is already cached in our table */
|
||||
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||
if (symbol_entry != NULL)
|
||||
{
|
||||
return symbol_entry->address;
|
||||
}
|
||||
|
||||
/* If symbol isn't in our table, then we have open the actual library */
|
||||
dlfile = open(dlmap->l_name, O_RDONLY);
|
||||
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
|
||||
{
|
||||
close(dlfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Map library file into memory */
|
||||
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
|
||||
map_base = (uintptr_t)file_hdr;
|
||||
if (file_hdr == MAP_FAILED)
|
||||
{
|
||||
close(dlfile);
|
||||
return NULL;
|
||||
}
|
||||
close(dlfile);
|
||||
|
||||
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
|
||||
{
|
||||
munmap(file_hdr, dlstat.st_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
|
||||
section_count = file_hdr->e_shnum;
|
||||
/* Get ELF section header string table */
|
||||
shstrtab_hdr = §ions[file_hdr->e_shstrndx];
|
||||
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
|
||||
|
||||
/* Iterate sections while looking for ELF symbol table and string table */
|
||||
for (uint16_t i = 0; i < section_count; i++)
|
||||
{
|
||||
Elf32_Shdr &hdr = sections[i];
|
||||
const char *section_name = shstrtab + hdr.sh_name;
|
||||
|
||||
if (strcmp(section_name, ".symtab") == 0)
|
||||
{
|
||||
symtab_hdr = &hdr;
|
||||
}
|
||||
else if (strcmp(section_name, ".strtab") == 0)
|
||||
{
|
||||
strtab_hdr = &hdr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Uh oh, we don't have a symbol table or a string table */
|
||||
if (symtab_hdr == NULL || strtab_hdr == NULL)
|
||||
{
|
||||
munmap(file_hdr, dlstat.st_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
|
||||
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
|
||||
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
||||
|
||||
/* Iterate symbol table starting from the position we were at last time */
|
||||
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||
{
|
||||
Elf32_Sym &sym = symtab[i];
|
||||
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
|
||||
const char *sym_name = strtab + sym.st_name;
|
||||
Symbol *cur_sym;
|
||||
|
||||
/* Skip symbols that are undefined or do not refer to functions or objects */
|
||||
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Caching symbols as we go along */
|
||||
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
|
||||
if (strcmp(symbol, sym_name) == 0)
|
||||
{
|
||||
symbol_entry = cur_sym;
|
||||
libtable->last_pos = ++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
munmap(file_hdr, dlstat.st_size);
|
||||
return symbol_entry ? symbol_entry->address : NULL;
|
||||
|
||||
#elif SH_SYS == SH_SYS_APPLE
|
||||
|
||||
uintptr_t dlbase, linkedit_addr;
|
||||
uint32_t image_count;
|
||||
struct mach_header *file_hdr;
|
||||
struct load_command *loadcmds;
|
||||
struct segment_command *linkedit_hdr;
|
||||
struct symtab_command *symtab_hdr;
|
||||
struct nlist *symtab;
|
||||
const char *strtab;
|
||||
uint32_t loadcmd_count;
|
||||
uint32_t symbol_count;
|
||||
LibSymbolTable *libtable;
|
||||
SymbolTable *table;
|
||||
Symbol *symbol_entry;
|
||||
|
||||
dlbase = 0;
|
||||
image_count = m_ImageList->infoArrayCount;
|
||||
linkedit_hdr = NULL;
|
||||
symtab_hdr = NULL;
|
||||
table = NULL;
|
||||
|
||||
/* Loop through mach-o images in process.
|
||||
* We can skip index 0 since that is just the executable.
|
||||
*/
|
||||
for (uint32_t i = 1; i < image_count; i++)
|
||||
{
|
||||
const struct dyld_image_info &info = m_ImageList->infoArray[i];
|
||||
|
||||
/* "Load" each one until we get a matching handle */
|
||||
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
|
||||
if (h == handle)
|
||||
{
|
||||
dlbase = (uintptr_t)info.imageLoadAddress;
|
||||
dlclose(h);
|
||||
break;
|
||||
}
|
||||
|
||||
dlclose(h);
|
||||
}
|
||||
|
||||
if (!dlbase)
|
||||
{
|
||||
/* Uh oh, we couldn't find a matching handle */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* See if we already have a symbol table for this library */
|
||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||
{
|
||||
libtable = m_SymTables[i];
|
||||
if (libtable->lib_base == dlbase)
|
||||
{
|
||||
table = &libtable->table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we don't have a symbol table for this library, then create one */
|
||||
if (table == NULL)
|
||||
{
|
||||
libtable = new LibSymbolTable();
|
||||
libtable->table.Initialize();
|
||||
libtable->lib_base = dlbase;
|
||||
libtable->last_pos = 0;
|
||||
table = &libtable->table;
|
||||
m_SymTables.push_back(libtable);
|
||||
}
|
||||
|
||||
/* See if the symbol is already cached in our table */
|
||||
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||
if (symbol_entry != NULL)
|
||||
{
|
||||
return symbol_entry->address;
|
||||
}
|
||||
|
||||
/* If symbol isn't in our table, then we have to locate it in memory */
|
||||
|
||||
file_hdr = (struct mach_header *)dlbase;
|
||||
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
|
||||
loadcmd_count = file_hdr->ncmds;
|
||||
|
||||
/* Loop through load commands until we find the ones for the symbol table */
|
||||
for (uint32_t i = 0; i < loadcmd_count; i++)
|
||||
{
|
||||
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
|
||||
{
|
||||
struct segment_command *seg = (struct segment_command *)loadcmds;
|
||||
if (strcmp(seg->segname, "__LINKEDIT") == 0)
|
||||
{
|
||||
linkedit_hdr = seg;
|
||||
if (symtab_hdr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (loadcmds->cmd == LC_SYMTAB)
|
||||
{
|
||||
symtab_hdr = (struct symtab_command *)loadcmds;
|
||||
if (linkedit_hdr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load commands are not of a fixed size which is why we add the size */
|
||||
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
|
||||
}
|
||||
|
||||
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
|
||||
{
|
||||
/* Uh oh, no symbol table */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
|
||||
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
|
||||
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
|
||||
symbol_count = symtab_hdr->nsyms;
|
||||
|
||||
/* Iterate symbol table starting from the position we were at last time */
|
||||
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||
{
|
||||
struct nlist &sym = symtab[i];
|
||||
/* Ignore the prepended underscore on all symbols, so +1 here */
|
||||
const char *sym_name = strtab + sym.n_un.n_strx + 1;
|
||||
Symbol *cur_sym;
|
||||
|
||||
/* Skip symbols that are undefined */
|
||||
if (sym.n_sect == NO_SECT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Caching symbols as we go along */
|
||||
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
|
||||
if (strcmp(symbol, sym_name) == 0)
|
||||
{
|
||||
symbol_entry = cur_sym;
|
||||
libtable->last_pos = ++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return symbol_entry ? symbol_entry->address : NULL;
|
||||
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* MemoryUtils
|
||||
* Copyright (C) 2004-2011 AlliedModders LLC., 2011 ProdigySim
|
||||
* 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, the authors give you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sourcehook.h"
|
||||
#include "sh_memory.h"
|
||||
|
||||
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||
#include <sh_vector.h>
|
||||
#include "sm_symtable.h"
|
||||
using SourceHook::CVector;
|
||||
#endif
|
||||
|
||||
#if SH_SYS == SH_SYS_APPLE
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||
struct LibSymbolTable
|
||||
{
|
||||
SymbolTable table;
|
||||
uintptr_t lib_base;
|
||||
uint32_t last_pos;
|
||||
};
|
||||
#endif
|
||||
|
||||
class MemoryUtils
|
||||
{
|
||||
public:
|
||||
MemoryUtils();
|
||||
~MemoryUtils();
|
||||
void *ResolveSymbol(void *handle, const char *symbol);
|
||||
|
||||
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||
private:
|
||||
CVector<LibSymbolTable *> m_SymTables;
|
||||
#if SH_SYS == SH_SYS_APPLE
|
||||
struct dyld_all_image_infos *m_ImageList;
|
||||
SInt32 m_OSXMajor;
|
||||
SInt32 m_OSXMinor;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
extern MemoryUtils g_MemUtils;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||
-243
@@ -1,243 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "signature.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <TlHelp32.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#define SIGN_HEADER_LEN 2
|
||||
#define SIGN_LEN_BYTE 0
|
||||
#define SIGN_OFFSET_BYTE 1
|
||||
|
||||
|
||||
static int lock_region(const void *addr, unsigned int sign_len, unsigned int sign_off, int lock)
|
||||
{
|
||||
#ifndef WIN32
|
||||
unsigned int all_adr;
|
||||
unsigned int all_size;
|
||||
unsigned int p_size;
|
||||
unsigned int u_addr;
|
||||
|
||||
p_size = sysconf(_SC_PAGESIZE);
|
||||
u_addr = (unsigned int)addr;
|
||||
|
||||
all_adr = (u_addr + sign_off) & ~(p_size-1);
|
||||
all_size = u_addr - all_adr + sign_len;
|
||||
|
||||
if(lock) {
|
||||
mlock((void *)all_adr, all_size);
|
||||
mprotect((void *)all_adr, all_size, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
} else
|
||||
munlock((void *)all_adr, all_size);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *find_signature(const char* mask, struct base_addr_t *base_addr, int pure)
|
||||
{
|
||||
char *pBasePtr = (char *)base_addr->addr;
|
||||
char *pEndPtr = pBasePtr+base_addr->len-(int)mask[SIGN_LEN_BYTE];
|
||||
int i;
|
||||
char* tmp;
|
||||
if(base_addr->addr == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifndef WIN32
|
||||
unsigned int p_size = sysconf(_SC_PAGESIZE);
|
||||
char* all_adr = (char*)((unsigned int)pBasePtr & ~(p_size-1));
|
||||
unsigned int size = pEndPtr - all_adr;
|
||||
mlock(all_adr, size);
|
||||
#endif
|
||||
|
||||
while(pBasePtr < pEndPtr)
|
||||
{
|
||||
tmp = pBasePtr;
|
||||
|
||||
for(i = 1; i <= mask[SIGN_LEN_BYTE]; ++i) {
|
||||
if(!pure && mask[i] == '\xC3'){
|
||||
tmp++;
|
||||
continue;
|
||||
}
|
||||
if(mask[i] != *tmp ) {
|
||||
break;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
if(i-1 == mask[0]) {
|
||||
#ifndef WIN32
|
||||
munlock(all_adr, size);
|
||||
#endif
|
||||
return pBasePtr;
|
||||
}
|
||||
|
||||
pBasePtr++;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
munlock(all_adr, size);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
struct v_data{
|
||||
const char *fname;
|
||||
void *baddr;
|
||||
unsigned int blen;
|
||||
};
|
||||
|
||||
static int callback(struct dl_phdr_info *info, size_t size, void *data)
|
||||
{
|
||||
int i;
|
||||
const char* filename;
|
||||
|
||||
if (!info->dlpi_name || !info->dlpi_name[0])
|
||||
return 0;
|
||||
|
||||
filename = ((struct v_data *)data)->fname;
|
||||
|
||||
if(strstr(info->dlpi_name, filename)) {
|
||||
if(strstr( info->dlpi_name, "metamod") == NULL) {
|
||||
((struct v_data *)data)->baddr = (void*)info->dlpi_addr;
|
||||
((struct v_data *)data)->blen = 0;
|
||||
for(i = 0; i < info->dlpi_phnum; ++i) {
|
||||
((struct v_data *)data)->blen+=info->dlpi_phdr[i].p_filesz;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int find_base(const char* name, struct base_addr_t *base_addr)
|
||||
{
|
||||
#ifdef WIN32
|
||||
MODULEENTRY32 modent;
|
||||
HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
|
||||
if(hModuleSnap == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
modent.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
if(!Module32Next(hModuleSnap, &modent)){
|
||||
CloseHandle(hModuleSnap);
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
if(strstr( modent.szExePath, name)) {
|
||||
if(strstr( modent.szExePath, "metamod"))
|
||||
continue;
|
||||
base_addr->addr = modent.modBaseAddr;
|
||||
base_addr->len = modent.modBaseSize;
|
||||
CloseHandle(hModuleSnap);
|
||||
return 1;
|
||||
}
|
||||
} while(Module32Next(hModuleSnap, &modent));
|
||||
CloseHandle(hModuleSnap);
|
||||
#else
|
||||
struct v_data vdata;
|
||||
vdata.fname = name;
|
||||
if(dl_iterate_phdr(callback, &vdata)){
|
||||
base_addr->addr = vdata.baddr;
|
||||
base_addr->len = vdata.blen;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
base_addr->addr = NULL;
|
||||
base_addr->len = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int find_base_from_list(const char *name[], struct base_addr_t *base_addr)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
base_addr->addr = NULL;
|
||||
base_addr->len = 0;
|
||||
|
||||
if (name == NULL)
|
||||
return 0;
|
||||
|
||||
while (name[i] != NULL && !(ret = find_base(name[i], base_addr)))
|
||||
i++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_signature(const void* addr, const void* signature)
|
||||
{
|
||||
if(!addr)
|
||||
return 0;
|
||||
|
||||
unsigned int u_addr_sign;
|
||||
unsigned int sign_len;
|
||||
unsigned int sign_off;
|
||||
unsigned int u_addr;
|
||||
|
||||
sign_len = ((unsigned char *)signature)[SIGN_LEN_BYTE];
|
||||
sign_off = ((unsigned char *)signature)[SIGN_OFFSET_BYTE];
|
||||
u_addr = (unsigned int)addr;
|
||||
u_addr_sign = (unsigned int)signature;
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
||||
WriteProcessMemory(h_process, (void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len, NULL);
|
||||
CloseHandle(h_process);
|
||||
#else
|
||||
lock_region(addr, sign_len, sign_off, 1);
|
||||
memcpy((void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len);
|
||||
lock_region(addr, sign_len, sign_off, 0);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_signature(const void *addr, void *signature)
|
||||
{
|
||||
unsigned int u_addr_sign;
|
||||
unsigned int sign_len;
|
||||
unsigned int sign_off;
|
||||
unsigned int u_addr;
|
||||
|
||||
sign_len = ((unsigned char *)signature)[SIGN_LEN_BYTE];
|
||||
sign_off = ((unsigned char *)signature)[SIGN_OFFSET_BYTE];
|
||||
u_addr = (unsigned int)addr;
|
||||
u_addr_sign = (unsigned int)signature;
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
||||
ReadProcessMemory(h_process, (void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len, NULL);
|
||||
CloseHandle(h_process);
|
||||
#else
|
||||
lock_region(addr, sign_len, sign_off, 1);
|
||||
memcpy((void *)(u_addr_sign+SIGN_HEADER_LEN), (void *)(u_addr+sign_off), sign_len);
|
||||
lock_region(addr, sign_len, sign_off, 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_original_signature(const void *offset, const void *new_sig, void *&org_sig)
|
||||
{
|
||||
unsigned int sign_len;
|
||||
|
||||
if(!offset)
|
||||
return 0;
|
||||
|
||||
sign_len = ((unsigned char *)new_sig)[SIGN_LEN_BYTE];
|
||||
org_sig = malloc(sign_len + SIGN_HEADER_LEN);
|
||||
memcpy(org_sig, new_sig, SIGN_HEADER_LEN);
|
||||
return read_signature(offset, org_sig);
|
||||
}
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
#ifndef _INCLUDE_SIGNATURE_
|
||||
#define _INCLUDE_SIGNATURE_
|
||||
|
||||
struct base_addr_t{
|
||||
void *addr;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
void *find_signature(const char *mask, struct base_addr_t *base_addr, int pure);
|
||||
int find_base(const char *name, struct base_addr_t *base_addr);
|
||||
int find_base_from_list(const char *name[], struct base_addr_t *base_addr);
|
||||
int write_signature(const void *addr, const void *signature);
|
||||
int read_signature(const void *addr, void *signature);
|
||||
int get_original_signature(const void *offset, const void *new_sig, void *&org_sig);
|
||||
|
||||
#endif //_INCLUDE_SIGNATURE_
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 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>.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||
#define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define KESTRING_TABLE_START_SIZE 65536
|
||||
|
||||
struct Symbol
|
||||
{
|
||||
size_t length;
|
||||
uint32_t hash;
|
||||
void *address;
|
||||
Symbol *tbl_next;
|
||||
|
||||
inline char *buffer()
|
||||
{
|
||||
return reinterpret_cast<char *>(this + 1);
|
||||
}
|
||||
};
|
||||
|
||||
class SymbolTable
|
||||
{
|
||||
public:
|
||||
~SymbolTable()
|
||||
{
|
||||
for (uint32_t i = 0; i < nbuckets; i++)
|
||||
{
|
||||
Symbol *sym = buckets[i];
|
||||
while (sym != NULL)
|
||||
{
|
||||
Symbol *next = sym->tbl_next;
|
||||
free(sym);
|
||||
sym = next;
|
||||
}
|
||||
}
|
||||
free(buckets);
|
||||
}
|
||||
|
||||
bool Initialize()
|
||||
{
|
||||
buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
|
||||
if (buckets == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
|
||||
|
||||
nbuckets = KESTRING_TABLE_START_SIZE;
|
||||
nused = 0;
|
||||
bucketmask = KESTRING_TABLE_START_SIZE - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint32_t HashString(const char *data, size_t len)
|
||||
{
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2 * sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
|
||||
#undef get16bits
|
||||
}
|
||||
|
||||
Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
|
||||
{
|
||||
uint32_t bucket = hash & bucketmask;
|
||||
Symbol **pkvs = &buckets[bucket];
|
||||
|
||||
Symbol *kvs = *pkvs;
|
||||
while (kvs != NULL)
|
||||
{
|
||||
if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
|
||||
{
|
||||
return pkvs;
|
||||
}
|
||||
pkvs = &kvs->tbl_next;
|
||||
kvs = *pkvs;
|
||||
}
|
||||
|
||||
return pkvs;
|
||||
}
|
||||
|
||||
void ResizeSymbolTable()
|
||||
{
|
||||
uint32_t xnbuckets = nbuckets * 2;
|
||||
Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
|
||||
if (xbuckets == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
|
||||
uint32_t xbucketmask = xnbuckets - 1;
|
||||
for (uint32_t i = 0; i < nbuckets; i++)
|
||||
{
|
||||
Symbol *sym = buckets[i];
|
||||
while (sym != NULL)
|
||||
{
|
||||
Symbol *next = sym->tbl_next;
|
||||
uint32_t bucket = sym->hash & xbucketmask;
|
||||
sym->tbl_next = xbuckets[bucket];
|
||||
xbuckets[bucket] = sym;
|
||||
sym = next;
|
||||
}
|
||||
}
|
||||
free(buckets);
|
||||
buckets = xbuckets;
|
||||
nbuckets = xnbuckets;
|
||||
bucketmask = xbucketmask;
|
||||
}
|
||||
|
||||
Symbol *FindSymbol(const char *str, size_t len)
|
||||
{
|
||||
uint32_t hash = HashString(str, len);
|
||||
Symbol **pkvs = FindSymbolBucket(str, len, hash);
|
||||
return *pkvs;
|
||||
}
|
||||
|
||||
Symbol *InternSymbol(const char* str, size_t len, void *address)
|
||||
{
|
||||
uint32_t hash = HashString(str, len);
|
||||
Symbol **pkvs = FindSymbolBucket(str, len, hash);
|
||||
if (*pkvs != NULL)
|
||||
{
|
||||
return *pkvs;
|
||||
}
|
||||
|
||||
Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
|
||||
kvs->length = len;
|
||||
kvs->hash = hash;
|
||||
kvs->address = address;
|
||||
kvs->tbl_next = NULL;
|
||||
memcpy(kvs + 1, str, sizeof(char) * (len + 1));
|
||||
*pkvs = kvs;
|
||||
nused++;
|
||||
|
||||
if (nused > nbuckets && nbuckets <= INT_MAX / 2)
|
||||
{
|
||||
ResizeSymbolTable();
|
||||
}
|
||||
|
||||
return kvs;
|
||||
}
|
||||
private:
|
||||
uint32_t nbuckets;
|
||||
uint32_t nused;
|
||||
uint32_t bucketmask;
|
||||
Symbol **buckets;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||
Reference in New Issue
Block a user