Modernize build/CI, support SourceMod 1.13, deprecate ForceHeartbeat
Rework the build and CI: swap to SourceMod's safetyhook-based CDetour and drop the vendored CDetour/asm sources, the old Makefile, Travis config, and buildbot perl scripts. Add GitHub Actions building and releasing x86 and x86_64 against SM 1.12 and 1.13, plus dependabot. Split the Windows and Linux packages and tidy naming. Gate IPluginManager::FindPluginByContext on the extension API version so the extension builds against both SM 1.12 (API 8) and 1.13 (API 9), and shim DETOUR_CREATE_STATIC_FIXED over the address overload safetyhook exposes. Deprecate SteamWorks_ForceHeartbeat: newer Steamworks SDKs removed ISteamGameServer::ForceHeartbeat, so make the native a no-op and mark it deprecated in the include.
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
name: SteamWorks.ext Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master, windows98 ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master, windows98 ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
python-version: [2.7, 3.3, 3.8]
|
|
||||||
os: [ubuntu-18.04, macos-latest, windows-2019]
|
|
||||||
exclude:
|
|
||||||
- os: macos-latest
|
|
||||||
python-version: 3.3
|
|
||||||
- os: windows-2019
|
|
||||||
python-version: 3.3
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
- name: Install Deps
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
sudo dpkg --add-architecture i386
|
|
||||||
sudo apt-get install lib32stdc++-7-dev lib32z1-dev libc6-dev-i386
|
|
||||||
sudo apt-get install g++-multilib
|
|
||||||
- name: install AMBuild
|
|
||||||
run: |
|
|
||||||
mkdir assets
|
|
||||||
cd assets
|
|
||||||
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b fix-deps https://github.com/alliedmodders/ambuild.git
|
|
||||||
pip install ./ambuild
|
|
||||||
- name: Clone Dependencies
|
|
||||||
run: |
|
|
||||||
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules https://[email protected]/SteamDatabase/SteamworksSDK.git SteamworksSDK
|
|
||||||
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b sdk2013 https://github.com/alliedmodders/hl2sdk.git hl2sdk-sdk2013
|
|
||||||
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b 1.10-dev https://github.com/alliedmodders/metamod-source.git mmsource-central
|
|
||||||
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b 1.7-dev https://github.com/alliedmodders/sourcemod.git sourcemod-central
|
|
||||||
- name: Run Build
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cp ../AMBuildScript ../../
|
|
||||||
python ../configure.py -s sdk2013 --hl2sdk-root ../assets --sm-path ../assets/sourcemod-central --mms-path ../assets/mmsource-central --steamworks-path ../assets/SteamworksSD
|
|
||||||
ambuild
|
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: sm${{ matrix.sm.label }}-${{ matrix.target.os_name }}-${{ matrix.target.arch }}
|
||||||
|
runs-on: ${{ matrix.target.os }}
|
||||||
|
container: ${{ matrix.target.container }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
sm:
|
||||||
|
- label: "1.12"
|
||||||
|
branch: "1.12-dev"
|
||||||
|
- label: "1.13"
|
||||||
|
branch: "master"
|
||||||
|
target:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
os_name: linux
|
||||||
|
arch: x86
|
||||||
|
container: ghcr.io/alliedmodders/build-containers/debian11-clang22:latest
|
||||||
|
- os: ubuntu-latest
|
||||||
|
os_name: linux
|
||||||
|
arch: x86_64
|
||||||
|
container: ghcr.io/alliedmodders/build-containers/debian11-clang22:latest
|
||||||
|
- os: windows-latest
|
||||||
|
os_name: windows
|
||||||
|
arch: x86
|
||||||
|
msvc_arch: x86
|
||||||
|
- os: windows-latest
|
||||||
|
os_name: windows
|
||||||
|
arch: x86_64
|
||||||
|
msvc_arch: amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Setup Python (Windows)
|
||||||
|
if: matrix.target.os_name == 'windows'
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.12'
|
||||||
|
|
||||||
|
- name: Setup MSVC (Windows)
|
||||||
|
if: matrix.target.os_name == 'windows'
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
with:
|
||||||
|
arch: ${{ matrix.target.msvc_arch }}
|
||||||
|
|
||||||
|
- name: Install AMBuild
|
||||||
|
if: matrix.target.os_name == 'windows'
|
||||||
|
shell: bash
|
||||||
|
run: python -m pip install --upgrade git+https://github.com/alliedmodders/ambuild.git
|
||||||
|
|
||||||
|
- name: Clone dependencies
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
|
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules https://github.com/rlabrecque/SteamworksSDK.git SteamworksSDK
|
||||||
|
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b 1.12-dev https://github.com/alliedmodders/metamod-source.git mmsource
|
||||||
|
git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b ${{ matrix.sm.branch }} https://github.com/alliedmodders/sourcemod.git sourcemod
|
||||||
|
|
||||||
|
- name: Build (Linux)
|
||||||
|
if: matrix.target.os_name == 'linux'
|
||||||
|
env:
|
||||||
|
CC: clang-22
|
||||||
|
CXX: clang++-22
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
python3 ../configure.py \
|
||||||
|
--sm-path ../sourcemod \
|
||||||
|
--mms-path ../mmsource \
|
||||||
|
--steamworks-path ../SteamworksSDK \
|
||||||
|
--target ${{ matrix.target.arch }} \
|
||||||
|
--enable-optimize
|
||||||
|
ambuild
|
||||||
|
|
||||||
|
- name: Build (Windows)
|
||||||
|
if: matrix.target.os_name == 'windows'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
python ../configure.py \
|
||||||
|
--sm-path ../sourcemod \
|
||||||
|
--mms-path ../mmsource \
|
||||||
|
--steamworks-path ../SteamworksSDK \
|
||||||
|
--target ${{ matrix.target.arch }} \
|
||||||
|
--enable-optimize
|
||||||
|
ambuild
|
||||||
|
|
||||||
|
- name: Upload package artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: pkg-sm${{ matrix.sm.label }}-${{ matrix.target.os_name }}-${{ matrix.target.arch }}
|
||||||
|
path: build/package/addons
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
needs: build
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Assemble packages
|
||||||
|
id: package
|
||||||
|
run: |
|
||||||
|
base_version=$(grep -oP 'SMEXT_CONF_VERSION\s+"\K[^"]+' Extension/sdk/smsdk_config.h)
|
||||||
|
build_number=$(git rev-list --count HEAD)
|
||||||
|
version="${base_version}-git${build_number}"
|
||||||
|
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# One package per SourceMod version per OS: Windows as .zip, Linux as
|
||||||
|
# .tar.gz. Each merges that combination's per-arch slices (the include
|
||||||
|
# file rides along in every slice).
|
||||||
|
assets=""
|
||||||
|
for label in 1.12 1.13; do
|
||||||
|
for os_name in windows linux; do
|
||||||
|
dest="package-sm${label}-${os_name}/addons"
|
||||||
|
mkdir -p "${dest}"
|
||||||
|
for dir in artifacts/pkg-sm${label}-${os_name}-*/; do
|
||||||
|
cp -a "${dir}." "${dest}/"
|
||||||
|
done
|
||||||
|
if [ "${os_name}" = "windows" ]; then
|
||||||
|
asset="SteamWorks-${version}-sm${label}-windows.zip"
|
||||||
|
(cd "package-sm${label}-${os_name}" && zip -r "../${asset}" addons)
|
||||||
|
else
|
||||||
|
asset="SteamWorks-${version}-sm${label}-linux.tar.gz"
|
||||||
|
tar -czf "${asset}" -C "package-sm${label}-${os_name}" addons
|
||||||
|
fi
|
||||||
|
assets="${assets} ${asset}"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
echo "assets=${assets# }" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
gh release create "v${{ steps.package.outputs.version }}" \
|
||||||
|
${{ steps.package.outputs.assets }} \
|
||||||
|
--target "${GITHUB_SHA}" \
|
||||||
|
--title "SteamWorks ${{ steps.package.outputs.version }}" \
|
||||||
|
--notes "Automated release built from ${GITHUB_SHA}."
|
||||||
@@ -26,3 +26,7 @@
|
|||||||
[Rr]elease - */
|
[Rr]elease - */
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Rr]elease/
|
[Rr]elease/
|
||||||
|
|
||||||
|
# ambuild output directories
|
||||||
|
/build/
|
||||||
|
/build-*/
|
||||||
-67
@@ -1,67 +0,0 @@
|
|||||||
git:
|
|
||||||
depth: 1
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- secure: "VsvGz6WqBVbT+RpnaWwYb16mVvQHQMvzfRxLlUEnYBVkKCWBgyECDXRL/ShBwGW+aMYW25ZPt/aJNk7rN/wvTrgGU2N9X6CrfVyGPp94HPSYPzEbZSXRoCGex30HkVVITYUBDd06CWuMMIOgS7At/XdJIR1ZjZpOr91Oze3YbGA="
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
include:
|
|
||||||
- os: linux
|
|
||||||
dist: trusty
|
|
||||||
language: cpp
|
|
||||||
compiler: gcc
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
|
||||||
packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
|
||||||
env:
|
|
||||||
- AMB="install --user"
|
|
||||||
- PATH="~/.local/bin:$PATH"
|
|
||||||
- RELEASE_PKG_FILE="package-lin.tgz"
|
|
||||||
# - os: windows
|
|
||||||
# language: cpp
|
|
||||||
# env:
|
|
||||||
# - AMB="install"
|
|
||||||
# - PATH="$PATH:/C/ProgramData/chocolatey/bin:/C/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/opt/bin"
|
|
||||||
# - RELEASE_PKG_FILE="package-win.tgz"
|
|
||||||
- os: mac
|
|
||||||
osx_image: xcode7.2
|
|
||||||
language: cpp
|
|
||||||
compiler: clang
|
|
||||||
env:
|
|
||||||
- AMB="install"
|
|
||||||
- PATH="~/.local/bin:$PATH"
|
|
||||||
- RELEASE_PKG_FILE="package-mac.tgz"
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- mkdir assets && cd assets
|
|
||||||
- git clone https://github.com/alliedmodders/ambuild.git
|
|
||||||
- cd ambuild
|
|
||||||
- python setup.py build
|
|
||||||
- python setup.py $AMB
|
|
||||||
- cd ..
|
|
||||||
- git clone --depth 1 --recurse-submodules -j8 --shallow-submodules https://[email protected]/SteamDatabase/SteamworksSDK.git SteamworksSDK
|
|
||||||
- git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b sdk2013 https://github.com/alliedmodders/hl2sdk.git hl2sdk-sdk2013
|
|
||||||
- git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b 1.10-dev https://github.com/alliedmodders/metamod-source.git mmsource-central
|
|
||||||
- git clone --depth 1 --recurse-submodules -j8 --shallow-submodules -b 1.7-dev https://github.com/alliedmodders/sourcemod.git sourcemod-central
|
|
||||||
- cd ..
|
|
||||||
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- cp ../AMBuildScript ../../
|
|
||||||
- python2 ../configure.py -s sdk2013 --hl2sdk-root ../assets --sm-path ../assets/sourcemod-central --mms-path ../assets/mmsource-central --steamworks-path ../assets/SteamworksSDK
|
|
||||||
- ambuild
|
|
||||||
- tar czvf ${RELEASE_PKG_FILE} package
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
provider: releases
|
|
||||||
api_key:
|
|
||||||
secure: "Px60/dTgw3w6ZvxzyuilYaHHWFHWQ1rONhpbWJbxzz5+dfkmiqVyYLszlBrbS6tbyOv/oBMqcaOXsB7mv4OOlvKQPOjc8siS8ux1Ows8WL+yvRR/rGS0j28pP6HKN11hBerxOps3sqiCyNa2gNJ+3vX987SIekpIb5nqzuqg+yQ="
|
|
||||||
file_glob: true
|
|
||||||
file: "${RELEASE_PKG_FILE}"
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
+28
-90
@@ -1,24 +1,5 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os, sys
|
import os
|
||||||
|
|
||||||
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 = {
|
|
||||||
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def ResolveEnvPath(env, folder):
|
def ResolveEnvPath(env, folder):
|
||||||
if env in os.environ:
|
if env in os.environ:
|
||||||
@@ -43,7 +24,6 @@ def Normalize(path):
|
|||||||
|
|
||||||
class SteamWorksConfig(object):
|
class SteamWorksConfig(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sdks = {}
|
|
||||||
self.binaries = []
|
self.binaries = []
|
||||||
self.mms_root = None
|
self.mms_root = None
|
||||||
self.sm_root = None
|
self.sm_root = None
|
||||||
@@ -62,29 +42,7 @@ class SteamWorksConfig(object):
|
|||||||
return 'Debug'
|
return 'Debug'
|
||||||
return 'Release'
|
return 'Release'
|
||||||
|
|
||||||
def detectSDKs(self):
|
def detectDeps(self):
|
||||||
sdk_list = builder.options.sdks.split(',')
|
|
||||||
use_all = sdk_list[0] == 'all'
|
|
||||||
use_present = sdk_list[0] == 'present'
|
|
||||||
|
|
||||||
for sdk_name in PossibleSDKs:
|
|
||||||
sdk = PossibleSDKs[sdk_name]
|
|
||||||
if builder.cxx.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.')
|
|
||||||
|
|
||||||
#METAMOD:SOURCE
|
#METAMOD:SOURCE
|
||||||
if builder.options.mms_path:
|
if builder.options.mms_path:
|
||||||
self.mms_root = builder.options.mms_path
|
self.mms_root = builder.options.mms_path
|
||||||
@@ -153,15 +111,22 @@ class SteamWorksConfig(object):
|
|||||||
'-Wno-format',
|
'-Wno-format',
|
||||||
'-Wno-format-security',
|
'-Wno-format-security',
|
||||||
'-Wno-array-bounds',
|
'-Wno-array-bounds',
|
||||||
'-msse',
|
|
||||||
'-m32',
|
|
||||||
]
|
]
|
||||||
cxx.cxxflags += [
|
cxx.cxxflags += [
|
||||||
'-std=c++11',
|
'-std=c++17',
|
||||||
]
|
]
|
||||||
|
|
||||||
have_gcc = cxx.vendor == 'gcc'
|
if cxx.target.arch == 'x86':
|
||||||
have_clang = cxx.vendor == 'clang'
|
cxx.cflags += ['-msse', '-m32']
|
||||||
|
cxx.linkflags += ['-m32']
|
||||||
|
if cxx.family == 'gcc':
|
||||||
|
cxx.cflags += ['-mfpmath=sse']
|
||||||
|
elif cxx.target.arch == 'x86_64':
|
||||||
|
cxx.cflags += ['-m64']
|
||||||
|
cxx.linkflags += ['-m64']
|
||||||
|
|
||||||
|
have_gcc = cxx.family == 'gcc'
|
||||||
|
have_clang = cxx.family == 'clang'
|
||||||
if have_clang or (have_gcc and cxx.version >= '4'):
|
if have_clang or (have_gcc and cxx.version >= '4'):
|
||||||
cxx.cflags += ['-fvisibility=hidden']
|
cxx.cflags += ['-fvisibility=hidden']
|
||||||
cxx.cxxflags += ['-fvisibility-inlines-hidden']
|
cxx.cxxflags += ['-fvisibility-inlines-hidden']
|
||||||
@@ -179,17 +144,13 @@ class SteamWorksConfig(object):
|
|||||||
cxx.cxxflags += ['-Wno-deprecated']
|
cxx.cxxflags += ['-Wno-deprecated']
|
||||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||||
|
|
||||||
cxx.linkflags += ['-m32']
|
|
||||||
cxx.cxxflags += [
|
cxx.cxxflags += [
|
||||||
'-fno-exceptions',
|
'-fno-exceptions',
|
||||||
'-fno-threadsafe-statics',
|
'-fno-threadsafe-statics',
|
||||||
'-Wno-non-virtual-dtor',
|
'-Wno-non-virtual-dtor',
|
||||||
'-Wno-overloaded-virtual',
|
'-Wno-overloaded-virtual',
|
||||||
]
|
]
|
||||||
|
elif cxx.like('msvc'):
|
||||||
if have_gcc:
|
|
||||||
cxx.cflags += ['-mfpmath=sse']
|
|
||||||
elif cxx.vendor == 'msvc':
|
|
||||||
if builder.options.debug == '1':
|
if builder.options.debug == '1':
|
||||||
cxx.cflags += ['/MTd']
|
cxx.cflags += ['/MTd']
|
||||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||||
@@ -208,9 +169,10 @@ class SteamWorksConfig(object):
|
|||||||
'/EHsc',
|
'/EHsc',
|
||||||
'/GR-',
|
'/GR-',
|
||||||
'/TP',
|
'/TP',
|
||||||
|
'/std:c++17',
|
||||||
]
|
]
|
||||||
cxx.linkflags += [
|
cxx.linkflags += [
|
||||||
'/MACHINE:X86',
|
'/MACHINE:X64' if cxx.target.arch == 'x86_64' else '/MACHINE:X86',
|
||||||
'/SUBSYSTEM:WINDOWS',
|
'/SUBSYSTEM:WINDOWS',
|
||||||
'kernel32.lib',
|
'kernel32.lib',
|
||||||
'user32.lib',
|
'user32.lib',
|
||||||
@@ -244,27 +206,17 @@ class SteamWorksConfig(object):
|
|||||||
cxx.cflags += ['/d2Zi+']
|
cxx.cflags += ['/d2Zi+']
|
||||||
|
|
||||||
# This needs to be after our optimization flags which could otherwise disable it.
|
# This needs to be after our optimization flags which could otherwise disable it.
|
||||||
if cxx.vendor == 'msvc':
|
if cxx.like('msvc'):
|
||||||
# Don't omit the frame pointer.
|
# Don't omit the frame pointer.
|
||||||
cxx.cflags += ['/Oy-']
|
cxx.cflags += ['/Oy-']
|
||||||
|
|
||||||
# Platform-specifics
|
# Platform-specifics
|
||||||
if cxx.target.platform == 'linux':
|
if cxx.target.platform == 'linux':
|
||||||
cxx.defines += ['_LINUX', 'POSIX']
|
cxx.defines += ['_LINUX', 'POSIX']
|
||||||
if cxx.vendor == 'gcc':
|
if cxx.family == 'gcc':
|
||||||
cxx.linkflags += ['-static-libgcc']
|
cxx.linkflags += ['-static-libgcc']
|
||||||
elif cxx.vendor == 'clang':
|
elif cxx.family == 'clang':
|
||||||
cxx.linkflags += ['-lgcc_eh']
|
cxx.linkflags += ['-lgcc_eh']
|
||||||
elif cxx.target.platform == 'mac':
|
|
||||||
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
|
||||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
|
||||||
cxx.linkflags += [
|
|
||||||
'-mmacosx-version-min=10.5',
|
|
||||||
'-arch', 'i386',
|
|
||||||
'-static',
|
|
||||||
'-stdlib=libc++'
|
|
||||||
]
|
|
||||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
|
||||||
elif cxx.target.platform == 'windows':
|
elif cxx.target.platform == 'windows':
|
||||||
cxx.defines += ['WIN32', '_WINDOWS']
|
cxx.defines += ['WIN32', '_WINDOWS']
|
||||||
|
|
||||||
@@ -274,16 +226,15 @@ class SteamWorksConfig(object):
|
|||||||
os.path.join(context.currentSourcePath, 'sdk'),
|
os.path.join(context.currentSourcePath, 'sdk'),
|
||||||
os.path.join(self.sm_root, 'public'),
|
os.path.join(self.sm_root, 'public'),
|
||||||
os.path.join(self.sm_root, 'public', 'extensions'),
|
os.path.join(self.sm_root, 'public', 'extensions'),
|
||||||
os.path.join(self.sm_root, 'public', 'sourcepawn'),
|
os.path.join(self.sm_root, 'sourcepawn', 'include'),
|
||||||
|
os.path.join(self.sm_root, 'public', 'amtl', 'amtl'),
|
||||||
|
os.path.join(self.sm_root, 'public', 'amtl'),
|
||||||
]
|
]
|
||||||
return compiler
|
return compiler
|
||||||
|
|
||||||
def ConfigureForHL2(self, binary, sdk):
|
def ConfigureForHL2(self, binary):
|
||||||
compiler = binary.compiler
|
compiler = binary.compiler
|
||||||
|
|
||||||
if sdk.name == 'episode1':
|
|
||||||
mms_path = os.path.join(self.mms_root, 'core-legacy')
|
|
||||||
else:
|
|
||||||
mms_path = os.path.join(self.mms_root, 'core')
|
mms_path = os.path.join(self.mms_root, 'core')
|
||||||
|
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
@@ -291,32 +242,19 @@ class SteamWorksConfig(object):
|
|||||||
os.path.join(mms_path, 'sourcehook'),
|
os.path.join(mms_path, 'sourcehook'),
|
||||||
]
|
]
|
||||||
|
|
||||||
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
|
||||||
compiler.defines += defines
|
|
||||||
|
|
||||||
if compiler.like('msvc'):
|
|
||||||
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
|
|
||||||
else:
|
|
||||||
compiler.defines += ['COMPILER_GCC']
|
|
||||||
|
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def HL2Library(self, context, name, sdk):
|
|
||||||
binary = context.compiler.Library(name)
|
|
||||||
self.ConfigureForExtension(context, binary.compiler)
|
|
||||||
return self.ConfigureForHL2(binary, sdk)
|
|
||||||
|
|
||||||
def HL2Project(self, context, name):
|
def HL2Project(self, context, name):
|
||||||
project = context.LibraryProject(name)
|
project = context.LibraryProject(name)
|
||||||
self.ConfigureForExtension(context, context.cxx)
|
self.ConfigureForExtension(context, context.cxx)
|
||||||
return project
|
return project
|
||||||
|
|
||||||
def HL2Config(self, project, cxx, name, sdk):
|
def HL2Config(self, project, cxx, name):
|
||||||
binary = project.Configure(cxx, name, '{0} - {1}'.format(self.tag, sdk.name))
|
binary = project.Configure(cxx, name, '{0}'.format(self.tag))
|
||||||
return self.ConfigureForHL2(binary, sdk)
|
return self.ConfigureForHL2(binary)
|
||||||
|
|
||||||
SteamWorks = SteamWorksConfig()
|
SteamWorks = SteamWorksConfig()
|
||||||
SteamWorks.detectSDKs()
|
SteamWorks.detectDeps()
|
||||||
SteamWorks.configure()
|
SteamWorks.configure()
|
||||||
|
|
||||||
BuildScripts = ['Extension/AMBuilder']
|
BuildScripts = ['Extension/AMBuilder']
|
||||||
|
|||||||
+69
-13
@@ -1,6 +1,51 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
# --- SafetyHook -----------------------------------------------------------------
|
||||||
|
# The extension's detours use SourceMod's safetyhook-based CDetour, which handles
|
||||||
|
# both x86 and x86_64, replacing the old x86-only asm trampolines. Build safetyhook
|
||||||
|
# as a static library straight out of the SourceMod tree.
|
||||||
|
sh_root = os.path.join(SteamWorks.sm_root, 'public', 'safetyhook')
|
||||||
|
|
||||||
|
libsafetyhook = builder.StaticLibraryProject('safetyhook')
|
||||||
|
libsafetyhook.sources += [
|
||||||
|
os.path.join(sh_root, 'src', 'allocator.cpp'),
|
||||||
|
os.path.join(sh_root, 'src', 'easy.cpp'),
|
||||||
|
os.path.join(sh_root, 'src', 'inline_hook.cpp'),
|
||||||
|
os.path.join(sh_root, 'src', 'mid_hook.cpp'),
|
||||||
|
os.path.join(sh_root, 'src', 'utility.cpp'),
|
||||||
|
os.path.join(sh_root, 'src', 'vmt_hook.cpp'),
|
||||||
|
os.path.join(sh_root, 'zydis', 'Zydis.c'),
|
||||||
|
]
|
||||||
|
|
||||||
|
sh_binary = libsafetyhook.Configure(builder.cxx, 'safetyhook',
|
||||||
|
'Release - {0}'.format(builder.cxx.target.arch))
|
||||||
|
sh_cxx = sh_binary.compiler
|
||||||
|
# safetyhook is third-party; compile it with its own flag set.
|
||||||
|
sh_cxx.cxxflags = []
|
||||||
|
sh_cxx.cflags = []
|
||||||
|
sh_cxx.defines = []
|
||||||
|
sh_cxx.includes = []
|
||||||
|
sh_cxx.cxxincludes = []
|
||||||
|
|
||||||
|
if builder.options.debug != '1':
|
||||||
|
sh_cxx.defines += ['NDEBUG']
|
||||||
|
|
||||||
|
if sh_cxx.target.platform == 'windows':
|
||||||
|
sh_cxx.cflags += ['/W4']
|
||||||
|
sh_cxx.cflags += ['/MTd' if builder.options.debug == '1' else '/MT']
|
||||||
|
sh_cxx.cxxflags += ['/EHsc', '/permissive-', '/std:c++17']
|
||||||
|
sh_binary.sources += [os.path.join(sh_root, 'src', 'os.windows.cpp')]
|
||||||
|
elif sh_cxx.target.platform == 'linux':
|
||||||
|
sh_cxx.cflags += ['-fPIC', '-Wall', '-Wno-unused-function', '-Wno-unused-const-variable']
|
||||||
|
sh_cxx.cflags += ['-m64' if sh_cxx.target.arch == 'x86_64' else '-m32']
|
||||||
|
sh_cxx.cxxflags += ['-std=c++17', '-Wno-format']
|
||||||
|
sh_binary.sources += [os.path.join(sh_root, 'src', 'os.linux.cpp')]
|
||||||
|
|
||||||
|
sh_cxx.includes += [os.path.join(sh_root, 'include'), os.path.join(sh_root, 'zydis')]
|
||||||
|
safetyhook_tasks = builder.Add(libsafetyhook)
|
||||||
|
|
||||||
|
# --- SteamWorks extension -------------------------------------------------------
|
||||||
project = SteamWorks.HL2Project(builder, 'SteamWorks.ext')
|
project = SteamWorks.HL2Project(builder, 'SteamWorks.ext')
|
||||||
project.sources += [
|
project.sources += [
|
||||||
'extension.cpp',
|
'extension.cpp',
|
||||||
@@ -16,25 +61,36 @@ project.sources += [
|
|||||||
'swhttprequest.cpp',
|
'swhttprequest.cpp',
|
||||||
'swgchooks.cpp',
|
'swgchooks.cpp',
|
||||||
'sdk/smsdk_ext.cpp',
|
'sdk/smsdk_ext.cpp',
|
||||||
'CDetour/detours.cpp',
|
os.path.join(SteamWorks.sm_root, 'public', 'CDetour', 'detours.cpp'),
|
||||||
'asm/asm.c'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for sdk_name in SteamWorks.sdks:
|
binary = SteamWorks.HL2Config(project, builder.cxx, 'SteamWorks.ext')
|
||||||
sdk = SteamWorks.sdks[sdk_name]
|
|
||||||
|
|
||||||
binary = SteamWorks.HL2Config(project, builder.cxx, 'SteamWorks.ext', sdk)
|
# The Steam API headers all come from the SteamWorks SDK; the extension is built
|
||||||
|
# with META_NO_HL2SDK, so no HL2SDK is required.
|
||||||
|
binary.compiler.defines += ['META_NO_HL2SDK', 'SOURCEMOD_BUILD', 'VERSION_SAFE_STEAM_API_INTERFACES']
|
||||||
|
binary.compiler.cxxincludes += [os.path.join(SteamWorks.steamworks_root, 'public', 'steam')]
|
||||||
|
binary.compiler.cxxincludes += [os.path.join(SteamWorks.sm_root, 'public', 'safetyhook', 'include')]
|
||||||
|
|
||||||
binary.compiler.defines += ['META_NO_HL2SDK', 'SOURCEMOD_BUILD', 'VERSION_SAFE_STEAM_API_INTERFACES']
|
# Link the matching-arch safetyhook static library.
|
||||||
binary.compiler.cxxincludes += [os.path.join(SteamWorks.steamworks_root, 'public', 'steam'), os.path.join(sdk.path, 'public', 'steam')];
|
for task in safetyhook_tasks:
|
||||||
|
if task.target.arch == binary.compiler.target.arch:
|
||||||
|
binary.compiler.linkflags += [task.binary]
|
||||||
|
break
|
||||||
|
|
||||||
if binary.compiler.target.platform == 'linux':
|
steamworks_bin = os.path.join(SteamWorks.steamworks_root, 'redistributable_bin')
|
||||||
binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'linux32', 'libsteam_api.so'),;
|
arch = binary.compiler.target.arch
|
||||||
|
|
||||||
if binary.compiler.target.platform == 'windows':
|
if binary.compiler.target.platform == 'linux':
|
||||||
binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'steam_api.lib'),;
|
if arch == 'x86_64':
|
||||||
|
binary.compiler.postlink += [os.path.join(steamworks_bin, 'linux64', 'libsteam_api.so')]
|
||||||
|
else:
|
||||||
|
binary.compiler.postlink += [os.path.join(steamworks_bin, 'linux32', 'libsteam_api.so')]
|
||||||
|
|
||||||
if binary.compiler.target.platform == 'mac':
|
if binary.compiler.target.platform == 'windows':
|
||||||
binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'osx', 'libsteam_api.dylib'),;
|
if arch == 'x86_64':
|
||||||
|
binary.compiler.postlink += [os.path.join(steamworks_bin, 'win64', 'steam_api64.lib')]
|
||||||
|
else:
|
||||||
|
binary.compiler.postlink += [os.path.join(steamworks_bin, 'steam_api.lib')]
|
||||||
|
|
||||||
SteamWorks.extensions += builder.Add(project)
|
SteamWorks.extensions += builder.Add(project)
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
|
||||||
#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
|
||||||
|
|
||||||
#if defined PLATFORM_POSIX
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#ifndef PAGE_SIZE
|
|
||||||
#define PAGE_SIZE 4096
|
|
||||||
#endif
|
|
||||||
#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
|
|
||||||
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct patch_t
|
|
||||||
{
|
|
||||||
patch_t()
|
|
||||||
{
|
|
||||||
patch[0] = 0;
|
|
||||||
bytes = 0;
|
|
||||||
}
|
|
||||||
unsigned char patch[20];
|
|
||||||
size_t bytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void ProtectMemory(void *addr, int length, int prot)
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_POSIX
|
|
||||||
void *addr2 = (void *)ALIGN(addr);
|
|
||||||
mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
DWORD old_prot;
|
|
||||||
VirtualProtect(addr, length, prot, &old_prot);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetMemPatchable(void *address, size_t size)
|
|
||||||
{
|
|
||||||
ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void DoGatePatch(unsigned char *target, void *callback)
|
|
||||||
{
|
|
||||||
SetMemPatchable(target, 20);
|
|
||||||
|
|
||||||
target[0] = 0xFF; /* JMP */
|
|
||||||
target[1] = 0x25; /* MEM32 */
|
|
||||||
*(void **)(&target[2]) = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
|
|
||||||
{
|
|
||||||
ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE);
|
|
||||||
|
|
||||||
unsigned char *addr = (unsigned char *)address + offset;
|
|
||||||
if (restore)
|
|
||||||
{
|
|
||||||
for (size_t i=0; i<patch->bytes; i++)
|
|
||||||
{
|
|
||||||
restore->patch[i] = addr[i];
|
|
||||||
}
|
|
||||||
restore->bytes = patch->bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i=0; i<patch->bytes; i++)
|
|
||||||
{
|
|
||||||
addr[i] = patch->patch[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "detours.h"
|
|
||||||
#include <asm/asm.h>
|
|
||||||
|
|
||||||
ISourcePawnEngine *CDetourManager::spengine = NULL;
|
|
||||||
IGameConfig *CDetourManager::gameconf = NULL;
|
|
||||||
|
|
||||||
void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
|
||||||
{
|
|
||||||
CDetourManager::spengine = spengine;
|
|
||||||
CDetourManager::gameconf = gameconf;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
|
|
||||||
{
|
|
||||||
CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
|
|
||||||
if (detour)
|
|
||||||
{
|
|
||||||
if (!detour->Init(spengine, gameconf))
|
|
||||||
{
|
|
||||||
delete detour;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return detour;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, void *address)
|
|
||||||
{
|
|
||||||
CDetour *detour = new CDetour(callbackfunction, trampoline, address);
|
|
||||||
if (detour)
|
|
||||||
{
|
|
||||||
if (!detour->Init(spengine, gameconf))
|
|
||||||
{
|
|
||||||
delete detour;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return detour;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
|
|
||||||
{
|
|
||||||
enabled = false;
|
|
||||||
detoured = false;
|
|
||||||
detour_address = NULL;
|
|
||||||
detour_trampoline = NULL;
|
|
||||||
this->signame = signame;
|
|
||||||
this->address = NULL;
|
|
||||||
this->detour_callback = callbackfunction;
|
|
||||||
spengine = NULL;
|
|
||||||
gameconf = NULL;
|
|
||||||
this->trampoline = trampoline;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDetour::CDetour(void *callbackfunction, void **trampoline, void *pAddress)
|
|
||||||
{
|
|
||||||
enabled = false;
|
|
||||||
detoured = false;
|
|
||||||
detour_address = NULL;
|
|
||||||
detour_trampoline = NULL;
|
|
||||||
this->signame = NULL;
|
|
||||||
this->address = pAddress;
|
|
||||||
this->detour_callback = callbackfunction;
|
|
||||||
spengine = NULL;
|
|
||||||
gameconf = NULL;
|
|
||||||
this->trampoline = trampoline;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
|
||||||
{
|
|
||||||
this->spengine = spengine;
|
|
||||||
this->gameconf = gameconf;
|
|
||||||
|
|
||||||
if (!CreateDetour())
|
|
||||||
{
|
|
||||||
enabled = false;
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled = true;
|
|
||||||
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDetour::Destroy()
|
|
||||||
{
|
|
||||||
DeleteDetour();
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDetour::IsEnabled()
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDetour::CreateDetour()
|
|
||||||
{
|
|
||||||
if (signame != NULL && !gameconf->GetMemSig(signame, &detour_address))
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (address != NULL)
|
|
||||||
{
|
|
||||||
detour_address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!detour_address)
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
|
|
||||||
|
|
||||||
/* First, save restore bits */
|
|
||||||
for (size_t i=0; i<detour_restore.bytes; i++)
|
|
||||||
{
|
|
||||||
detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
JitWriter wr;
|
|
||||||
JitWriter *jit = ≀
|
|
||||||
jit_uint32_t CodeSize = 0;
|
|
||||||
|
|
||||||
wr.outbase = NULL;
|
|
||||||
wr.outptr = NULL;
|
|
||||||
|
|
||||||
jit_rewind:
|
|
||||||
|
|
||||||
/* Patch old bytes in */
|
|
||||||
if (wr.outbase != NULL)
|
|
||||||
{
|
|
||||||
copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes);
|
|
||||||
}
|
|
||||||
wr.outptr += detour_restore.bytes;
|
|
||||||
|
|
||||||
/* Return to the original function */
|
|
||||||
jitoffs_t call = IA32_Jump_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
|
|
||||||
|
|
||||||
if (wr.outbase == NULL)
|
|
||||||
{
|
|
||||||
CodeSize = wr.get_outputpos();
|
|
||||||
wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize);
|
|
||||||
spengine->SetReadWrite(wr.outbase);
|
|
||||||
wr.outptr = wr.outbase;
|
|
||||||
detour_trampoline = wr.outbase;
|
|
||||||
goto jit_rewind;
|
|
||||||
}
|
|
||||||
|
|
||||||
spengine->SetReadExecute(wr.outbase);
|
|
||||||
|
|
||||||
*trampoline = detour_trampoline;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDetour::DeleteDetour()
|
|
||||||
{
|
|
||||||
if (detoured)
|
|
||||||
{
|
|
||||||
DisableDetour();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (detour_trampoline)
|
|
||||||
{
|
|
||||||
/* Free the allocated trampoline memory */
|
|
||||||
spengine->FreePageMemory(detour_trampoline);
|
|
||||||
detour_trampoline = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDetour::EnableDetour()
|
|
||||||
{
|
|
||||||
if (!detoured)
|
|
||||||
{
|
|
||||||
DoGatePatch((unsigned char *)detour_address, &detour_callback);
|
|
||||||
detoured = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDetour::DisableDetour()
|
|
||||||
{
|
|
||||||
if (detoured)
|
|
||||||
{
|
|
||||||
/* Remove the patch */
|
|
||||||
ApplyPatch(detour_address, 0, &detour_restore, NULL);
|
|
||||||
detoured = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
|
|
||||||
#define _INCLUDE_SOURCEMOD_DETOURS_H_
|
|
||||||
|
|
||||||
#include "smsdk_ext.h"
|
|
||||||
#include <jit/jit_helpers.h>
|
|
||||||
#include <jit/x86/x86_macros.h>
|
|
||||||
#include "detourhelpers.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CDetours class for SourceMod Extensions by pRED*
|
|
||||||
* detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
|
|
||||||
* asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly
|
|
||||||
* Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/)
|
|
||||||
* Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
|
|
||||||
#define DETOUR_STATIC_CALL(name) (name##_Actual)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_STATIC0(name, ret) \
|
|
||||||
ret (*name##_Actual)(void) = NULL; \
|
|
||||||
ret name(void)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
|
|
||||||
ret (*name##_Actual)(p1type) = NULL; \
|
|
||||||
ret name(p1type p1name)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
|
|
||||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
|
|
||||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_STATIC6(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name) \
|
|
||||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type) = NULL; \
|
|
||||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_MEMBER0(name, ret) \
|
|
||||||
class name##Class \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
ret name(); \
|
|
||||||
static ret (name##Class::* name##_Actual)(void); \
|
|
||||||
}; \
|
|
||||||
ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
|
|
||||||
ret name##Class::name()
|
|
||||||
|
|
||||||
#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
|
|
||||||
class name##Class \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
ret name(p1type p1name); \
|
|
||||||
static ret (name##Class::* name##_Actual)(p1type); \
|
|
||||||
}; \
|
|
||||||
ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
|
|
||||||
ret name##Class::name(p1type p1name)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
|
|
||||||
class name##Class \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
ret name(p1type p1name, p2type p2name); \
|
|
||||||
static ret (name##Class::* name##_Actual)(p1type, p2type); \
|
|
||||||
}; \
|
|
||||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
|
|
||||||
ret name##Class::name(p1type p1name, p2type p2name)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
|
|
||||||
class name##Class \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
ret name(p1type p1name, p2type p2name, p3type p3name); \
|
|
||||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
|
|
||||||
}; \
|
|
||||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
|
|
||||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
|
|
||||||
|
|
||||||
#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
|
|
||||||
class name##Class \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
|
|
||||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
|
|
||||||
}; \
|
|
||||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
|
|
||||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
|
|
||||||
|
|
||||||
|
|
||||||
#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
|
|
||||||
#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
|
|
||||||
|
|
||||||
#define GET_STATIC_CALLBACK(name) (void *)&name
|
|
||||||
#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
|
|
||||||
|
|
||||||
#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
|
|
||||||
#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
|
|
||||||
#define DETOUR_CREATE_STATIC_FIXED(name, address) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), address);
|
|
||||||
|
|
||||||
|
|
||||||
class GenericClass {};
|
|
||||||
typedef void (GenericClass::*VoidFunc)();
|
|
||||||
|
|
||||||
inline void *GetCodeAddr(VoidFunc mfp)
|
|
||||||
{
|
|
||||||
return *(void **)&mfp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a member function pointer to a void pointer.
|
|
||||||
* This relies on the assumption that the code address lies at mfp+0
|
|
||||||
* This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
|
|
||||||
* Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
|
|
||||||
*/
|
|
||||||
#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast<VoidFunc>(mfp))
|
|
||||||
|
|
||||||
class CDetourManager;
|
|
||||||
|
|
||||||
class CDetour
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool IsEnabled();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These would be somewhat self-explanatory I hope
|
|
||||||
*/
|
|
||||||
void EnableDetour();
|
|
||||||
void DisableDetour();
|
|
||||||
|
|
||||||
void Destroy();
|
|
||||||
|
|
||||||
friend class CDetourManager;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
CDetour(void *callbackfunction, void **trampoline, const char *signame);
|
|
||||||
CDetour(void *callbackfunction, void **trampoline, void *address);
|
|
||||||
|
|
||||||
bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
|
||||||
private:
|
|
||||||
|
|
||||||
/* These create/delete the allocated memory */
|
|
||||||
bool CreateDetour();
|
|
||||||
void DeleteDetour();
|
|
||||||
|
|
||||||
bool enabled;
|
|
||||||
bool detoured;
|
|
||||||
|
|
||||||
patch_t detour_restore;
|
|
||||||
/* Address of the detoured function */
|
|
||||||
void *detour_address;
|
|
||||||
/* Address of the allocated trampoline function */
|
|
||||||
void *detour_trampoline;
|
|
||||||
/* Address of the callback handler */
|
|
||||||
void *detour_callback;
|
|
||||||
/* The function pointer used to call our trampoline */
|
|
||||||
void **trampoline;
|
|
||||||
|
|
||||||
const char *signame;
|
|
||||||
void *address;
|
|
||||||
ISourcePawnEngine *spengine;
|
|
||||||
IGameConfig *gameconf;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CDetourManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new detour
|
|
||||||
*
|
|
||||||
* @param callbackfunction Void pointer to your detour callback function.
|
|
||||||
* @param trampoline Address of the trampoline pointer
|
|
||||||
* @param signame Section name containing a signature to fetch from the gamedata file.
|
|
||||||
* @return A new CDetour pointer to control your detour.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
|
|
||||||
*
|
|
||||||
* Define a new class with the required function and a member function pointer to the same type:
|
|
||||||
*
|
|
||||||
* class CBaseServerDetour
|
|
||||||
* {
|
|
||||||
* public:
|
|
||||||
* bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
|
||||||
* static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
|
|
||||||
* void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
|
|
||||||
*
|
|
||||||
* Creation:
|
|
||||||
* CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
*
|
|
||||||
* CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
|
|
||||||
* {
|
|
||||||
* //pre hook code
|
|
||||||
* bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
|
|
||||||
* //post hook code
|
|
||||||
* return result;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Note we changed the netadr_s reference into a void* to avoid needing to define the type
|
|
||||||
*/
|
|
||||||
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
|
|
||||||
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, void *address);
|
|
||||||
|
|
||||||
friend class CBlocker;
|
|
||||||
friend class CDetour;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ISourcePawnEngine *spengine;
|
|
||||||
static IGameConfig *gameconf;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
|
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
# (C)2004-2010 SourceMod Development Team
|
|
||||||
# Makefile written by David "BAILOPAN" Anderson
|
|
||||||
|
|
||||||
###########################################
|
|
||||||
### EDIT THESE PATHS FOR YOUR OWN SETUP ###
|
|
||||||
###########################################
|
|
||||||
|
|
||||||
SMSDK = ../..
|
|
||||||
HL2SDK_ORIG = ../../../hl2sdk
|
|
||||||
HL2SDK_OB = ../../../hl2sdk-ob
|
|
||||||
HL2SDK_CSS = ../../../hl2sdk-css
|
|
||||||
HL2SDK_OB_VALVE = ../../../hl2sdk-2013
|
|
||||||
HL2SDK_L4D = ../../../hl2sdk-l4d
|
|
||||||
HL2SDK_L4D2 = ../../../hl2sdk-l4d2
|
|
||||||
HL2SDK_CSGO = ../../../hl2sdk-csgo
|
|
||||||
MMSOURCE19 = ../../../mmsource-1.9
|
|
||||||
STEAMWORKS = ../../../opensteamworks
|
|
||||||
|
|
||||||
#####################################
|
|
||||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
|
||||||
#####################################
|
|
||||||
|
|
||||||
PROJECT = SteamWorks
|
|
||||||
|
|
||||||
#Uncomment for Metamod: Source enabled extension
|
|
||||||
#USEMETA = true
|
|
||||||
USESH = true
|
|
||||||
USECD = true
|
|
||||||
|
|
||||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp swgameserver.cpp swgamedata.cpp swforwards.cpp gsnatives.cpp swgshooks.cpp swgsdetours.cpp ssnatives.cpp swhttp.cpp swhttprequest.cpp
|
|
||||||
|
|
||||||
ifeq "$(USECD)" "true"
|
|
||||||
OBJECTS += CDetour/detours.cpp asm/asm.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
##############################################
|
|
||||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
|
||||||
##############################################
|
|
||||||
|
|
||||||
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
|
|
||||||
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
|
|
||||||
C_GCC4_FLAGS = -fvisibility=hidden
|
|
||||||
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
|
|
||||||
CPP = gcc
|
|
||||||
CPP_OSX = clang
|
|
||||||
|
|
||||||
##########################
|
|
||||||
### SDK CONFIGURATIONS ###
|
|
||||||
##########################
|
|
||||||
|
|
||||||
override ENGSET = false
|
|
||||||
|
|
||||||
# Check for valid list of engines
|
|
||||||
ifneq (,$(filter original orangebox orangeboxvalve css left4dead left4dead2 csgo,$(ENGINE)))
|
|
||||||
override ENGSET = true
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq "$(ENGINE)" "original"
|
|
||||||
HL2SDK = $(HL2SDK_ORIG)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=1
|
|
||||||
endif
|
|
||||||
ifeq "$(ENGINE)" "orangebox"
|
|
||||||
HL2SDK = $(HL2SDK_OB)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=3
|
|
||||||
endif
|
|
||||||
ifeq "$(ENGINE)" "css"
|
|
||||||
HL2SDK = $(HL2SDK_CSS)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=6
|
|
||||||
endif
|
|
||||||
ifeq "$(ENGINE)" "orangeboxvalve"
|
|
||||||
HL2SDK = $(HL2SDK_OB_VALVE)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=7
|
|
||||||
endif
|
|
||||||
ifeq "$(ENGINE)" "left4dead"
|
|
||||||
HL2SDK = $(HL2SDK_L4D)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=8
|
|
||||||
endif
|
|
||||||
ifeq "$(ENGINE)" "left4dead2"
|
|
||||||
HL2SDK = $(HL2SDK_L4D2)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=9
|
|
||||||
endif
|
|
||||||
ifeq "$(ENGINE)" "csgo"
|
|
||||||
HL2SDK = $(HL2SDK_CSGO)
|
|
||||||
CFLAGS += -DSOURCE_ENGINE=12
|
|
||||||
endif
|
|
||||||
|
|
||||||
HL2PUB = $(HL2SDK)/public
|
|
||||||
|
|
||||||
ifeq "$(ENGINE)" "original"
|
|
||||||
INCLUDE += -I$(HL2SDK)/public/dlls
|
|
||||||
METAMOD = $(MMSOURCE19)/core-legacy
|
|
||||||
else
|
|
||||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
|
||||||
METAMOD = $(MMSOURCE19)/core
|
|
||||||
endif
|
|
||||||
|
|
||||||
OS := $(shell uname -s)
|
|
||||||
|
|
||||||
ifeq "$(OS)" "Darwin"
|
|
||||||
LIB_EXT = dylib
|
|
||||||
HL2LIB = $(HL2SDK)/lib/mac
|
|
||||||
else
|
|
||||||
LIB_EXT = so
|
|
||||||
ifeq "$(ENGINE)" "original"
|
|
||||||
HL2LIB = $(HL2SDK)/linux_sdk
|
|
||||||
else
|
|
||||||
HL2LIB = $(HL2SDK)/lib/linux
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
# if ENGINE is original or OB
|
|
||||||
ifneq (,$(filter original orangebox,$(ENGINE)))
|
|
||||||
LIB_SUFFIX = _i486.$(LIB_EXT)
|
|
||||||
else
|
|
||||||
LIB_PREFIX = lib
|
|
||||||
LIB_SUFFIX = .$(LIB_EXT)
|
|
||||||
endif
|
|
||||||
|
|
||||||
INCLUDE += -I. -I.. -Isdk -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
|
||||||
|
|
||||||
ifeq "$(USEMETA)" "true"
|
|
||||||
LINK_HL2 = $(HL2LIB)/tier1_i486.a $(LIB_PREFIX)vstdlib$(LIB_SUFFIX) $(LIB_PREFIX)tier0$(LIB_SUFFIX)
|
|
||||||
ifeq "$(ENGINE)" "csgo"
|
|
||||||
LINK_HL2 += $(HL2LIB)/interfaces_i486.a
|
|
||||||
endif
|
|
||||||
|
|
||||||
LINK += $(LINK_HL2)
|
|
||||||
|
|
||||||
INCLUDE += -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) \
|
|
||||||
-I$(METAMOD)/sourcehook
|
|
||||||
CFLAGS += -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
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq "$(USESH)" "true"
|
|
||||||
INCLUDE += -I$(METAMOD) -I$(METAMOD)/sourcehook
|
|
||||||
CFLAGS += -DMETA_NO_HL2SDK
|
|
||||||
endif
|
|
||||||
|
|
||||||
LINK += -m32 -lm -ldl
|
|
||||||
LINK += $(STEAMWORKS)/redistributable_bin/linux32/libsteam_api.so
|
|
||||||
|
|
||||||
CFLAGS += -DPOSIX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
|
||||||
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -DCOMPILER_GCC -Wall -Werror \
|
|
||||||
-Wno-overloaded-virtual -Wno-switch -Wno-unused -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -m32
|
|
||||||
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
|
||||||
|
|
||||||
INCLUDE += -I$(STEAMWORKS)/public/steam
|
|
||||||
INCLUDE += -I$(HL2SDK)/public/steam
|
|
||||||
|
|
||||||
CFLAGS += -DVERSION_SAFE_STEAM_API_INTERFACES
|
|
||||||
|
|
||||||
################################################
|
|
||||||
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
|
||||||
################################################
|
|
||||||
|
|
||||||
BINARY = $(PROJECT).ext.$(LIB_EXT)
|
|
||||||
|
|
||||||
ifeq "$(DEBUG)" "true"
|
|
||||||
BIN_DIR = Debug
|
|
||||||
CFLAGS += $(C_DEBUG_FLAGS)
|
|
||||||
else
|
|
||||||
BIN_DIR = Release
|
|
||||||
CFLAGS += $(C_OPT_FLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq "$(USEMETA)" "true"
|
|
||||||
BIN_DIR := $(BIN_DIR).$(ENGINE)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq "$(OS)" "Darwin"
|
|
||||||
CPP = $(CPP_OSX)
|
|
||||||
LIB_EXT = dylib
|
|
||||||
CFLAGS += -DOSX -D_OSX
|
|
||||||
LINK += -dynamiclib -lstdc++ -mmacosx-version-min=10.5
|
|
||||||
else
|
|
||||||
LIB_EXT = so
|
|
||||||
CFLAGS += -D_LINUX
|
|
||||||
LINK += -shared
|
|
||||||
endif
|
|
||||||
|
|
||||||
IS_CLANG := $(shell $(CPP) --version | head -1 | grep clang > /dev/null && echo "1" || echo "0")
|
|
||||||
|
|
||||||
ifeq "$(IS_CLANG)" "1"
|
|
||||||
CPP_MAJOR := $(shell $(CPP) --version | grep clang | sed "s/.*version \([0-9]\)*\.[0-9]*.*/\1/")
|
|
||||||
CPP_MINOR := $(shell $(CPP) --version | grep clang | sed "s/.*version [0-9]*\.\([0-9]\)*.*/\1/")
|
|
||||||
else
|
|
||||||
CPP_MAJOR := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
|
||||||
CPP_MINOR := $(shell $(CPP) -dumpversion >&1 | cut -b3)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# If not clang
|
|
||||||
ifeq "$(IS_CLANG)" "0"
|
|
||||||
CFLAGS += -mfpmath=sse
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Clang || GCC >= 4
|
|
||||||
ifeq "$(shell expr $(IS_CLANG) \| $(CPP_MAJOR) \>= 4)" "1"
|
|
||||||
CFLAGS += $(C_GCC4_FLAGS)
|
|
||||||
CPPFLAGS += $(CPP_GCC4_FLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Clang >= 3 || GCC >= 4.7
|
|
||||||
ifeq "$(shell expr $(IS_CLANG) \& $(CPP_MAJOR) \>= 3 \| $(CPP_MAJOR) \>= 4 \& $(CPP_MINOR) \>= 7)" "1"
|
|
||||||
CFLAGS += -Wno-delete-non-virtual-dtor
|
|
||||||
endif
|
|
||||||
|
|
||||||
# OS is Linux and not using clang
|
|
||||||
ifeq "$(shell expr $(OS) \= Linux \& $(IS_CLANG) \= 0)" "1"
|
|
||||||
LINK += -static-libgcc
|
|
||||||
endif
|
|
||||||
|
|
||||||
OBJ_BIN := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
|
||||||
|
|
||||||
# This will break if we include other Makefiles, but is fine for now. It allows
|
|
||||||
# us to make a copy of this file that uses altered paths (ie. Makefile.mine)
|
|
||||||
# or other changes without mucking up the original.
|
|
||||||
MAKEFILE_NAME := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
|
|
||||||
|
|
||||||
$(BIN_DIR)/%.o: %.cpp
|
|
||||||
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
|
||||||
|
|
||||||
all: check
|
|
||||||
mkdir -p $(BIN_DIR)/sdk
|
|
||||||
mkdir -p $(BIN_DIR)/CDetour
|
|
||||||
if [ "$(USEMETA)" = "true" ]; then \
|
|
||||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX); \
|
|
||||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX); \
|
|
||||||
fi
|
|
||||||
$(MAKE) -f $(MAKEFILE_NAME) extension
|
|
||||||
|
|
||||||
check:
|
|
||||||
if [ "$(USEMETA)" = "true" ] && [ "$(ENGSET)" = "false" ]; then \
|
|
||||||
echo "You must supply one of the following values for ENGINE:"; \
|
|
||||||
echo "csgo, left4dead2, left4dead, css, orangeboxvalve, orangebox, or original"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
extension: check $(OBJ_BIN)
|
|
||||||
$(CPP) $(INCLUDE) $(OBJ_BIN) $(LINK) -o $(BIN_DIR)/$(BINARY)
|
|
||||||
|
|
||||||
debug:
|
|
||||||
$(MAKE) -f $(MAKEFILE_NAME) all DEBUG=true
|
|
||||||
|
|
||||||
default: all
|
|
||||||
|
|
||||||
clean: check
|
|
||||||
rm -rf $(BIN_DIR)/*.o
|
|
||||||
rm -rf $(BIN_DIR)/sdk/*.o
|
|
||||||
rm -rf $(BIN_DIR)/$(BINARY)
|
|
||||||
|
|
||||||
@@ -1,418 +0,0 @@
|
|||||||
#include "asm.h"
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define REG_EAX 0
|
|
||||||
#define REG_ECX 1
|
|
||||||
#define REG_EDX 2
|
|
||||||
#define REG_EBX 3
|
|
||||||
|
|
||||||
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a call to a fpic thunk has just been written into dest.
|
|
||||||
* If found replaces it with a direct mov that sets the required register to the value of pc.
|
|
||||||
*
|
|
||||||
* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
|
|
||||||
* @param pc The program counter value that needs to be set (usually the next address from the source).
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void check_thunks(unsigned char *dest, unsigned char *pc)
|
|
||||||
{
|
|
||||||
#if defined WIN32
|
|
||||||
return;
|
|
||||||
#else
|
|
||||||
/* Step write address back 4 to the start of the function address */
|
|
||||||
unsigned char *writeaddr = dest - 4;
|
|
||||||
unsigned char *calloffset = *(unsigned char **)writeaddr;
|
|
||||||
unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
|
|
||||||
|
|
||||||
/* Lookup name of function being called */
|
|
||||||
if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
|
|
||||||
{
|
|
||||||
//a thunk maybe?
|
|
||||||
char movByte = IA32_MOV_REG_IMM;
|
|
||||||
|
|
||||||
/* Calculate the correct mov opcode */
|
|
||||||
switch (*(calladdr+1))
|
|
||||||
{
|
|
||||||
case 0x04:
|
|
||||||
{
|
|
||||||
movByte += REG_EAX;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x1C:
|
|
||||||
{
|
|
||||||
movByte += REG_EBX;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0C:
|
|
||||||
{
|
|
||||||
movByte += REG_ECX;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x14:
|
|
||||||
{
|
|
||||||
movByte += REG_EDX;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move our write address back one to where the call opcode was */
|
|
||||||
writeaddr--;
|
|
||||||
|
|
||||||
|
|
||||||
/* Write our mov */
|
|
||||||
*writeaddr = movByte;
|
|
||||||
writeaddr++;
|
|
||||||
|
|
||||||
/* Write the value - The provided program counter value */
|
|
||||||
*(void **)writeaddr = (void *)pc;
|
|
||||||
writeaddr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//if dest is NULL, returns minimum number of bytes needed to be copied
|
|
||||||
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
|
||||||
//http://www.devmaster.net/forums/showthread.php?t=2311
|
|
||||||
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
|
|
||||||
int bytecount = 0;
|
|
||||||
|
|
||||||
while(bytecount < required_len && *func != 0xCC)
|
|
||||||
{
|
|
||||||
// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
|
|
||||||
int operandSize = 4;
|
|
||||||
int FPU = 0;
|
|
||||||
int twoByte = 0;
|
|
||||||
unsigned char opcode = 0x90;
|
|
||||||
unsigned char modRM = 0xFF;
|
|
||||||
while(*func == 0xF0 ||
|
|
||||||
*func == 0xF2 ||
|
|
||||||
*func == 0xF3 ||
|
|
||||||
(*func & 0xFC) == 0x64 ||
|
|
||||||
(*func & 0xF8) == 0xD8 ||
|
|
||||||
(*func & 0x7E) == 0x62)
|
|
||||||
{
|
|
||||||
if(*func == 0x66)
|
|
||||||
{
|
|
||||||
operandSize = 2;
|
|
||||||
}
|
|
||||||
else if((*func & 0xF8) == 0xD8)
|
|
||||||
{
|
|
||||||
FPU = *func;
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++;
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
bytecount++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++;
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// two-byte opcode byte
|
|
||||||
if(*func == 0x0F)
|
|
||||||
{
|
|
||||||
twoByte = 1;
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++;
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// opcode byte
|
|
||||||
opcode = *func++;
|
|
||||||
if (dest) *dest++ = opcode;
|
|
||||||
bytecount++;
|
|
||||||
|
|
||||||
// mod R/M byte
|
|
||||||
modRM = 0xFF;
|
|
||||||
if(FPU)
|
|
||||||
{
|
|
||||||
if((opcode & 0xC0) != 0xC0)
|
|
||||||
{
|
|
||||||
modRM = opcode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(!twoByte)
|
|
||||||
{
|
|
||||||
if((opcode & 0xC4) == 0x00 ||
|
|
||||||
((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) ||
|
|
||||||
(opcode & 0xF0) == 0x80 ||
|
|
||||||
((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) ||
|
|
||||||
(opcode & 0xFC) == 0xD0 ||
|
|
||||||
(opcode & 0xF6) == 0xF6)
|
|
||||||
{
|
|
||||||
modRM = *func++;
|
|
||||||
if (dest) *dest++ = modRM;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
|
|
||||||
(opcode & 0xF0) == 0x30 ||
|
|
||||||
opcode == 0x77 ||
|
|
||||||
(opcode & 0xF0) == 0x80 ||
|
|
||||||
((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
|
|
||||||
(opcode & 0xF8) == 0xC8)
|
|
||||||
{
|
|
||||||
// No mod R/M byte
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modRM = *func++;
|
|
||||||
if (dest) *dest++ = modRM;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SIB
|
|
||||||
if((modRM & 0x07) == 0x04 &&
|
|
||||||
(modRM & 0xC0) != 0xC0)
|
|
||||||
{
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++; //SIB
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mod R/M displacement
|
|
||||||
|
|
||||||
// Dword displacement, no base
|
|
||||||
if((modRM & 0xC5) == 0x05) {
|
|
||||||
if (dest) {
|
|
||||||
*(unsigned int*)dest = *(unsigned int*)func;
|
|
||||||
dest += 4;
|
|
||||||
}
|
|
||||||
func += 4;
|
|
||||||
bytecount += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Byte displacement
|
|
||||||
if((modRM & 0xC0) == 0x40) {
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++;
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dword displacement
|
|
||||||
if((modRM & 0xC0) == 0x80) {
|
|
||||||
if (dest) {
|
|
||||||
*(unsigned int*)dest = *(unsigned int*)func;
|
|
||||||
dest += 4;
|
|
||||||
}
|
|
||||||
func += 4;
|
|
||||||
bytecount += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// immediate
|
|
||||||
if(FPU)
|
|
||||||
{
|
|
||||||
// Can't have immediate operand
|
|
||||||
}
|
|
||||||
else if(!twoByte)
|
|
||||||
{
|
|
||||||
if((opcode & 0xC7) == 0x04 ||
|
|
||||||
(opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
|
|
||||||
(opcode & 0xF0) == 0x70 || // Jcc
|
|
||||||
opcode == 0x80 ||
|
|
||||||
opcode == 0x83 ||
|
|
||||||
(opcode & 0xFD) == 0xA0 || // MOV
|
|
||||||
opcode == 0xA8 || // TEST
|
|
||||||
(opcode & 0xF8) == 0xB0 || // MOV
|
|
||||||
(opcode & 0xFE) == 0xC0 || // RCL
|
|
||||||
opcode == 0xC6 || // MOV
|
|
||||||
opcode == 0xCD || // INT
|
|
||||||
(opcode & 0xFE) == 0xD4 || // AAD/AAM
|
|
||||||
(opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
|
|
||||||
opcode == 0xEB ||
|
|
||||||
(opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST
|
|
||||||
{
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++;
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
bytecount++;
|
|
||||||
}
|
|
||||||
else if((opcode & 0xF7) == 0xC2) // RET
|
|
||||||
{
|
|
||||||
if (dest) {
|
|
||||||
*(unsigned short*)dest = *(unsigned short*)func;
|
|
||||||
dest += 2;
|
|
||||||
}
|
|
||||||
func += 2;
|
|
||||||
bytecount += 2;
|
|
||||||
}
|
|
||||||
else if((opcode & 0xFC) == 0x80 ||
|
|
||||||
(opcode & 0xC7) == 0x05 ||
|
|
||||||
(opcode & 0xF8) == 0xB8 ||
|
|
||||||
(opcode & 0xFE) == 0xE8 || // CALL/Jcc
|
|
||||||
(opcode & 0xFE) == 0x68 ||
|
|
||||||
(opcode & 0xFC) == 0xA0 ||
|
|
||||||
(opcode & 0xEE) == 0xA8 ||
|
|
||||||
opcode == 0xC7 ||
|
|
||||||
(opcode == 0xF7 && (modRM & 0x30) == 0x00))
|
|
||||||
{
|
|
||||||
if (dest) {
|
|
||||||
//Fix CALL/JMP offset
|
|
||||||
if ((opcode & 0xFE) == 0xE8) {
|
|
||||||
if (operandSize == 4)
|
|
||||||
{
|
|
||||||
*(long*)dest = ((func + *(long*)func) - dest);
|
|
||||||
|
|
||||||
//pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
|
|
||||||
check_thunks(dest+4, func+4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*(short*)dest = ((func + *(short*)func) - dest);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (operandSize == 4)
|
|
||||||
*(unsigned long*)dest = *(unsigned long*)func;
|
|
||||||
else
|
|
||||||
*(unsigned short*)dest = *(unsigned short*)func;
|
|
||||||
}
|
|
||||||
dest += operandSize;
|
|
||||||
}
|
|
||||||
func += operandSize;
|
|
||||||
bytecount += operandSize;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(opcode == 0xBA || // BT
|
|
||||||
opcode == 0x0F || // 3DNow!
|
|
||||||
(opcode & 0xFC) == 0x70 || // PSLLW
|
|
||||||
(opcode & 0xF7) == 0xA4 || // SHLD
|
|
||||||
opcode == 0xC2 ||
|
|
||||||
opcode == 0xC4 ||
|
|
||||||
opcode == 0xC5 ||
|
|
||||||
opcode == 0xC6)
|
|
||||||
{
|
|
||||||
if (dest)
|
|
||||||
*dest++ = *func++;
|
|
||||||
else
|
|
||||||
func++;
|
|
||||||
}
|
|
||||||
else if((opcode & 0xF0) == 0x80) // Jcc -i
|
|
||||||
{
|
|
||||||
if (dest) {
|
|
||||||
if (operandSize == 4)
|
|
||||||
*(unsigned long*)dest = *(unsigned long*)func;
|
|
||||||
else
|
|
||||||
*(unsigned short*)dest = *(unsigned short*)func;
|
|
||||||
|
|
||||||
dest += operandSize;
|
|
||||||
}
|
|
||||||
func += operandSize;
|
|
||||||
bytecount += operandSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytecount;
|
|
||||||
}
|
|
||||||
|
|
||||||
//insert a specific JMP instruction at the given location
|
|
||||||
void inject_jmp(void* src, void* dest) {
|
|
||||||
*(unsigned char*)src = OP_JMP;
|
|
||||||
*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
|
|
||||||
}
|
|
||||||
|
|
||||||
//fill a given block with NOPs
|
|
||||||
void fill_nop(void* src, unsigned int len) {
|
|
||||||
unsigned char* src2 = (unsigned char*)src;
|
|
||||||
while (len) {
|
|
||||||
*src2++ = OP_NOP;
|
|
||||||
--len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* eval_jump(void* src) {
|
|
||||||
unsigned char* addr = (unsigned char*)src;
|
|
||||||
|
|
||||||
if (!addr) return 0;
|
|
||||||
|
|
||||||
//import table jump
|
|
||||||
if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
|
|
||||||
addr += 2;
|
|
||||||
addr = *(unsigned char**)addr;
|
|
||||||
//TODO: if addr points into the IAT
|
|
||||||
return *(void**)addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//8bit offset
|
|
||||||
else if (addr[0] == OP_JMP_BYTE) {
|
|
||||||
addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
|
|
||||||
//mangled 32bit jump?
|
|
||||||
if (addr[0] == OP_JMP) {
|
|
||||||
addr = addr + *(int*)&addr[1];
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
//32bit offset
|
|
||||||
else if (addr[0] == OP_JMP) {
|
|
||||||
addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
from ms detours package
|
|
||||||
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
|
|
||||||
{
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
|
|
||||||
__try {
|
|
||||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
|
|
||||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
|
||||||
pDosHeader->e_lfanew);
|
|
||||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbAddress >= ((PBYTE)pDosHeader +
|
|
||||||
pNtHeader->OptionalHeader
|
|
||||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
|
|
||||||
pbAddress < ((PBYTE)pDosHeader +
|
|
||||||
pNtHeader->OptionalHeader
|
|
||||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
|
|
||||||
pNtHeader->OptionalHeader
|
|
||||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#ifndef __ASM_H__
|
|
||||||
#define __ASM_H__
|
|
||||||
|
|
||||||
#define OP_JMP 0xE9
|
|
||||||
#define OP_JMP_SIZE 5
|
|
||||||
|
|
||||||
#define OP_NOP 0x90
|
|
||||||
#define OP_NOP_SIZE 1
|
|
||||||
|
|
||||||
#define OP_PREFIX 0xFF
|
|
||||||
#define OP_JMP_SEG 0x25
|
|
||||||
|
|
||||||
#define OP_JMP_BYTE 0xEB
|
|
||||||
#define OP_JMP_BYTE_SIZE 2
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void check_thunks(unsigned char *dest, unsigned char *pc);
|
|
||||||
|
|
||||||
//if dest is NULL, returns minimum number of bytes needed to be copied
|
|
||||||
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
|
||||||
//http://www.devmaster.net/forums/showthread.php?t=2311
|
|
||||||
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
|
|
||||||
|
|
||||||
//insert a specific JMP instruction at the given location
|
|
||||||
void inject_jmp(void* src, void* dest);
|
|
||||||
|
|
||||||
//fill a given block with NOPs
|
|
||||||
void fill_nop(void* src, unsigned int len);
|
|
||||||
|
|
||||||
//evaluate a JMP at the target
|
|
||||||
void* eval_jump(void* src);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //__ASM_H__
|
|
||||||
@@ -192,15 +192,9 @@ static cell_t sm_ClearRules(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
static cell_t sm_ForceHeartbeat(IPluginContext *pContext, const cell_t *params)
|
static cell_t sm_ForceHeartbeat(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
ISteamGameServer *pServer = GetGSPointer();
|
/* Deprecated no-op: newer Steamworks SDKs removed ISteamGameServer::ForceHeartbeat();
|
||||||
|
server list heartbeats are now sent implicitly by Steam. */
|
||||||
if (pServer == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
pServer->ForceHeartbeat();
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t sm_UserHasLicenseForApp(IPluginContext *pContext, const cell_t *params)
|
static cell_t sm_UserHasLicenseForApp(IPluginContext *pContext, const cell_t *params)
|
||||||
|
|||||||
@@ -21,6 +21,12 @@
|
|||||||
#include "steam_gameserver.h"
|
#include "steam_gameserver.h"
|
||||||
#include "CDetour/detours.h"
|
#include "CDetour/detours.h"
|
||||||
|
|
||||||
|
/* SourceMod's safetyhook-based CDetour doesn't ship the "fixed address" helper the
|
||||||
|
old vendored copy had, so define it in terms of the address overload it does expose. */
|
||||||
|
#ifndef DETOUR_CREATE_STATIC_FIXED
|
||||||
|
#define DETOUR_CREATE_STATIC_FIXED(name, address) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), address);
|
||||||
|
#endif
|
||||||
|
|
||||||
class SteamWorksGSDetours
|
class SteamWorksGSDetours
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -20,6 +20,15 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
/* SourceMod 1.13 (extension API 9) changed IPluginManager::FindPluginByContext()
|
||||||
|
to take an IPluginContext* directly; older SM (API 8) takes the low-level
|
||||||
|
sp_context_t* from IPluginContext::GetContext(). */
|
||||||
|
#if SMINTERFACE_EXTENSIONAPI_VERSION >= 9
|
||||||
|
#define SW_PLUGIN_CTX(ctx) (ctx)
|
||||||
|
#else
|
||||||
|
#define SW_PLUGIN_CTX(ctx) ((ctx)->GetContext())
|
||||||
|
#endif
|
||||||
|
|
||||||
static ISteamHTTP *GetHTTPPointer(void)
|
static ISteamHTTP *GetHTTPPointer(void)
|
||||||
{
|
{
|
||||||
return g_SteamWorks.pSWGameServer->GetHTTP();
|
return g_SteamWorks.pSWGameServer->GetHTTP();
|
||||||
@@ -220,7 +229,7 @@ static cell_t sm_SetCallbacks(IPluginContext *pContext, const cell_t *params)
|
|||||||
IPlugin *pPlugin;
|
IPlugin *pPlugin;
|
||||||
if (params[5] == BAD_HANDLE)
|
if (params[5] == BAD_HANDLE)
|
||||||
{
|
{
|
||||||
pPlugin = plsys->FindPluginByContext(pContext->GetContext());
|
pPlugin = plsys->FindPluginByContext(SW_PLUGIN_CTX(pContext));
|
||||||
} else {
|
} else {
|
||||||
HandleError err;
|
HandleError err;
|
||||||
pPlugin = plsys->PluginFromHandle(params[5], &err);
|
pPlugin = plsys->PluginFromHandle(params[5], &err);
|
||||||
@@ -518,7 +527,7 @@ static cell_t sm_GetHTTPResponseBodyCallback(IPluginContext *pContext, const cel
|
|||||||
IPlugin *pPlugin;
|
IPlugin *pPlugin;
|
||||||
if (params[4] == BAD_HANDLE)
|
if (params[4] == BAD_HANDLE)
|
||||||
{
|
{
|
||||||
pPlugin = plsys->FindPluginByContext(pContext->GetContext());
|
pPlugin = plsys->FindPluginByContext(SW_PLUGIN_CTX(pContext));
|
||||||
} else {
|
} else {
|
||||||
HandleError err;
|
HandleError err;
|
||||||
pPlugin = plsys->PluginFromHandle(params[4], &err);
|
pPlugin = plsys->PluginFromHandle(params[4], &err);
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ native bool:SteamWorks_SetMapName(const String:sMapName[]);
|
|||||||
native bool:SteamWorks_IsConnected();
|
native bool:SteamWorks_IsConnected();
|
||||||
native bool:SteamWorks_SetRule(const String:sKey[], const String:sValue[]);
|
native bool:SteamWorks_SetRule(const String:sKey[], const String:sValue[]);
|
||||||
native bool:SteamWorks_ClearRules();
|
native bool:SteamWorks_ClearRules();
|
||||||
|
#pragma deprecated This function is deprecated in the SDK and no longer does anything in this extension
|
||||||
native bool:SteamWorks_ForceHeartbeat();
|
native bool:SteamWorks_ForceHeartbeat();
|
||||||
native bool:SteamWorks_GetUserGroupStatus(client, groupid);
|
native bool:SteamWorks_GetUserGroupStatus(client, groupid);
|
||||||
native bool:SteamWorks_GetUserGroupStatusAuthID(authid, groupid);
|
native bool:SteamWorks_GetUserGroupStatusAuthID(authid, groupid);
|
||||||
|
|||||||
+10
-4
@@ -3,9 +3,16 @@ import os
|
|||||||
|
|
||||||
builder.SetBuildFolder('package')
|
builder.SetBuildFolder('package')
|
||||||
|
|
||||||
|
# 64-bit extensions live under an x64/ subfolder; 32-bit sit directly in
|
||||||
|
# extensions/. Only one architecture is built per configure, so pick the
|
||||||
|
# matching destination here.
|
||||||
|
if builder.cxx.target.arch == 'x86_64':
|
||||||
|
ext_folder = 'addons/sourcemod/extensions/x64'
|
||||||
|
else:
|
||||||
|
ext_folder = 'addons/sourcemod/extensions'
|
||||||
|
|
||||||
folder_list = [
|
folder_list = [
|
||||||
'addons/sourcemod/extensions',
|
ext_folder,
|
||||||
'addons/sourcemod/scripting',
|
|
||||||
'addons/sourcemod/scripting/include',
|
'addons/sourcemod/scripting/include',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -16,7 +23,7 @@ for folder in folder_list:
|
|||||||
folder_map[folder] = builder.AddFolder(norm_folder)
|
folder_map[folder] = builder.AddFolder(norm_folder)
|
||||||
|
|
||||||
for extension in SteamWorks.extensions:
|
for extension in SteamWorks.extensions:
|
||||||
builder.AddCopy(extension.binary, folder_map['addons/sourcemod/extensions'])
|
builder.AddCopy(extension.binary, folder_map[ext_folder])
|
||||||
|
|
||||||
# Do all straight-up file copies from the source tree.
|
# Do all straight-up file copies from the source tree.
|
||||||
def CopyFiles(src, dest, files):
|
def CopyFiles(src, dest, files):
|
||||||
@@ -27,5 +34,4 @@ def CopyFiles(src, dest, files):
|
|||||||
source_path = os.path.join(builder.sourcePath, src, source_file)
|
source_path = os.path.join(builder.sourcePath, src, source_file)
|
||||||
builder.AddCopy(source_path, dest_entry)
|
builder.AddCopy(source_path, dest_entry)
|
||||||
|
|
||||||
CopyFiles('Pawn', 'addons/sourcemod/scripting', ['swag.sp'])
|
|
||||||
CopyFiles('Pawn/includes', 'addons/sourcemod/scripting/include', ['SteamWorks.inc'])
|
CopyFiles('Pawn/includes', 'addons/sourcemod/scripting/include', ['SteamWorks.inc'])
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use Cwd;
|
|
||||||
|
|
||||||
package Build;
|
|
||||||
|
|
||||||
our $SVN = "/usr/bin/svn";
|
|
||||||
our $SVN_USER = 'dvander';
|
|
||||||
our $SVN_ARGS = '';
|
|
||||||
|
|
||||||
sub GitRevNum
|
|
||||||
{
|
|
||||||
my ($path) = (@_);
|
|
||||||
my ($cd, $text, $rev);
|
|
||||||
|
|
||||||
$cd = Cwd::cwd();
|
|
||||||
chdir($path);
|
|
||||||
$text = `git rev-list --count HEAD`;
|
|
||||||
chdir($cd);
|
|
||||||
|
|
||||||
chomp $text;
|
|
||||||
if ($text =~ /^(\d+)/) {
|
|
||||||
return $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub HgRevNum
|
|
||||||
{
|
|
||||||
my ($path) = (@_);
|
|
||||||
my ($cd, $text, $rev);
|
|
||||||
|
|
||||||
$cd = Cwd::cwd();
|
|
||||||
chdir($path);
|
|
||||||
$text = `hg identify -n`;
|
|
||||||
chdir($cd);
|
|
||||||
|
|
||||||
chomp $text;
|
|
||||||
if ($text =~ /^(\d+)/)
|
|
||||||
{
|
|
||||||
return $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub SvnRevNum
|
|
||||||
{
|
|
||||||
my ($str)=(@_);
|
|
||||||
|
|
||||||
my $data = Command('svnversion -c ' . $str);
|
|
||||||
if ($data =~ /(\d+):(\d+)/)
|
|
||||||
{
|
|
||||||
return $2;
|
|
||||||
} elsif ($data =~ /(\d+)/) {
|
|
||||||
return $1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub ProductVersion
|
|
||||||
{
|
|
||||||
my ($file) = (@_);
|
|
||||||
my ($version);
|
|
||||||
open(FILE, $file) or die "Could not open $file: $!\n";
|
|
||||||
$version = <FILE>;
|
|
||||||
close(FILE);
|
|
||||||
chomp $version;
|
|
||||||
return $version;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Delete
|
|
||||||
{
|
|
||||||
my ($str)=(@_);
|
|
||||||
if ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
Command("del /S /F /Q \"$str\"");
|
|
||||||
Command("rmdir /S /Q \"$str\"");
|
|
||||||
} else {
|
|
||||||
Command("rm -rf $str");
|
|
||||||
}
|
|
||||||
return !(-e $str);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Copy
|
|
||||||
{
|
|
||||||
my ($src,$dest)=(@_);
|
|
||||||
if ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
Command("copy \"$src\" \"$dest\" /y");
|
|
||||||
} else {
|
|
||||||
Command("cp \"$src\" \"$dest\"");
|
|
||||||
}
|
|
||||||
return (-e $dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Move
|
|
||||||
{
|
|
||||||
my ($src,$dest)=(@_);
|
|
||||||
if ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
Command("move \"$src\" \"$dest\"");
|
|
||||||
} else {
|
|
||||||
Command("mv \"$src\" \"$dest\"");
|
|
||||||
}
|
|
||||||
return (-e $dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Command
|
|
||||||
{
|
|
||||||
my($cmd)=(@_);
|
|
||||||
print "$cmd\n";
|
|
||||||
return `$cmd`;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub PathFormat
|
|
||||||
{
|
|
||||||
my ($str)=(@_);
|
|
||||||
if ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
$str =~ s#/#\\#g;
|
|
||||||
} else {
|
|
||||||
$str =~ s#\\#/#g;
|
|
||||||
}
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub SVN_Remove
|
|
||||||
{
|
|
||||||
my ($file)=(@_);
|
|
||||||
my ($path, $name);
|
|
||||||
if ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
($path, $name) = ($file =~ /(.+)\/([^\/]+)$/);
|
|
||||||
} else {
|
|
||||||
($path, $name) = ($file =~ /(.+)\\([^\\]+)$/);
|
|
||||||
}
|
|
||||||
my $dir = Cwd::cwd();
|
|
||||||
chdir($path);
|
|
||||||
Command($SVN . ' ' . $SVN_ARGS . ' delete ' . $name);
|
|
||||||
chdir($dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub SVN_Add
|
|
||||||
{
|
|
||||||
my ($file)=(@_);
|
|
||||||
my ($path, $name);
|
|
||||||
if ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
($path, $name) = ($file =~ /(.+)\/([^\/]+)$/);
|
|
||||||
} else {
|
|
||||||
($path, $name) = ($file =~ /(.+)\\([^\\]+)$/);
|
|
||||||
}
|
|
||||||
my $dir = Cwd::cwd();
|
|
||||||
chdir($path);
|
|
||||||
Command($SVN . ' ' . $SVN_ARGS . ' add ' . $name);
|
|
||||||
chdir($dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub GetBuildType
|
|
||||||
{
|
|
||||||
my ($file)=(@_);
|
|
||||||
my ($type);
|
|
||||||
open(TYPE, $file) or die("Could not open file: $!\n");
|
|
||||||
$type = <TYPE>;
|
|
||||||
close(TYPE);
|
|
||||||
chomp $type;
|
|
||||||
return $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
# Pastebin eziGmKtQ
|
|
||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use Cwd;
|
|
||||||
use File::Basename;
|
|
||||||
use File::Copy;
|
|
||||||
use File::Path;
|
|
||||||
use Net::FTP;
|
|
||||||
|
|
||||||
my ($ftp_file, $ftp_host, $ftp_user, $ftp_pass, $ftp_path, $tag);
|
|
||||||
|
|
||||||
$ftp_file = shift;
|
|
||||||
$tag = shift;
|
|
||||||
|
|
||||||
open(FTP, $ftp_file) or die "Unable to read FTP config file $ftp_file: $!\n";
|
|
||||||
$ftp_host = <FTP>;
|
|
||||||
$ftp_user = <FTP>;
|
|
||||||
$ftp_pass = <FTP>;
|
|
||||||
$ftp_path = <FTP>;
|
|
||||||
close(FTP);
|
|
||||||
|
|
||||||
chomp $ftp_host;
|
|
||||||
chomp $ftp_user;
|
|
||||||
chomp $ftp_pass;
|
|
||||||
chomp $ftp_path;
|
|
||||||
|
|
||||||
my ($myself, $path) = fileparse($0);
|
|
||||||
chdir($path);
|
|
||||||
|
|
||||||
require 'helpers.pm';
|
|
||||||
|
|
||||||
my ($version, $ext);
|
|
||||||
$version .= '-git' . Build::GitRevNum('.');
|
|
||||||
|
|
||||||
# Append OS to package version
|
|
||||||
if ($^O eq "darwin")
|
|
||||||
{
|
|
||||||
$ext = ".dylib";
|
|
||||||
$version .= '-mac';
|
|
||||||
}
|
|
||||||
elsif ($^O =~ /MSWin/)
|
|
||||||
{
|
|
||||||
$ext = ".dll";
|
|
||||||
$version .= '-windows';
|
|
||||||
}
|
|
||||||
elsif ($^O eq "linux")
|
|
||||||
{
|
|
||||||
$ext = ".so";
|
|
||||||
$version .= '-linux';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$version .= '-' . $^O;
|
|
||||||
}
|
|
||||||
|
|
||||||
#Switch to the output folder.
|
|
||||||
chdir(Build::PathFormat('../build/package'));
|
|
||||||
|
|
||||||
my ($dirlist, $filename, $cmd);
|
|
||||||
$dirlist = "addons";
|
|
||||||
$filename = 'SteamWorks' . $version;
|
|
||||||
|
|
||||||
if ($^O eq "linux")
|
|
||||||
{
|
|
||||||
$filename .= '.tar.gz';
|
|
||||||
$cmd = "tar zcvf $filename $dirlist";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$filename .= '.zip';
|
|
||||||
$cmd = "zip -r $filename $dirlist";
|
|
||||||
}
|
|
||||||
|
|
||||||
print "$cmd\n";
|
|
||||||
system($cmd);
|
|
||||||
|
|
||||||
$ftp_path .= "/SteamWorks";
|
|
||||||
|
|
||||||
my ($ftp);
|
|
||||||
|
|
||||||
$ftp = Net::FTP->new($ftp_host, Debug => 0, Passive => 1)
|
|
||||||
or die "Cannot connect to host $ftp_host: $@";
|
|
||||||
|
|
||||||
$ftp->login($ftp_user, $ftp_pass)
|
|
||||||
or die "Cannot connect to host $ftp_host as $ftp_user: " . $ftp->message . "\n";
|
|
||||||
|
|
||||||
if ($ftp_path ne '')
|
|
||||||
{
|
|
||||||
# YOU LEAVE ME NO CHOICE
|
|
||||||
$ftp->mkdir($ftp_path, 1);
|
|
||||||
|
|
||||||
$ftp->cwd($ftp_path)
|
|
||||||
or die "Cannot change to folder $ftp_path: " . $ftp->message . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
$ftp->binary();
|
|
||||||
$ftp->put($filename)
|
|
||||||
or die "Cannot drop file $filename ($ftp_path): " . $ftp->message . "\n";
|
|
||||||
|
|
||||||
$ftp->close();
|
|
||||||
|
|
||||||
print "File sent to drop site as $filename -- build succeeded.\n";
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
@@ -19,8 +19,6 @@ if ambuild_version.startswith('2.1'):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
run = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
run = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
||||||
run.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
|
||||||
help='Root search folder for HL2SDKs')
|
|
||||||
run.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
run.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||||
help='Path to Metamod:Source')
|
help='Path to Metamod:Source')
|
||||||
run.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
|
run.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
|
||||||
@@ -31,8 +29,5 @@ run.options.add_argument('--enable-debug', action='store_const', const='1', dest
|
|||||||
help='Enable debugging symbols')
|
help='Enable debugging symbols')
|
||||||
run.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
run.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||||
help='Enable optimization')
|
help='Enable optimization')
|
||||||
run.options.add_argument('-s', '--sdks', default='all', dest='sdks',
|
|
||||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
|
||||||
'comma-delimited list of engine names')
|
|
||||||
run.options.add_argument('--target', default=None, help='Override the default build target')
|
run.options.add_argument('--target', default=None, help='Override the default build target')
|
||||||
run.Configure()
|
run.Configure()
|
||||||
|
|||||||
Reference in New Issue
Block a user