Compare commits
112
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb356f2ffe | ||
|
|
d1b4821ab3 | ||
|
|
ce117a8295 | ||
|
|
ad4309b512 | ||
|
|
81a83fa7ce | ||
|
|
37bfc28011 | ||
|
|
4e308c40ba | ||
|
|
47b597c3ef | ||
|
|
b038670c50 | ||
|
|
79744d0de6 | ||
|
|
dac57ecbec | ||
|
|
6d40705a76 | ||
|
|
b0513dce63 | ||
|
|
3a2f04d2bc | ||
|
|
5539f2e8bf | ||
|
|
477d56b0fe | ||
|
|
f967ffaf76 | ||
|
|
3a1c518ed8 | ||
|
|
0b407a19f1 | ||
|
|
bb681c9c69 | ||
|
|
7a6382d636 | ||
|
|
ee5fa32851 | ||
|
|
5d4d0cf106 | ||
|
|
40149ba650 | ||
|
|
6608766829 | ||
|
|
7d6ef266fb | ||
|
|
54ff5fed60 | ||
|
|
3fdf350f7b | ||
|
|
cb08a96836 | ||
|
|
e3e2b8291a | ||
|
|
f7ed81d3ab | ||
|
|
1c1e9cda7c | ||
|
|
3f17137086 | ||
|
|
3d353d8ae9 | ||
|
|
482ee315b7 | ||
|
|
9e24d6e53f | ||
|
|
f248f474e7 | ||
|
|
a4512141a9 | ||
|
|
e94234ae73 | ||
|
|
54a7aa1116 | ||
|
|
6e264b6eea | ||
|
|
debfaebda8 | ||
|
|
8a633363a2 | ||
|
|
fa6f2f7e64 | ||
|
|
20eae5e394 | ||
|
|
4bce2a8a44 | ||
|
|
7eced94651 | ||
|
|
0869fde119 | ||
|
|
8e6166fa37 | ||
|
|
669b4cc69f | ||
|
|
22622ccafe | ||
|
|
d25c68f0a6 | ||
|
|
ff38e3ded2 | ||
|
|
4f43f43297 | ||
|
|
60fccfface | ||
|
|
98690df815 | ||
|
|
52c537b2ab | ||
|
|
bbec55d5f6 | ||
|
|
0abdcb58cf | ||
|
|
902672aa58 | ||
|
|
aed47ac13d | ||
|
|
6928d046f4 | ||
|
|
6c396dfbef | ||
|
|
4b66ca079d | ||
|
|
ea2e448dd6 | ||
|
|
d7fe14221b | ||
|
|
e89d3e5616 | ||
|
|
253ed583e6 | ||
|
|
58cb84d0bf | ||
|
|
65d34bdb55 | ||
|
|
19fd09c102 | ||
|
|
434d458a54 | ||
|
|
aaae36dbd3 | ||
|
|
4427ec3a65 | ||
|
|
5f6c5cb4fb | ||
|
|
6425484608 | ||
|
|
8e897f62a3 | ||
|
|
d40423569a | ||
|
|
7f28a15a5c | ||
|
|
669f1aefa6 | ||
|
|
a65dfc4888 | ||
|
|
60292fa424 | ||
|
|
0303377f92 | ||
|
|
bfd9b061f4 | ||
|
|
b1bf2dece1 | ||
|
|
b9e2d2b690 | ||
|
|
15fe086e7a | ||
|
|
26eae4e396 | ||
|
|
72eeebb59f | ||
|
|
1c5a684f1c | ||
|
|
3f5cd0e0e7 | ||
|
|
536ef2c019 | ||
|
|
9320d4b378 | ||
|
|
5b6970561e | ||
|
|
83f374561c | ||
|
|
d914a6b982 | ||
|
|
9b14101586 | ||
|
|
46c87f509b | ||
|
|
4df1d19cf2 | ||
|
|
c1af9081c6 | ||
|
|
ae538916b6 | ||
|
|
1efea1fd82 | ||
|
|
ef255c9a3e | ||
|
|
0909a1ffae | ||
|
|
d725178405 | ||
|
|
148271c5ea | ||
|
|
6252676e57 | ||
|
|
d4709704ea | ||
|
|
e6d418c04e | ||
|
|
752f7bdefc | ||
|
|
ced6add9ea | ||
|
|
e9834a33b1 |
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"project_id" : "sourcemod",
|
||||
"conduit_uri" : "https://phabricator.alliedmods.net/",
|
||||
"history.immutable" : false
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
# GitHub views all .h files as C, let's assume it's C++
|
||||
*.h linguist-language=c++
|
||||
|
||||
# Internal tools overriding
|
||||
tools/* linguist-vendored
|
||||
editor/* linguist-vendored
|
||||
|
||||
# Third-party overriding
|
||||
extensions/curl/curl-src/* linguist-vendored
|
||||
extensions/geoip/GeoIP.c linguist-vendored
|
||||
extensions/geoip/GeoIP.h linguist-vendored
|
||||
extensions/sqlite/sqlite-source/* linguist-vendored
|
||||
@@ -1,74 +0,0 @@
|
||||
# Contributing to SourceMod
|
||||
|
||||
## Issue reports
|
||||
|
||||
Please consider the following guidelines when reporting an issue.
|
||||
|
||||
#### Not for general support
|
||||
This is not the right place to get help with using or installing SourceMod, or for issues with specific, third-party SourceMod plugins or extensions.
|
||||
|
||||
For help with SourceMod, please consult the [AlliedModders forums](https://forums.alliedmods.net/forumdisplay.php?f=52). Similarly, for assistance with, or to report issues with, third-party SourceMod plugins or extensions, you should post in the existing thread for that plugin or extension on the [AlliedModders forums](https://forums.alliedmods.net/forumdisplay.php?f=52).
|
||||
|
||||
#### Details, details, details
|
||||
Provide as much detail as possible when reporting an issue.
|
||||
|
||||
For bugs or other undesired behavior, answers to the following questions are a great start:
|
||||
* What is the issue?
|
||||
* What behavior are you expecting instead?
|
||||
* On what operating system is the game server running?
|
||||
* What game is the game server running?
|
||||
* What exact version (full x.y.z.a version number) of Metamod:Source and SourceMod are installed on the game server?
|
||||
* What is the specific, shortest path to reproducing this issue? If this issue can be reproduced with plugin code, please try to shorten it to the minimum required to trigger the problem.
|
||||
|
||||
If this is a feature request, the following are helpful. Generally, not all will apply, but whatever you can answer ahead of time will shorten back and forth conversation.
|
||||
* What is your end goal, or what are you trying to accomplish?
|
||||
* Why is this necessary, or what benefit do you see with it?
|
||||
* Will this be useful to others?
|
||||
|
||||
#### Issues with security implications
|
||||
Please report any security bugs to [[email protected]](mailto:[email protected]) rather than to this public issue tracker.
|
||||
|
||||
#### We're only human
|
||||
Please keep in mind that we maintain this project in our spare time, at no cost. There is no SLA, and you are not owed a response or a fix.
|
||||
|
||||
#### Conduct
|
||||
Please refer to the [AlliedModders forum rules.](https://forums.alliedmods.net/misc.php?do=showrules)
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Firstly, thank you for considering contributing changes to the project!
|
||||
|
||||
However, if this is anything more than a small fix such as a gamedata update, a glaring code flaw, or a simple typo in a file like this one, please file an issue first so that it can be discussed, unless you have already spoken to multiple members of the development team about it on IRC or the AlliedModders forums.
|
||||
|
||||
We don't like to have to reject pull requests, so we want to avoid those scenarios. We wouldn't want you to feel like you wasted your time writing something only for us to shoot it down.
|
||||
|
||||
#### Rejection
|
||||
*Copied from Phabricator's [Contributing Code guidelines](https://secure.phabricator.com/book/phabcontrib/article/contributing_code/#rejecting-patches), as we largely feel the same way about this.*
|
||||
|
||||
> If you send us a patch without coordinating it with us first, it will probably be immediately rejected, or sit in limbo for a long time and eventually be rejected. The reasons we do this vary from patch to patch, but some of the most common reasons are:
|
||||
>
|
||||
> **Unjustifiable Costs**: We support code in the upstream forever. Support is enormously expensive and takes up a huge amount of our time. The cost to support a change over its lifetime is often 10x or 100x or 1000x greater than the cost to write the first version of it. Many uncoordinated patches we receive are "white elephants", which would cost much more to maintain than the value they provide.
|
||||
>
|
||||
> As an author, it may look like you're giving us free work and we're rejecting it as too expensive, but this viewpoint doesn't align with the reality of a large project which is actively supported by a small, experienced team. Writing code is cheap; maintaining it is expensive.
|
||||
>
|
||||
> By coordinating with us first, you can make sure the patch is something we consider valuable enough to put long-term support resources behind, and that you're building it in a way that we're comfortable taking over.
|
||||
>
|
||||
> **Not a Good Fit**: Many patches aren't good fits for the upstream: they implement features we simply don't want. You can find more information in Contributing Feature Requests. Coordinating with us first helps make sure we're on the same page and interested in a feature.
|
||||
>
|
||||
> The most common type of patch along these lines is a patch which adds new configuration options. We consider additional configuration options to have an exceptionally high lifetime support cost and are very unlikely to accept them. Coordinate with us first.
|
||||
>
|
||||
> **Not a Priority**: If you send us a patch against something which isn't a priority, we probably won't have time to look at it. We don't give special treatment to low-priority issues just because there's code written: we'd still be spending time on something lower-priority when we could be spending it on something higher-priority instead.
|
||||
>
|
||||
> If you coordinate with us first, you can make sure your patch is in an area of the codebase that we can prioritize.
|
||||
>
|
||||
> **Overly Ambitious Patches**: Sometimes we'll get huge patches from new contributors. These can have a lot of fundamental problems and require a huge amount of our time to review and correct. If you're interested in contributing, you'll have more success if you start small and learn as you go.
|
||||
>
|
||||
> We can help you break a large change into smaller pieces and learn how the codebase works as you proceed through the implementation, but only if you coordinate with us first.
|
||||
>
|
||||
> **Generality**: We often receive several feature requests which ask for similar features, and can come up with a general approach which covers all of the use cases. If you send us a patch for your use case only, the approach may be too specific. When a cleaner and more general approach is available, we usually prefer to pursue it.
|
||||
>
|
||||
> By coordinating with us first, we can make you aware of similar use cases and opportunities to generalize an approach. These changes are often small, but can have a big impact on how useful a piece of code is.
|
||||
>
|
||||
> **Infrastructure and Sequencing**: Sometimes patches are written against a piece of infrastructure with major planned changes. We don't want to accept these because they'll make the infrastructure changes more difficult to implement.
|
||||
>
|
||||
> Coordinate with us first to make sure a change doesn't need to wait on other pieces of infrastructure. We can help you identify technical blockers and possibly guide you through resolving them if you're interested.
|
||||
@@ -1,8 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
custom: https://www.sourcemod.net/donate.php
|
||||
@@ -1,26 +0,0 @@
|
||||
# Help us help you
|
||||
- [ ] I have checked that my issue [doesn't exist yet](https://github.com/alliedmodders/sourcemod/issues).
|
||||
- [ ] I have tried my absolute best to reduce the problem-space and have provided the absolute smallest test-case possible.
|
||||
- [ ] I can always reproduce the issue with the provided description below.
|
||||
|
||||
# Environment
|
||||
* Operating System version:
|
||||
* Game/AppID (with version if applicable):
|
||||
* Current SourceMod version:
|
||||
* Current SourceMod snapshot:
|
||||
* Current Metamod: Source snapshot:
|
||||
- [ ] I have updated SourceMod to the [latest version](https://www.sourcemod.net/downloads.php) and it still happens.
|
||||
- [ ] I have updated SourceMod to the [latest snapshot](https://www.sourcemod.net/downloads.php?branch=dev) and it still happens.
|
||||
- [ ] I have updated SourceMM to the [latest snapshot](https://sourcemm.net/downloads.php?branch=dev) and it still happens.
|
||||
|
||||
# Description
|
||||
|
||||
|
||||
# Problematic Code (or Steps to Reproduce)
|
||||
```
|
||||
// TODO(you): code here to reproduce the problem
|
||||
```
|
||||
|
||||
# Logs
|
||||
* Please attach in separate files: game output, library logs, kernel logs, and any other supporting information.
|
||||
* In case of a crash, please attach minidump or dump analyze output.
|
||||
@@ -1,8 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
# Check for updates to GitHub Actions every week
|
||||
interval: "weekly"
|
||||
@@ -1,98 +0,0 @@
|
||||
name: Continuous Integration
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-latest, windows-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
compiler_cc: msvc
|
||||
- os: ubuntu-latest
|
||||
os_short: linux
|
||||
compiler_cc: clang
|
||||
compiler_cxx: clang++
|
||||
- os: ubuntu-20.04
|
||||
os_short: linux
|
||||
compiler_cc: clang-8
|
||||
compiler_cxx: clang++-8
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: ${{ matrix.os_short }}-${{ matrix.compiler_cc }}
|
||||
env:
|
||||
SDKS: '["episode1","css","tf2","l4d2","csgo"]'
|
||||
ARCH: x86,x86_64
|
||||
DEPENDENCIES_FOLDER: dependencies
|
||||
DEPENDENCIES_ROOT: ${{ github.workspace }}/dependencies
|
||||
MYSQL_VERSION: '5.5'
|
||||
MMSOURCE_VERSION: '1.12'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
path: sourcemod
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: hl2sdk-mysql-mmsource
|
||||
with:
|
||||
path: ${{ env.DEPENDENCIES_ROOT }}
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-${{ join(fromJSON(env.SDKS), '') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-
|
||||
|
||||
# Setup Python for AMBuild
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.8
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ${{ env.DEPENDENCIES_FOLDER }}
|
||||
cd ${{ env.DEPENDENCIES_FOLDER }}
|
||||
|
||||
# Satisfy checkout-deps requirement for a "sourcemod" folder.
|
||||
mkdir -p sourcemod
|
||||
../sourcemod/tools/checkout-deps.sh -s ${{ join(fromJSON(env.SDKS)) }}
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||
|
||||
- name: Select clang compiler
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
echo "CC=${{ matrix.compiler_cc }}" >> $GITHUB_ENV
|
||||
echo "CXX=${{ matrix.compiler_cxx }}" >> $GITHUB_ENV
|
||||
${{ matrix.compiler_cc }} --version
|
||||
${{ matrix.compiler_cxx }} --version
|
||||
|
||||
- name: Build
|
||||
working-directory: sourcemod
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
python ../configure.py --enable-optimize --sdks=${{ join(fromJSON(env.SDKS)) }} --targets=${{ env.ARCH }} --mms-path=${{ env.DEPENDENCIES_ROOT }}/mmsource-${{ env.MMSOURCE_VERSION }} --hl2sdk-root=${{ env.DEPENDENCIES_ROOT }} --mysql-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }} --mysql64-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }}-x86_64
|
||||
ambuild
|
||||
@@ -1,104 +0,0 @@
|
||||
name: hl2sdk-mock tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
jobs:
|
||||
mock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
name: Clone sourcemod
|
||||
with:
|
||||
submodules: recursive
|
||||
path: sourcemod
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
name: Clone metamod-source
|
||||
with:
|
||||
repository: alliedmodders/metamod-source
|
||||
submodules: recursive
|
||||
path: metamod-source
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
name: Clone hl2sdk-mock
|
||||
with:
|
||||
repository: alliedmodders/hl2sdk-mock
|
||||
submodules: recursive
|
||||
path: hl2sdk-mock
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.10
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install AMBuild
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install git+https://github.com/alliedmodders/ambuild
|
||||
|
||||
- name: Build MetaMod:Source
|
||||
working-directory: metamod-source
|
||||
run: |
|
||||
python configure.py --enable-optimize --sdks=mock --targets=x86_64
|
||||
ambuild objdir
|
||||
|
||||
- name: Build SourceMod
|
||||
working-directory: sourcemod
|
||||
run: |
|
||||
python configure.py --no-mysql --enable-optimize --sdks=mock --targets=x86_64
|
||||
ambuild objdir
|
||||
|
||||
- name: Build hl2sdk-mock
|
||||
working-directory: hl2sdk-mock
|
||||
run: |
|
||||
python configure.py --enable-optimize --targets=x86_64
|
||||
ambuild objdir
|
||||
|
||||
- name: Setup gamedir
|
||||
working-directory: hl2sdk-mock
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir ../gamedir
|
||||
./build_gamedir.sh ../gamedir ../metamod-source/objdir/package
|
||||
./build_gamedir.sh ../gamedir ../sourcemod/objdir/package
|
||||
|
||||
- name: Compile testsuite
|
||||
working-directory: hl2sdk-mock
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir ../gamedir/addons/sourcemod/plugins/optional
|
||||
|
||||
for f in ../sourcemod/plugins/testsuite/mock/*.sp; do
|
||||
echo "Compiling $(basename $f)"
|
||||
../gamedir/addons/sourcemod/scripting/spcomp64 -i ../gamedir/addons/sourcemod/scripting/include -o "../gamedir/addons/sourcemod/plugins/optional/$(basename $f .sp).smx" -E "$f"
|
||||
done
|
||||
|
||||
- name: Test
|
||||
working-directory: hl2sdk-mock
|
||||
shell: bash
|
||||
run: |
|
||||
for f in ../gamedir/addons/sourcemod/plugins/optional/*.smx; do
|
||||
echo "==================================="
|
||||
echo "Running $(basename $f)..."
|
||||
echo "==================================="
|
||||
timeout 60 ./objdir/dist/x86_64/srcds -game_dir ../gamedir +map de_thunder -command "sm plugins load optional/$(basename $f)" -run -run-ticks 20 |
|
||||
{
|
||||
failed=0
|
||||
while IFS= read -r line; do
|
||||
echo "$line"
|
||||
if [[ "$line" == *"FAIL"* ]]; then
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
if [ "$failed" = "1" ]; then
|
||||
echo "$(basename $f) failed."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
done
|
||||
@@ -1,79 +0,0 @@
|
||||
name: SourcePawn scripting
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
paths:
|
||||
- 'plugins/include/*'
|
||||
- 'sourcepawn/**'
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '53 05 01 */3 *' # Artifacts expire every 3 months
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
os_short: linux
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
- os: macos-latest
|
||||
os_short: mac
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
ARCH: x86,x86_64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
# Setup Python for AMBuild
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.8
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install AMBuild
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install git+https://github.com/alliedmodders/ambuild
|
||||
|
||||
- name: Build universal x64/arm64 on macOS
|
||||
if: startsWith(runner.os, 'macOS')
|
||||
run: echo "ARCH=x86_64,arm64" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||
|
||||
- name: Select clang compiler
|
||||
if: startsWith(runner.os, 'Linux') || startsWith(runner.os, 'macOS')
|
||||
run: |
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "CXX=clang++" >> $GITHUB_ENV
|
||||
clang --version
|
||||
clang++ --version
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
python ../configure.py --enable-optimize --scripting-only --targets=${{ env.ARCH }}
|
||||
ambuild
|
||||
echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV
|
||||
|
||||
- name: Archive tooling
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
|
||||
path: build/package
|
||||
@@ -1,42 +0,0 @@
|
||||
name: Update translation project
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'translations/**'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
update_translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.10
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install Python dependencies
|
||||
working-directory: tools/language_check
|
||||
run: |
|
||||
python -m pip install --upgrade -r requirements.txt
|
||||
|
||||
- name: Generate token
|
||||
id: generate_token
|
||||
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
|
||||
with:
|
||||
app_id: ${{ secrets.APP_ID }}
|
||||
private_key: ${{ secrets.APP_PEM }}
|
||||
|
||||
- name: Update translation project
|
||||
working-directory: tools/language_check
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
ORGANIZATION: alliedmodders
|
||||
PROJECT_NUMBER: 1
|
||||
run: |
|
||||
python ./compare_translation_phrases.py
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Sanity check translation phrases
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'translations/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'translations/**'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
check_translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.10
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Check translation phrases syntax
|
||||
working-directory: tools/language_check
|
||||
run: |
|
||||
python ./sanity_check.py
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
# Binaries
|
||||
*.dll
|
||||
*.dylib
|
||||
*.exe
|
||||
*.so
|
||||
|
||||
# Files generated by Visual Studio
|
||||
*.aps
|
||||
*.ipch
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.suo
|
||||
*.user
|
||||
|
||||
# Build directories
|
||||
CrazyDebug*/
|
||||
Debug*/
|
||||
Release*/
|
||||
LIB-Release/
|
||||
LIB-Debug/
|
||||
|
||||
# Files generated by Mac OS X Finder
|
||||
.DS_Store
|
||||
|
||||
# Files generated by Windows Explorer
|
||||
[Dd]esktop.ini
|
||||
[Tt]humbs.db
|
||||
|
||||
# AMBuild build directories
|
||||
obj-*/
|
||||
*~
|
||||
*.rej
|
||||
*.orig
|
||||
*.smx
|
||||
*.swp
|
||||
*.gdb_history
|
||||
objdir
|
||||
# Not standardized, but common name for build directories
|
||||
build*/
|
||||
|
||||
.vs/*
|
||||
.vscode/*
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
[submodule "public/amtl"]
|
||||
path = public/amtl
|
||||
url = https://github.com/alliedmodders/amtl
|
||||
shallow = true
|
||||
[submodule "sourcepawn"]
|
||||
path = sourcepawn
|
||||
url = https://github.com/alliedmodders/sourcepawn
|
||||
shallow = true
|
||||
[submodule "hl2sdk-manifests"]
|
||||
path = hl2sdk-manifests
|
||||
url = https://github.com/alliedmodders/hl2sdk-manifests.git
|
||||
[submodule "public/safetyhook"]
|
||||
path = public/safetyhook
|
||||
url = https://github.com/alliedmodders/safetyhook
|
||||
@@ -0,0 +1,15 @@
|
||||
# Binaries
|
||||
\.dll$
|
||||
\.exe$
|
||||
\.so$
|
||||
|
||||
# Files generated by Visual Studio
|
||||
\.aps$
|
||||
\.ncb$
|
||||
\.suo$
|
||||
\.user$
|
||||
|
||||
# Build directories
|
||||
/CrazyDebug.*
|
||||
/Debug.*
|
||||
/Release.*
|
||||
@@ -0,0 +1,8 @@
|
||||
54539fa4e51f98d7841c853c1370dff6ccd3cdf2 sourcemod-1.0.0
|
||||
e6ef5ecdf8d75740ca2685a709bf321f8873bc3b sourcemod-1.1.0
|
||||
e877885fac80be71822641f7a9122cebc9812521 sourcemod-1.1.1
|
||||
b3ffa8a4511c4eadaf533fc790aa6b14f7f0c6ea sourcemod-1.1.2
|
||||
3a73bbf60f34befa9b66be03fa5974b394bb3411 sourcemod-1.2.0
|
||||
3c30a59c2296a13284a9f4eb42863b47db645adf sourcemod-1.2.1
|
||||
f55c735efeefe68863b96713fcd55a7774d8ceab sourcemod-1.2.2
|
||||
236a032c2a4da8f0af24b56b0539b1c574379be8 sourcemod-1.2.3
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
language: cpp
|
||||
os: linux
|
||||
dist: xenial
|
||||
|
||||
jobs:
|
||||
fast_finish: true
|
||||
include:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
language: cpp
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip']
|
||||
env:
|
||||
- MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||
- MODE=optimize
|
||||
- ARCH=x86,x86_64
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
language: cpp
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages: ['clang-3.4', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip']
|
||||
env:
|
||||
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||
- MODE=optimize
|
||||
- ARCH=x86,x86_64
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7.2
|
||||
language: cpp
|
||||
env:
|
||||
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||
- MODE=optimize
|
||||
- ARCH=x86_64,x86
|
||||
|
||||
# # This is a faster test for the latest g++.
|
||||
# - os: linux
|
||||
# dist: bionic
|
||||
# sudo: false
|
||||
# language: cpp
|
||||
# addons:
|
||||
# apt:
|
||||
# packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'g++']
|
||||
# cache:
|
||||
# directories: ['../mysql-5.0']
|
||||
# env:
|
||||
# - MATRIX_EVAL="CC=gcc && CXX=g++"
|
||||
# - SDKS=csgo
|
||||
# # GCC currently fails in opt builds trying to inline stuff in sqlite3.c.
|
||||
# - MODE=debug
|
||||
|
||||
# This is a faster test for the latest clang.
|
||||
- os: linux
|
||||
dist: bionic
|
||||
language: cpp
|
||||
addons:
|
||||
apt:
|
||||
packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'clang']
|
||||
env:
|
||||
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||
- SDKS=csgo
|
||||
- MODE=optimize
|
||||
- ARCH=x86
|
||||
|
||||
before_script:
|
||||
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh -s ${SDKS} && cd $CHECKOUT_DIR
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- PATH="~/.local/bin:$PATH"
|
||||
- eval "${MATRIX_EVAL}"
|
||||
- eval "${CC} --version"
|
||||
- eval "${CXX} --version"
|
||||
- python3 ../configure.py --enable-${MODE} --sdks=${SDKS} --targets=${ARCH}
|
||||
- ambuild
|
||||
+288
-685
@@ -1,685 +1,288 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import collections
|
||||
import os, sys
|
||||
import subprocess
|
||||
|
||||
def ResolveEnvPath(env, folder):
|
||||
if env in os.environ:
|
||||
path = os.environ[env]
|
||||
if os.path.isdir(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
head = os.getcwd()
|
||||
oldhead = None
|
||||
while head != None and head != oldhead:
|
||||
path = os.path.join(head, folder)
|
||||
if os.path.isdir(path):
|
||||
return path
|
||||
oldhead = head
|
||||
head, tail = os.path.split(head)
|
||||
|
||||
return None
|
||||
|
||||
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']
|
||||
|
||||
SdkHelpers = builder.Eval('hl2sdk-manifests/SdkHelpers.ambuild', {
|
||||
'Project': 'sourcemod'
|
||||
})
|
||||
|
||||
class SMConfig(object):
|
||||
def __init__(self):
|
||||
self.sdk_manifests = []
|
||||
self.sdks = {}
|
||||
self.sdk_targets = []
|
||||
self.binaries = []
|
||||
self.spvm = []
|
||||
self.extensions = []
|
||||
self.generated_headers = None
|
||||
self.mms_root = None
|
||||
self.mysql_root = {}
|
||||
self.spcomp = None
|
||||
self.spcomp_bins = []
|
||||
self.smx_files = {}
|
||||
self.versionlib = None
|
||||
self.all_targets = []
|
||||
self.target_archs = set()
|
||||
self.enable_asan = getattr(builder.options, 'enable_asan', False)
|
||||
self.asan_libs = {}
|
||||
self.libsafetyhook = {}
|
||||
|
||||
if builder.options.targets:
|
||||
target_archs = builder.options.targets.split(',')
|
||||
else:
|
||||
target_archs = ['x86']
|
||||
if builder.backend != 'amb2':
|
||||
target_archs.append('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.')
|
||||
|
||||
def use_auto_versioning(self):
|
||||
if builder.backend != 'amb2':
|
||||
return False
|
||||
return not getattr(builder.options, 'disable_auto_versioning', False)
|
||||
|
||||
@property
|
||||
def tag(self):
|
||||
if builder.options.debug == '1':
|
||||
return 'Debug'
|
||||
return 'Release'
|
||||
|
||||
def detectProductVersion(self):
|
||||
builder.AddConfigureFile('product.version')
|
||||
|
||||
# For OS X dylib versioning
|
||||
import re
|
||||
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
||||
productContents = fp.read()
|
||||
m = re.match(r'(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||
if m == None:
|
||||
self.productVersion = '1.0.0'
|
||||
else:
|
||||
major, minor, release = m.groups()
|
||||
self.productVersion = '{0}.{1}.{2}'.format(major, minor, 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 = [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)
|
||||
|
||||
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('MMSOURCE112', 'mmsource-1.12')
|
||||
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')
|
||||
|
||||
if not self.mms_root or not os.path.isdir(self.mms_root):
|
||||
raise Exception('Could not find a source copy of Metamod:Source')
|
||||
self.mms_root = Normalize(self.mms_root)
|
||||
|
||||
if builder.options.hasMySql:
|
||||
if 'x86' in self.target_archs:
|
||||
if builder.options.mysql_path:
|
||||
self.mysql_root['x86'] = builder.options.mysql_path
|
||||
else:
|
||||
for i in range(10):
|
||||
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
|
||||
if self.mysql_root['x86']:
|
||||
break
|
||||
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
|
||||
raise Exception('Could not find a path to MySQL. Configure with --no-mysql to disable it.')
|
||||
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
|
||||
|
||||
if 'x86_64' in self.target_archs:
|
||||
if builder.options.mysql64_path:
|
||||
self.mysql_root['x86_64'] = builder.options.mysql64_path
|
||||
else:
|
||||
for i in range(10):
|
||||
self.mysql_root['x86_64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
|
||||
if self.mysql_root['x86_64']:
|
||||
break
|
||||
if not self.mysql_root['x86_64'] or not os.path.isdir(self.mysql_root['x86_64']):
|
||||
raise Exception('Could not find a path to 64-bit MySQL!')
|
||||
self.mysql_root['x86_64'] = Normalize(self.mysql_root['x86_64'])
|
||||
|
||||
def configure(self):
|
||||
builder.AddConfigureFile('pushbuild.txt')
|
||||
|
||||
allowed_archs = ['x86_64']
|
||||
if builder.host.platform == 'mac':
|
||||
if getattr(builder.options, 'scripting_only', False):
|
||||
allowed_archs += ['arm64']
|
||||
else:
|
||||
allowed_archs += ['x86']
|
||||
|
||||
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 < 1914 and builder.options.generator != 'vs':
|
||||
raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
|
||||
elif cxx.family == 'gcc':
|
||||
if cxx.version < 'gcc-9':
|
||||
raise Exception('Only GCC versions 9 or later are supported, full C++17 support is required.')
|
||||
elif cxx.family == 'clang':
|
||||
if cxx.version < 'clang-5':
|
||||
raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.')
|
||||
|
||||
if cxx.like('gcc'):
|
||||
self.configure_gcc(cxx)
|
||||
elif cxx.family == 'msvc':
|
||||
self.configure_msvc(cxx)
|
||||
|
||||
# Optimizaiton
|
||||
if builder.options.opt == '1':
|
||||
cxx.defines += ['NDEBUG']
|
||||
|
||||
# Debugging
|
||||
if builder.options.debug == '1':
|
||||
cxx.defines += ['DEBUG', '_DEBUG']
|
||||
|
||||
# Platform-specifics
|
||||
if cxx.target.platform == 'linux':
|
||||
self.configure_linux(cxx)
|
||||
elif cxx.target.platform == 'mac':
|
||||
self.configure_mac(cxx)
|
||||
elif cxx.target.platform == 'windows':
|
||||
self.configure_windows(cxx)
|
||||
|
||||
# Finish up.
|
||||
cxx.defines += [
|
||||
'SOURCEMOD_BUILD',
|
||||
'SM_USE_VERSIONLIB',
|
||||
]
|
||||
cxx.includes += [
|
||||
os.path.join(builder.sourcePath, 'public'),
|
||||
]
|
||||
if self.use_auto_versioning():
|
||||
cxx.defines += ['SM_GENERATED_BUILD']
|
||||
cxx.includes += [
|
||||
os.path.join(builder.buildPath, 'includes'),
|
||||
os.path.join(builder.sourcePath, 'versionlib'),
|
||||
]
|
||||
|
||||
def configure_gcc(self, cxx):
|
||||
cxx.defines += [
|
||||
'stricmp=strcasecmp',
|
||||
'_stricmp=strcasecmp',
|
||||
'_snprintf=snprintf',
|
||||
'_vsnprintf=vsnprintf',
|
||||
'HAVE_STDINT_H',
|
||||
'GNUC',
|
||||
]
|
||||
cxx.cflags += [
|
||||
'-pipe',
|
||||
'-fno-strict-aliasing',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-Wno-unused',
|
||||
'-Wno-switch',
|
||||
'-Wno-array-bounds',
|
||||
'-fvisibility=hidden',
|
||||
]
|
||||
if cxx.target.arch in ['x86', 'x86_64']:
|
||||
cxx.cflags += ['-msse']
|
||||
|
||||
cxx.cxxflags += ['-std=c++17']
|
||||
|
||||
cxx.cxxflags += [
|
||||
'-fno-threadsafe-statics',
|
||||
'-Wno-non-virtual-dtor',
|
||||
'-Wno-overloaded-virtual',
|
||||
'-Wno-register',
|
||||
'-fvisibility-inlines-hidden',
|
||||
]
|
||||
|
||||
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.9' or cxx.version == 'apple-clang-8.0':
|
||||
cxx.cflags += ['-Wno-varargs']
|
||||
if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0':
|
||||
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
||||
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
||||
cxx.cxxflags += ['-Wno-null-dereference']
|
||||
if have_clang or (cxx.version >= 'gcc-4.6'):
|
||||
cxx.cflags += ['-Wno-narrowing']
|
||||
if have_clang or (cxx.version >= 'gcc-4.7'):
|
||||
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
|
||||
if cxx.version >= 'gcc-4.8':
|
||||
cxx.cflags += ['-Wno-unused-result']
|
||||
if cxx.version >= 'gcc-9.0':
|
||||
cxx.cxxflags += ['-Wno-class-memaccess', '-Wno-packed-not-aligned']
|
||||
if have_clang:
|
||||
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
|
||||
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
|
||||
cxx.cxxflags += ['-Wno-deprecated-register']
|
||||
else:
|
||||
cxx.cxxflags += ['-Wno-deprecated']
|
||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||
|
||||
if self.enable_asan:
|
||||
if not have_clang:
|
||||
raise Exception('--enable-asan only supported when using Clang')
|
||||
self.configure_asan(cxx)
|
||||
|
||||
# Work around SDK warnings.
|
||||
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 have_gcc:
|
||||
cxx.cflags += ['-mfpmath=sse']
|
||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||
|
||||
if builder.options.opt == '1':
|
||||
if self.enable_asan:
|
||||
cxx.cflags += ['-O1']
|
||||
else:
|
||||
cxx.cflags += ['-O3']
|
||||
|
||||
# Don't omit the frame pointer.
|
||||
cxx.cflags += ['-fno-omit-frame-pointer']
|
||||
|
||||
def configure_msvc(self, cxx):
|
||||
if self.enable_asan:
|
||||
raise Exception('--enable-asan only supported when using Clang')
|
||||
|
||||
if builder.options.debug == '1':
|
||||
cxx.cflags += ['/MTd']
|
||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||
else:
|
||||
cxx.cflags += ['/MT']
|
||||
cxx.defines += [
|
||||
'_CRT_SECURE_NO_DEPRECATE',
|
||||
'_CRT_SECURE_NO_WARNINGS',
|
||||
'_CRT_NONSTDC_NO_DEPRECATE',
|
||||
'_ITERATOR_DEBUG_LEVEL=0',
|
||||
]
|
||||
cxx.cflags += [
|
||||
'/W3',
|
||||
]
|
||||
cxx.cxxflags += [
|
||||
'/EHsc',
|
||||
'/GR-',
|
||||
'/TP',
|
||||
'/std:c++17',
|
||||
]
|
||||
cxx.linkflags += [
|
||||
'kernel32.lib',
|
||||
'user32.lib',
|
||||
'gdi32.lib',
|
||||
'winspool.lib',
|
||||
'comdlg32.lib',
|
||||
'advapi32.lib',
|
||||
'shell32.lib',
|
||||
'ole32.lib',
|
||||
'oleaut32.lib',
|
||||
'uuid.lib',
|
||||
'odbc32.lib',
|
||||
'odbccp32.lib',
|
||||
]
|
||||
|
||||
if builder.options.opt == '1':
|
||||
cxx.cflags += ['/Ox', '/Zo']
|
||||
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
|
||||
|
||||
if builder.options.debug == '1':
|
||||
cxx.cflags += ['/Od', '/RTC1']
|
||||
|
||||
# This needs to be after our optimization flags which could otherwise disable it.
|
||||
# Don't omit the frame pointer.
|
||||
cxx.cflags += ['/Oy-']
|
||||
|
||||
def configure_asan(self, cxx):
|
||||
if cxx.target.platform != 'linux':
|
||||
raise Exception('--enable-asan only supported on Linux')
|
||||
cxx.cflags += ['-fsanitize=address']
|
||||
cxx.linkflags += ['-fsanitize=address']
|
||||
if cxx.target.arch == 'x86':
|
||||
libclang_rt = 'libclang_rt.asan-i386.so'
|
||||
else:
|
||||
libclang_rt = 'libclang_rt.asan-x86_64.so'
|
||||
|
||||
try:
|
||||
argv = cxx.cxx_argv + ['--print-file-name', libclang_rt]
|
||||
output = subprocess.check_output(argv)
|
||||
output = output.decode('utf-8')
|
||||
output = output.strip()
|
||||
except:
|
||||
raise Exception('Could not find {}'.format(libclang_rt))
|
||||
|
||||
print('ASAN library for {}: {}'.format(cxx.target.arch, output))
|
||||
print('You will need to LD_PRELOAD this into srcds.')
|
||||
|
||||
self.asan_libs[cxx.target.arch] = os.path.dirname(output)
|
||||
|
||||
def configure_linux(self, cxx):
|
||||
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||
cxx.linkflags += ['-lm']
|
||||
if cxx.family == 'gcc':
|
||||
cxx.linkflags += ['-static-libgcc']
|
||||
elif cxx.family == 'clang':
|
||||
cxx.linkflags += ['-lgcc_eh']
|
||||
cxx.linkflags += ['-static-libstdc++']
|
||||
|
||||
def configure_mac(self, cxx):
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.15']
|
||||
cxx.linkflags += [
|
||||
'-mmacosx-version-min=10.15',
|
||||
'-stdlib=libc++',
|
||||
'-lc++',
|
||||
]
|
||||
cxx.cxxflags += ['-stdlib=libc++']
|
||||
|
||||
def configure_windows(self, cxx):
|
||||
cxx.defines += ['WIN32', '_WINDOWS']
|
||||
|
||||
def add_libamtl(self):
|
||||
# Add libamtl.
|
||||
self.libamtl = {}
|
||||
for cxx in self.all_targets:
|
||||
def get_configure_fn(cxx):
|
||||
return lambda builder, name: self.StaticLibrary(builder, cxx, name)
|
||||
extra_vars = {'Configure': get_configure_fn(cxx)}
|
||||
libamtl = builder.Build('public/amtl/amtl/AMBuilder', extra_vars)
|
||||
self.libamtl[cxx.target.arch] = libamtl.binary
|
||||
|
||||
def AddVersioning(self, binary):
|
||||
if binary.compiler.target.platform == 'windows':
|
||||
binary.sources += ['version.rc']
|
||||
binary.compiler.rcdefines += [
|
||||
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
||||
'RC_COMPILE',
|
||||
]
|
||||
if self.use_auto_versioning():
|
||||
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
||||
elif binary.compiler.target.platform == 'mac':
|
||||
if binary.type == 'library':
|
||||
binary.compiler.postlink += [
|
||||
'-compatibility_version', '1.0.0',
|
||||
'-current_version', self.productVersion
|
||||
]
|
||||
if self.use_auto_versioning():
|
||||
binary.compiler.postlink += [self.versionlib[binary.compiler.target.arch]]
|
||||
binary.compiler.sourcedeps += SM.generated_headers
|
||||
return binary
|
||||
|
||||
def LibraryBuilder(self, compiler, name):
|
||||
binary = compiler.Library(name)
|
||||
self.AddVersioning(binary)
|
||||
if binary.compiler.like('msvc'):
|
||||
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
||||
self.AddCxxCompat(binary)
|
||||
|
||||
# Dumb clang behavior means we have to manually find libclang_rt.
|
||||
if self.enable_asan:
|
||||
binary.compiler.linkflags += [
|
||||
'-shared-libsan',
|
||||
'-Wl,-rpath={}'.format(self.asan_libs[binary.compiler.target.arch]),
|
||||
]
|
||||
return binary
|
||||
|
||||
def ProgramBuilder(self, compiler, name):
|
||||
binary = compiler.Program(name)
|
||||
self.AddVersioning(binary)
|
||||
if '-static-libgcc' in binary.compiler.linkflags:
|
||||
binary.compiler.linkflags.remove('-static-libgcc')
|
||||
if self.enable_asan:
|
||||
binary.compiler.linkflags.append('-static-libsan')
|
||||
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 += [
|
||||
os.path.join(context.currentSourcePath),
|
||||
os.path.join(context.currentSourcePath, 'sdk'),
|
||||
os.path.join(builder.sourcePath, 'public', 'extensions'),
|
||||
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||
]
|
||||
return compiler
|
||||
|
||||
def ExtLibrary(self, context, compiler, name):
|
||||
binary = self.Library(context, compiler, name)
|
||||
SetArchFlags(compiler)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return binary
|
||||
|
||||
def AddCxxCompat(self, binary):
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.sources += [
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
|
||||
]
|
||||
|
||||
def ConfigureForHL2(self, context, binary, sdk):
|
||||
compiler = binary.compiler
|
||||
SetArchFlags(compiler)
|
||||
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(self.mms_root, 'core'),
|
||||
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||
]
|
||||
|
||||
for other_sdk in self.sdk_manifests:
|
||||
compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
|
||||
|
||||
SdkHelpers.configureCxx(context, binary, sdk)
|
||||
|
||||
return binary
|
||||
|
||||
def AddCDetour(self, binary):
|
||||
public_path = os.path.join(builder.sourcePath, 'public')
|
||||
binary.sources += [ os.path.join(public_path, 'CDetour', 'detours.cpp') ]
|
||||
binary.compiler.cxxincludes += [ os.path.join(public_path, 'safetyhook', 'include') ]
|
||||
|
||||
for task in self.libsafetyhook:
|
||||
if task.target.arch == binary.compiler.target.arch:
|
||||
binary.compiler.linkflags += [task.binary]
|
||||
return
|
||||
raise Exception('No suitable build of safetyhook was found.')
|
||||
|
||||
def HL2Library(self, context, compiler, name, sdk):
|
||||
binary = self.Library(context, compiler, name)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2Config(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||
self.AddCxxCompat(binary)
|
||||
self.AddVersioning(binary)
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2ExtConfig(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||
self.AddCxxCompat(binary)
|
||||
self.AddVersioning(binary)
|
||||
self.ConfigureForHL2(context, binary, sdk)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return binary
|
||||
|
||||
if getattr(builder, 'target', None) is not None:
|
||||
sys.stderr.write("Your output folder was configured for AMBuild 2.1, and SourceMod is now\n")
|
||||
sys.stderr.write("configured to use AMBuild 2.2. Please remove your output folder and\n")
|
||||
sys.stderr.write("reconfigure to continue.\n")
|
||||
os._exit(1)
|
||||
|
||||
SM = SMConfig()
|
||||
SM.detectProductVersion()
|
||||
if not getattr(builder.options, 'scripting_only', False):
|
||||
SM.detectSDKs()
|
||||
SM.configure()
|
||||
SM.add_libamtl()
|
||||
|
||||
# This will clone the list and each cxx object as we recurse, preventing child
|
||||
# scripts from messing up global state.
|
||||
builder.targets = builder.CloneableList(SM.all_targets)
|
||||
|
||||
if SM.use_auto_versioning():
|
||||
SM.generated_headers = builder.Build(
|
||||
'tools/buildbot/Versioning',
|
||||
{ 'SM': SM }
|
||||
)
|
||||
SM.versionlib = builder.Build(
|
||||
'versionlib/AMBuilder',
|
||||
{ 'SM': SM }
|
||||
)
|
||||
|
||||
class SafetyHookShim(object):
|
||||
def __init__(self):
|
||||
self.all_targets = {}
|
||||
self.libsafetyhook = {}
|
||||
|
||||
SafetyHook = SafetyHookShim()
|
||||
SafetyHook.all_targets = SM.all_targets
|
||||
builder.Build('public/safetyhook/AMBuilder', {'SafetyHook': SafetyHook })
|
||||
SM.libsafetyhook = SafetyHook.libsafetyhook
|
||||
|
||||
class SPRoot(object):
|
||||
def __init__(self):
|
||||
self.generated_headers = SM.generated_headers
|
||||
# SourcePawn's build scripts are always one-offs, and attach the current target
|
||||
# to the builder, so we have to provide a shim to our StaticLibrary() method.
|
||||
def StaticLibrary(self, builder, name):
|
||||
return SM.StaticLibrary(builder, builder.cxx, name)
|
||||
def Program(self, builder, name):
|
||||
return SM.Program(builder, builder.cxx, name)
|
||||
def Library(self, builder, name):
|
||||
return SM.Library(builder, builder.cxx, name)
|
||||
|
||||
@property
|
||||
def targets(self):
|
||||
return SM.all_targets
|
||||
|
||||
@property
|
||||
def libamtl(self):
|
||||
return SM.libamtl
|
||||
|
||||
SP_build_parts = ['core']
|
||||
if getattr(builder.options, 'scripting_only', False):
|
||||
SP_build_parts = ['spcomp']
|
||||
|
||||
# Build SourcePawn externally.
|
||||
SP = builder.Build('sourcepawn/AMBuildScript', {
|
||||
'external_root': SPRoot(),
|
||||
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||
'external_build': SP_build_parts,
|
||||
})
|
||||
|
||||
def IsBetterDefaultSpcomp(spcomp, other):
|
||||
if other is None:
|
||||
return True
|
||||
if spcomp.target.arch == 'universal':
|
||||
return True
|
||||
if other.target.arch == 'universal':
|
||||
return False
|
||||
return spcomp.target.arch == 'x86'
|
||||
|
||||
for spcomp in SP.spcomp:
|
||||
if IsBetterDefaultSpcomp(spcomp, SM.spcomp):
|
||||
SM.spcomp = spcomp
|
||||
SM.spcomp_bins.append(spcomp)
|
||||
|
||||
# If we have a universal binary, ignore all other spcomps.
|
||||
if SM.spcomp.target.arch == 'universal':
|
||||
SM.spcomp_bins = [SM.spcomp]
|
||||
|
||||
if not getattr(builder.options, 'scripting_only', False):
|
||||
for cxx in SM.all_targets:
|
||||
SM.spvm += [
|
||||
SP.libsourcepawn[cxx.target.arch]
|
||||
]
|
||||
|
||||
if getattr(builder.options, 'scripting_only', False):
|
||||
BuildScripts = [
|
||||
'tools/buildbot/PackageHelpers',
|
||||
'tools/buildbot/ToolsPackageScript',
|
||||
]
|
||||
else:
|
||||
BuildScripts = [
|
||||
'loader/AMBuilder',
|
||||
'core/AMBuilder',
|
||||
'core/logic/AMBuilder',
|
||||
'extensions/bintools/AMBuilder',
|
||||
'extensions/clientprefs/AMBuilder',
|
||||
'extensions/curl/AMBuilder',
|
||||
'extensions/cstrike/AMBuilder',
|
||||
'extensions/dhooks/AMBuilder',
|
||||
'extensions/geoip/AMBuilder',
|
||||
'extensions/mysql/AMBuilder',
|
||||
'extensions/pgsql/AMBuilder',
|
||||
'extensions/regex/AMBuilder',
|
||||
'extensions/sdkhooks/AMBuilder',
|
||||
'extensions/sdktools/AMBuilder',
|
||||
'extensions/sqlite/AMBuilder',
|
||||
'extensions/tf2/AMBuilder',
|
||||
'extensions/topmenus/AMBuilder',
|
||||
'extensions/updater/AMBuilder',
|
||||
]
|
||||
|
||||
if builder.backend == 'amb2':
|
||||
BuildScripts += [
|
||||
'plugins/AMBuilder',
|
||||
'tools/buildbot/PackageHelpers',
|
||||
'tools/buildbot/PackageScript',
|
||||
]
|
||||
|
||||
builder.Build(BuildScripts, { 'SM': SM })
|
||||
|
||||
if builder.options.breakpad_dump:
|
||||
builder.Build('tools/buildbot/BreakpadSymbols', { 'SM': SM })
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
import sys
|
||||
from ambuild.command import SymlinkCommand
|
||||
|
||||
class SM:
|
||||
def __init__(self):
|
||||
self.compiler = Cpp.Compiler()
|
||||
|
||||
#Build SDK info
|
||||
self.sdkInfo = { }
|
||||
self.sdkInfo['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
|
||||
'name': 'EPISODEONE'}
|
||||
self.sdkInfo['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
|
||||
'name': 'ORANGEBOX'}
|
||||
self.sdkInfo['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '4',
|
||||
'name': 'ORANGEBOXVALVE'}
|
||||
self.sdkInfo['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '5',
|
||||
'name': 'LEFT4DEAD'}
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
self.sdkInfo['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
|
||||
'name': 'DARKMESSIAH'}
|
||||
|
||||
if AMBuild.mode == 'config':
|
||||
#Detect compilers
|
||||
self.compiler.DetectAll(AMBuild)
|
||||
|
||||
#Detect variables
|
||||
envvars = { 'MMSOURCE17': 'mmsource-1.7',
|
||||
'HL2SDK': 'hl2sdk',
|
||||
'HL2SDKOB': 'hl2sdk-ob',
|
||||
'HL2SDKL4D': 'hl2sdk-l4d',
|
||||
'HL2SDKOBVALVE': 'hl2sdk-ob-valve',
|
||||
'MYSQL5': 'mysql-5.0'
|
||||
}
|
||||
|
||||
#Dark Messiah is Windows-only
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
envvars['HL2SDK-DARKM'] = 'hl2sdk-darkm'
|
||||
|
||||
#Must have a path for each envvar (file a bug if you don't like this)
|
||||
for i in envvars:
|
||||
if i in os.environ:
|
||||
path = os.environ[i]
|
||||
if not os.path.isdir(path):
|
||||
raise Exception('Path for {0} was not found: {1}'.format(i, path))
|
||||
else:
|
||||
head = os.getcwd()
|
||||
while head != None and head != '/':
|
||||
path = os.path.join(head, envvars[i])
|
||||
if os.path.isdir(path):
|
||||
break
|
||||
head, tail = os.path.split(head)
|
||||
if head == None or head == '/':
|
||||
raise Exception('Could not find a valid path for {0}'.format(i))
|
||||
AMBuild.cache.CacheVariable(i, path)
|
||||
|
||||
#Set up defines
|
||||
cxx = self.compiler.cxx
|
||||
if isinstance(cxx, Cpp.GCC):
|
||||
self.vendor = 'gcc'
|
||||
self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
|
||||
self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
|
||||
self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
|
||||
self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
|
||||
self.compiler.AddToListVar('CFLAGS', '-pipe')
|
||||
self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
|
||||
if cxx.majorVersion >= 4:
|
||||
self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wall')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Werror')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
|
||||
self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
|
||||
self.compiler.AddToListVar('CFLAGS', '-msse')
|
||||
self.compiler.AddToListVar('CFLAGS', '-m32')
|
||||
self.compiler.AddToListVar('CFLAGS', '-static-libgcc')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
|
||||
self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
|
||||
elif isinstance(cxx, Cpp.MSVC):
|
||||
self.vendor = 'msvc'
|
||||
if AMBuild.options.debug == '1':
|
||||
self.compiler.AddToListVar('CFLAGS', '/MTd')
|
||||
else:
|
||||
self.compiler.AddToListVar('CFLAGS', '/MT')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/GR-')
|
||||
self.compiler.AddToListVar('CFLAGS', '/W3')
|
||||
self.compiler.AddToListVar('CFLAGS', '/nologo')
|
||||
self.compiler.AddToListVar('CFLAGS', '/Zi')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/TP')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
|
||||
|
||||
#Optimization
|
||||
if AMBuild.options.opt == '1':
|
||||
self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
|
||||
if self.vendor == 'gcc':
|
||||
self.compiler.AddToListVar('CFLAGS', '-O3')
|
||||
elif self.vendor == 'msvc':
|
||||
self.compiler.AddToListVar('CFLAGS', '/Ot')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
|
||||
|
||||
#Debugging
|
||||
if AMBuild.options.debug == '1':
|
||||
self.compiler.AddToListVar('CDEFINES', 'DEBUG')
|
||||
self.compiler.AddToListVar('CDEFINES', '_DEBUG')
|
||||
if self.vendor == 'gcc':
|
||||
self.compiler.AddToListVar('CFLAGS', '-g3')
|
||||
elif self.vendor == 'msvc':
|
||||
self.compiler.AddToListVar('CFLAGS', '/Od')
|
||||
self.compiler.AddToListVar('CFLAGS', '/RTC1')
|
||||
|
||||
#Platform-specifics
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
self.compiler.AddToListVar('CDEFINES', '_LINUX')
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
self.compiler.AddToListVar('CDEFINES', 'WIN32')
|
||||
self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
|
||||
|
||||
#Finish up
|
||||
self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
|
||||
self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
|
||||
self.compiler.AddToListVar('CINCLUDES',
|
||||
os.path.join(AMBuild.outputFolder, 'includes'))
|
||||
self.compiler.ToConfig(AMBuild, 'compiler')
|
||||
AMBuild.cache.CacheVariable('vendor', self.vendor)
|
||||
self.targetMap = { }
|
||||
AMBuild.cache.CacheVariable('targetMap', self.targetMap)
|
||||
else:
|
||||
self.compiler.FromConfig(AMBuild, 'compiler')
|
||||
self.targetMap = AMBuild.cache['targetMap']
|
||||
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
|
||||
self.mmsPath = AMBuild.cache['MMSOURCE17']
|
||||
|
||||
def DefaultCompiler(self):
|
||||
return self.compiler.Clone()
|
||||
|
||||
def JobMatters(self, jobname):
|
||||
file = sys._getframe().f_code.co_filename
|
||||
if AMBuild.mode == 'config':
|
||||
self.targetMap[jobname] = file
|
||||
return True
|
||||
if len(AMBuild.args) == 0:
|
||||
return True
|
||||
if not jobname in AMBuild.args:
|
||||
return False
|
||||
|
||||
def DefaultExtCompiler(self, path):
|
||||
compiler = self.DefaultCompiler()
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
|
||||
return compiler
|
||||
|
||||
def AutoVersion(self, folder, binary):
|
||||
if AMBuild.target['platform'] != 'windows':
|
||||
return
|
||||
env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"']}
|
||||
binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
|
||||
|
||||
def PreSetupHL2Job(self, job, builder, sdk):
|
||||
info = self.sdkInfo[sdk]
|
||||
sdkPath = AMBuild.cache[info['sdk']]
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
if sdk == 'ep1':
|
||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
||||
else:
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
||||
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
|
||||
for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
|
||||
link = os.path.join(workFolder, i)
|
||||
target = os.path.join(staticLibs, i)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
for lib in ['tier0', 'tier1', 'vstdlib', 'mathlib']:
|
||||
libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
|
||||
builder.RebuildIfNewer(libPath)
|
||||
builder['POSTLINKFLAGS'].append(libPath)
|
||||
|
||||
def PostSetupHL2Job(self, job, builder, sdk):
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
|
||||
|
||||
def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
|
||||
compiler = self.DefaultExtCompiler(path)
|
||||
|
||||
mms = 'core'
|
||||
if sdk == 'ep1':
|
||||
mms += oldMms
|
||||
|
||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
|
||||
|
||||
info = self.sdkInfo
|
||||
compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
|
||||
compiler['CDEFINES'].append('SE_DARKMESSIAH=2')
|
||||
|
||||
paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
|
||||
['public', 'tier0'], ['public', 'tier1']]
|
||||
if sdk == 'ep1' or sdk == 'darkm':
|
||||
paths.append(['public', 'dlls'])
|
||||
else:
|
||||
paths.append(['public', 'game', 'server'])
|
||||
paths.append(['common'])
|
||||
|
||||
info = self.sdkInfo[sdk]
|
||||
sdkPath = AMBuild.cache[info['sdk']]
|
||||
|
||||
compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
|
||||
|
||||
if sdk == 'ep1':
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
||||
else:
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
||||
|
||||
for i in paths:
|
||||
compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
|
||||
|
||||
if not noLink:
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['-lm']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
|
||||
|
||||
return compiler
|
||||
|
||||
sm = SM()
|
||||
globals = {
|
||||
'SM': sm
|
||||
}
|
||||
|
||||
AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
|
||||
|
||||
FileList = [
|
||||
['loader', 'AMBuilder'],
|
||||
['core', 'AMBuilder'],
|
||||
['extensions', 'bintools', 'AMBuilder'],
|
||||
['extensions', 'clientprefs', 'AMBuilder'],
|
||||
['extensions', 'cstrike', 'AMBuilder'],
|
||||
['extensions', 'curl', 'AMBuilder'],
|
||||
['extensions', 'geoip', 'AMBuilder'],
|
||||
['extensions', 'mysql', 'AMBuilder'],
|
||||
['extensions', 'sdktools', 'AMBuilder'],
|
||||
['extensions', 'topmenus', 'AMBuilder'],
|
||||
['extensions', 'updater', 'AMBuilder'],
|
||||
['extensions', 'sqlite', 'AMBuilder'],
|
||||
['extensions', 'regex', 'AMBuilder'],
|
||||
['extensions', 'tf2', 'AMBuilder'],
|
||||
['sourcepawn', 'jit', 'AMBuilder'],
|
||||
['sourcepawn', 'compiler', 'AMBuilder'],
|
||||
['plugins', 'AMBuilder'],
|
||||
['tools', 'buildbot', 'PackageScript']
|
||||
]
|
||||
|
||||
for parts in FileList:
|
||||
AMBuild.Include(os.path.join(*parts), globals)
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
CONFIGURE YOUR IDENTITY FOR MERCURIAL!
|
||||
IF YOU ARE A DEVELOPER WITH PUSH ACCESS, DO IT NOW KPLZTHX.
|
||||
|
||||
http://wiki.alliedmods.net/Mercurial_Tutorial#Identity
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
SourceMod
|
||||
=========
|
||||
|
||||
General
|
||||
-------
|
||||
- [SourceMod website](http://www.sourcemod.net): Source Engine scripting and server administration
|
||||
- [Forum](https://forums.alliedmods.net/forumdisplay.php?f=52): Discussion forum including plugin/extension development
|
||||
- [General documentation](https://wiki.alliedmods.net/Category:SourceMod_Documentation): Miscellaneous information about SourceMod
|
||||
- [Stable builds](http://www.sourcemod.net/downloads.php?branch=stable): The latest stable SourceMod releases
|
||||
- [Dev builds](http://www.sourcemod.net/downloads.php?branch=dev): Builds of recent development versions
|
||||
|
||||
Development
|
||||
-----------
|
||||
- [Issue tracker](https://github.com/alliedmodders/sourcemod/issues): Issues that require back and forth communication
|
||||
- [Building SourceMod](https://wiki.alliedmods.net/Building_SourceMod): Instructions on how to build SourceMod itself using [AMBuild](https://github.com/alliedmodders/ambuild)
|
||||
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
|
||||
- [SourceMod plugin API](https://sm.alliedmods.net/new-api): Online SourceMod plugin API reference generated from the include files
|
||||
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
|
||||
- [Translation project](https://github.com/orgs/alliedmodders/projects/1): Help [translate SourceMod](https://wiki.alliedmods.net/Translations_(SourceMod_Scripting)) into your language
|
||||
|
||||
Contact
|
||||
-------
|
||||
- Connect with us on [GameSurge](https://gamesurge.net) IRC in #sourcemod
|
||||
- Alternatively feel free to join our [Discord](https://discord.gg/HgZctSS) server
|
||||
|
||||
License
|
||||
-------
|
||||
SourceMod is licensed under the GNU General Public License version 3. Special exceptions are outlined in the LICENSE.txt file inside of the licenses folder.
|
||||
@@ -1,17 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2015
|
||||
clone_folder: c:/projects/sourcemod
|
||||
clone_depth: 1
|
||||
install:
|
||||
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
|
||||
- cmd: git submodule update --init --recursive
|
||||
- cmd: git pull --recurse-submodules
|
||||
- cmd: cd ..
|
||||
- ps: sourcemod/tools/checkout-deps.ps1 -SDKs episode1,css,tf2,l4d2,csgo
|
||||
- cmd: cd sourcemod
|
||||
build_script:
|
||||
- cmd: call "%VS140COMNTOOLS%/vsvars32.bat"
|
||||
- cmd: mkdir build
|
||||
- cmd: cd build
|
||||
- cmd: python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
|
||||
- cmd: ambuild
|
||||
@@ -1,46 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_API_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_API_H_
|
||||
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/LogicProvider.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
// Add 1 to the RHS of this expression to bump the intercom file
|
||||
// This is to prevent mismatching core/logic binaries
|
||||
static const uint32_t SM_LOGIC_MAGIC = 0x0F47C0DE - 57;
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
typedef void (*LogicInitFunction)(SourceMod::CoreProvider *core, SourceMod::sm_logic_t *logic);
|
||||
typedef LogicInitFunction (*LogicLoadFunction)(uint32_t magic);
|
||||
typedef SourceMod::ITextParsers *(*GetITextParsers)();
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_API_H_
|
||||
@@ -1,139 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_PROVIDER_API_H_
|
||||
#define _INCLUDE_SOURCEMOD_CORE_PROVIDER_API_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <IAdminSystem.h>
|
||||
#include <amtl/am-function.h>
|
||||
|
||||
namespace SourcePawn {
|
||||
class ISourcePawnEngine;
|
||||
class ISourcePawnEngine2;
|
||||
} // namespace SourcePawn
|
||||
|
||||
// SDK types.
|
||||
#if defined(SM_LOGIC)
|
||||
class ConCommandBase {};
|
||||
class ConVar : public ConCommandBase {};
|
||||
#else
|
||||
class ConCommandBase;
|
||||
class ConVar;
|
||||
#endif
|
||||
class KeyValues;
|
||||
|
||||
struct ServerGlobals
|
||||
{
|
||||
const double *universalTime;
|
||||
float *interval_per_tick;
|
||||
float *frametime;
|
||||
};
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
class ISourceMod;
|
||||
class IVEngineServerBridge;
|
||||
class IFileSystemBridge;
|
||||
class ITimerSystem;
|
||||
class IPlayerManager;
|
||||
class IGameHelpers;
|
||||
class IMenuManager;
|
||||
struct DatabaseInfo;
|
||||
class IPlayerInfoBridge;
|
||||
class ICommandArgs;
|
||||
|
||||
typedef ke::Function<bool(int client, const ICommandArgs*)> CommandFunc;
|
||||
|
||||
class CoreProvider
|
||||
{
|
||||
public:
|
||||
/* Objects */
|
||||
ISourceMod *sm;
|
||||
IVEngineServerBridge *engine;
|
||||
IFileSystemBridge *filesystem;
|
||||
IPlayerInfoBridge *playerInfo;
|
||||
ITimerSystem *timersys;
|
||||
IPlayerManager *playerhelpers;
|
||||
IGameHelpers *gamehelpers;
|
||||
IMenuManager *menus;
|
||||
SourcePawn::ISourcePawnEngine **spe1;
|
||||
SourcePawn::ISourcePawnEngine2 **spe2;
|
||||
const char *gamesuffix;
|
||||
/* Data */
|
||||
ServerGlobals *serverGlobals;
|
||||
SMGlobalClass * listeners;
|
||||
|
||||
// ConVar functions.
|
||||
virtual ConVar *FindConVar(const char *name) = 0;
|
||||
virtual const char *GetCvarString(ConVar *cvar) = 0;
|
||||
virtual bool GetCvarBool(ConVar* cvar) = 0;
|
||||
|
||||
// Command functions.
|
||||
virtual void DefineCommand(const char *cmd, const char *help, const CommandFunc &callback) = 0;
|
||||
|
||||
// Game description functions.
|
||||
virtual bool GetGameName(char *buffer, size_t maxlength) = 0;
|
||||
virtual const char *GetGameDescription() = 0;
|
||||
virtual const char *GetSourceEngineName() = 0;
|
||||
virtual bool SymbolsAreHidden() = 0;
|
||||
|
||||
// Game state and helper functions.
|
||||
virtual bool IsMapLoading() = 0;
|
||||
virtual bool IsMapRunning() = 0;
|
||||
virtual int MaxClients() = 0;
|
||||
virtual bool DescribePlayer(int index, const char **namep, const char **authp, int *useridp) = 0;
|
||||
virtual void LogToGame(const char *message) = 0;
|
||||
virtual void ConPrint(const char *message) = 0;
|
||||
virtual void ConsolePrint(const char *fmt, ...) = 0;
|
||||
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0;
|
||||
|
||||
virtual void FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength) = 0;
|
||||
|
||||
// Game engine helper functions.
|
||||
virtual bool IsClientConVarQueryingSupported() = 0;
|
||||
virtual int QueryClientConVar(int client, const char *cvar) = 0;
|
||||
|
||||
// Metamod:Source functions.
|
||||
virtual int LoadMMSPlugin(const char *file, bool *ok, char *error, size_t maxlength) = 0;
|
||||
virtual void UnloadMMSPlugin(int id) = 0;
|
||||
|
||||
const char * (*GetCoreConfigValue)(const char*);
|
||||
void (*DoGlobalPluginLoads)();
|
||||
bool (*AreConfigsExecuted)();
|
||||
void (*ExecuteConfigs)(IPluginContext *ctx);
|
||||
void (*GetDBInfoFromKeyValues)(KeyValues *, DatabaseInfo *);
|
||||
int (*GetActivityFlags)();
|
||||
int (*GetImmunityMode)();
|
||||
void (*UpdateAdminCmdFlags)(const char *cmd, OverrideType type, FlagBits bits, bool remove);
|
||||
bool (*LookForCommandAdminFlags)(const char *cmd, FlagBits *pFlags);
|
||||
int (*GetGlobalTarget)();
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_CORE_PROVIDER_API_H_
|
||||
@@ -1,81 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_INCLUDE_IEXTBRIDGE_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IEXTBRIDGE_H_
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <IExtensionSys.h>
|
||||
#include <sh_vector.h>
|
||||
|
||||
struct edict_t;
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourcePawn;
|
||||
class SMPlugin;
|
||||
|
||||
class IExtensionSys : public IExtensionManager
|
||||
{
|
||||
public:
|
||||
virtual IExtension *LoadAutoExtension(const char *name, bool bErrorOnMissing=true) = 0;
|
||||
virtual void TryAutoload() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual IExtension *FindExtensionByFile(const char *name) = 0;
|
||||
virtual bool LibraryExists(const char *name) = 0;
|
||||
virtual void CallOnCoreMapStart(edict_t *edictList, int edictCount, int maxClients) = 0;
|
||||
virtual IExtension *GetExtensionFromIdent(IdentityToken_t *token) = 0;
|
||||
virtual void BindChildPlugin(IExtension *ext, SMPlugin *plugin) = 0;
|
||||
virtual void AddRawDependency(IExtension *myself, IdentityToken_t *token, void *iface) = 0;
|
||||
virtual const CVector<IExtension *> *ListExtensions() = 0;
|
||||
virtual void FreeExtensionList(const CVector<IExtension *> *list) = 0;
|
||||
virtual void CallOnCoreMapEnd() = 0;
|
||||
};
|
||||
|
||||
class AutoExtensionList
|
||||
{
|
||||
public:
|
||||
AutoExtensionList(IExtensionSys *extensions)
|
||||
: extensions_(extensions), list_(extensions_->ListExtensions())
|
||||
{
|
||||
}
|
||||
~AutoExtensionList()
|
||||
{
|
||||
extensions_->FreeExtensionList(list_);
|
||||
}
|
||||
const CVector<IExtension *> *operator ->()
|
||||
{
|
||||
return list_;
|
||||
}
|
||||
private:
|
||||
IExtensionSys *extensions_;
|
||||
const CVector<IExtension *> *list_;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IEXTBRIDGE_H_
|
||||
@@ -1,65 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_IFILESYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_IFILESYSTEM_H_
|
||||
|
||||
typedef void * FileHandle_t;
|
||||
typedef int FileFindHandle_t;
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
class IFileSystemBridge
|
||||
{
|
||||
public:
|
||||
virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0;
|
||||
virtual const char *FindNext(FileFindHandle_t handle) = 0;
|
||||
virtual bool FindIsDirectory(FileFindHandle_t handle) = 0;
|
||||
virtual void FindClose(FileFindHandle_t handle) = 0;
|
||||
virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0;
|
||||
virtual void Close(FileHandle_t file) = 0;
|
||||
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
|
||||
virtual bool EndOfFile(FileHandle_t file) = 0;
|
||||
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
|
||||
virtual unsigned int Size(FileHandle_t file) = 0;
|
||||
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
|
||||
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
|
||||
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
|
||||
virtual void Seek(FileHandle_t file, int post, int seekType) = 0;
|
||||
virtual unsigned int Tell(FileHandle_t file) = 0;
|
||||
virtual int FPrint(FileHandle_t file, const char *pData) = 0;
|
||||
virtual void Flush(FileHandle_t file) = 0;
|
||||
virtual bool IsOk(FileHandle_t file) = 0;
|
||||
virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0;
|
||||
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
|
||||
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
|
||||
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
|
||||
virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) = 0;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_IFILESYSTEM_H_
|
||||
@@ -1,43 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_LOGGER_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_LOGGER_H_
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
class ILogger
|
||||
{
|
||||
public:
|
||||
virtual void LogMessage(const char *msg, ...) = 0;
|
||||
virtual void LogError(const char *msg, ...) = 0;
|
||||
virtual void LogFatal(const char *msg, ...) = 0;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_LOGGER_H_
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_INCLUDE_IPLAYERINFO_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPLAYERINFO_H_
|
||||
|
||||
class IPlayerInfo;
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
class IPlayerInfoBridge
|
||||
{
|
||||
public:
|
||||
virtual bool IsObserver(IPlayerInfo *pInfo) = 0;
|
||||
virtual int GetTeamIndex(IPlayerInfo *pInfo) = 0;
|
||||
virtual int GetFragCount(IPlayerInfo *pInfo) = 0;
|
||||
virtual int GetDeathCount(IPlayerInfo *pInfo) = 0;
|
||||
virtual int GetArmorValue(IPlayerInfo *pInfo) = 0;
|
||||
virtual void GetAbsOrigin(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
|
||||
virtual void GetAbsAngles(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
|
||||
virtual void GetPlayerMins(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
|
||||
virtual void GetPlayerMaxs(IPlayerInfo *pInfo, float *x, float *y, float *z) = 0;
|
||||
virtual const char *GetWeaponName(IPlayerInfo *pInfo) = 0;
|
||||
virtual const char *GetModelName(IPlayerInfo *pInfo) = 0;
|
||||
virtual int GetHealth(IPlayerInfo *pInfo) = 0;
|
||||
virtual void ChangeTeam(IPlayerInfo *pInfo, int iTeamNum) = 0;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPLAYERINFO_H_
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_INCLUDE_IPROVIDERCALLBACK_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPROVIDERCALLBACK_H_
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
// Global callbacks provided to Core.
|
||||
class IProviderCallbacks
|
||||
{
|
||||
public:
|
||||
// Called when a log message is printed. Return true to supercede.
|
||||
virtual bool OnLogPrint(const char *msg) = 0;
|
||||
|
||||
// Called each frame tick.
|
||||
virtual void OnThink(bool simulating) = 0;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_IPROVIDERCALLBACK_H_
|
||||
@@ -1,112 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_INCLUDE_ISCRIPTMANAGER_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_ISCRIPTMANAGER_H_
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <sh_vector.h>
|
||||
#include <sh_string.h>
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourcePawn;
|
||||
|
||||
class IChangeableForward;
|
||||
|
||||
enum LibraryAction
|
||||
{
|
||||
LibraryAction_Removed,
|
||||
LibraryAction_Added
|
||||
};
|
||||
|
||||
struct AutoConfig
|
||||
{
|
||||
SourceHook::String autocfg;
|
||||
SourceHook::String folder;
|
||||
bool create;
|
||||
};
|
||||
|
||||
class SMPlugin : public IPlugin
|
||||
{
|
||||
public:
|
||||
virtual size_t GetConfigCount() = 0;
|
||||
virtual AutoConfig *GetConfig(size_t i) = 0;
|
||||
virtual void AddLibrary(const char *name) = 0;
|
||||
virtual void AddConfig(bool create, const char *cfg, const char *folder) = 0;
|
||||
virtual void EvictWithError(PluginStatus status, const char *fmt, ...) = 0;
|
||||
};
|
||||
|
||||
class IScriptManager
|
||||
{
|
||||
public:
|
||||
virtual void LoadAll(const char *config_path, const char *plugins_path) = 0;
|
||||
virtual void RefreshAll() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual IdentityToken_t *GetIdentity() = 0;
|
||||
virtual void SyncMaxClients(int maxClients) = 0;
|
||||
virtual void AddPluginsListener(IPluginsListener *listener) = 0;
|
||||
virtual void RemovePluginsListener(IPluginsListener *listener) = 0;
|
||||
virtual IPluginIterator *GetPluginIterator() = 0;
|
||||
virtual void OnLibraryAction(const char *name, LibraryAction action) = 0;
|
||||
virtual bool LibraryExists(const char *name) = 0;
|
||||
virtual SMPlugin *FindPluginByOrder(unsigned num) = 0;
|
||||
virtual SMPlugin *FindPluginByIdentity(IdentityToken_t *ident) = 0;
|
||||
virtual SMPlugin *FindPluginByContext(IPluginContext *ctx) = 0;
|
||||
virtual SMPlugin *FindPluginByContext(sp_context_t *ctx) = 0;
|
||||
virtual SMPlugin *FindPluginByConsoleArg(const char *text) = 0;
|
||||
virtual SMPlugin *FindPluginByHandle(Handle_t hndl, HandleError *errp) = 0;
|
||||
virtual bool UnloadPlugin(IPlugin *plugin) = 0;
|
||||
virtual const CVector<SMPlugin *> *ListPlugins() = 0;
|
||||
virtual void FreePluginList(const CVector<SMPlugin *> *list) = 0;
|
||||
virtual void AddFunctionsToForward(const char *name, IChangeableForward *fwd) = 0;
|
||||
};
|
||||
|
||||
class AutoPluginList
|
||||
{
|
||||
public:
|
||||
AutoPluginList(IScriptManager *scripts)
|
||||
: scripts_(scripts), list_(scripts->ListPlugins())
|
||||
{
|
||||
}
|
||||
~AutoPluginList()
|
||||
{
|
||||
scripts_->FreePluginList(list_);
|
||||
}
|
||||
const CVector<SMPlugin *> *operator ->()
|
||||
{
|
||||
return list_;
|
||||
}
|
||||
private:
|
||||
IScriptManager *scripts_;
|
||||
const CVector<SMPlugin *> *list_;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_INCLUDE_ISCRIPTMANAGER_H_
|
||||
@@ -1,48 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_BRIDGE_IVENGINESERVER_H_
|
||||
#define _INCLUDE_SOURCEMOD_BRIDGE_IVENGINESERVER_H_
|
||||
|
||||
struct edict_t;
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
class IVEngineServerBridge
|
||||
{
|
||||
public:
|
||||
virtual bool IsDedicatedServer() = 0;
|
||||
virtual void InsertServerCommand(const char *cmd) = 0;
|
||||
virtual void ServerCommand(const char *cmd) = 0;
|
||||
virtual void ServerExecute() = 0;
|
||||
virtual const char *GetClientConVarValue(int clientIndex, const char *name) = 0;
|
||||
virtual void ClientCommand(edict_t *pEdict, const char *szCommand) = 0;
|
||||
virtual void FakeClientCommand(edict_t *pEdict, const char *szCommand) = 0;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_BRIDGE_IVENGINESERVER_H_
|
||||
@@ -1,95 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_LOGIC_PROVIDER_API_H_
|
||||
#define _INCLUDE_SOURCEMOD_LOGIC_PROVIDER_API_H_
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
|
||||
class SMGlobalClass;
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
class CoreProvider;
|
||||
class IThreader;
|
||||
class ITranslator;
|
||||
class IGameConfig;
|
||||
class IScriptManager;
|
||||
class IShareSys;
|
||||
class IHandleSys;
|
||||
class ICommandArgs;
|
||||
class IForwardManager;
|
||||
class IAdminSystem;
|
||||
class IRootConsole;
|
||||
class IProviderCallbacks;
|
||||
class IExtensionSys;
|
||||
class ITextParsers;
|
||||
class ILogger;
|
||||
class ICellArray;
|
||||
|
||||
struct sm_logic_t
|
||||
{
|
||||
SMGlobalClass *head;
|
||||
IThreader *threader;
|
||||
ITranslator *translator;
|
||||
const char *(*stristr)(const char *, const char *);
|
||||
size_t (*atcprintf)(char *, size_t, const char *, IPluginContext *, const cell_t *, int *);
|
||||
bool (*CoreTranslate)(char *, size_t, const char *, unsigned int, size_t *, ...);
|
||||
void (*AddCorePhraseFile)(const char *filename);
|
||||
unsigned int (*ReplaceAll)(char*, size_t, const char *, const char *, bool);
|
||||
char *(*ReplaceEx)(char *, size_t, const char *, size_t, const char *, size_t, bool);
|
||||
size_t (*DecodeHexString)(unsigned char *, size_t, const char *);
|
||||
IGameConfig * (*GetCoreGameConfig)();
|
||||
IDebugListener *debugger;
|
||||
void (*GenerateError)(IPluginContext *, cell_t, int, const char *, ...);
|
||||
void (*AddNatives)(sp_nativeinfo_t *natives);
|
||||
void (*RegisterProfiler)(IProfilingTool *tool);
|
||||
ICellArray * (*CreateCellArray)(size_t blocksize);
|
||||
void (*FreeCellArray)(ICellArray *arr);
|
||||
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
|
||||
uint32_t (*ToPseudoAddress)(void *addr);
|
||||
void (*SetEntityLumpWritable)(bool writable);
|
||||
bool (*ParseEntityLumpString)(const char *entityString, int &status, size_t &position);
|
||||
const char * (*GetEntityLumpString)();
|
||||
IScriptManager *scripts;
|
||||
IShareSys *sharesys;
|
||||
IExtensionSys *extsys;
|
||||
IHandleSys *handlesys;
|
||||
IForwardManager *forwardsys;
|
||||
IAdminSystem *adminsys;
|
||||
IdentityToken_t *core_ident;
|
||||
ILogger *logger;
|
||||
IRootConsole *rootmenu;
|
||||
IProviderCallbacks *callbacks;
|
||||
float sentinel;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_LOGIC_PROVIDER_API_H_
|
||||
|
||||
-172
@@ -2,178 +2,6 @@ SourceMod Changelog
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.6 [2010-10-31]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.6_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Left 4 Dead 1 (bug 4681).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Updated TF2 custom kill defines (bug 4682).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.5 [2010-10-17]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.5_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for CS:S, Garry's Mod, DoD:S, TF2, HL2DM.
|
||||
- Added support for Firearms: Source (bug 4537).
|
||||
- Added support for Fistful of Frags (bug 3883).
|
||||
- Added support for Alien Swarm (bug 4530).
|
||||
- Fixed living players hearing dead players if alltalk is disabled while deadtalk is on (bug 4533, thanks Zach Callear).
|
||||
- Fixed timeleft not getting reset on Game_Commencing in CS:S (bug 4557).
|
||||
- Fixed PlayerRunCmd being hooked when not used (bug 3990).
|
||||
- Fixed errors and missing effects caused by missing sprites on L4D2 (bug 4512).
|
||||
- Fixed 'sm plugins' public command skipping plugins in recommended listing (bug 4501).
|
||||
- Fixed corruption with large database.cfg files (bug 4286).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added TF2 object stocks (bug 4536).
|
||||
- Added TF2_MakeBleed native to TF2 ext (bug 4542).
|
||||
- Added support for logical entities in Synergy (bug 4534).
|
||||
- Updated TF2 conditions enum and defines (bug 4526).
|
||||
- Fixed potential crash with IMemUtils::FindPattern on Linux (bug 4554).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.4 [2010-07-18]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.4_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Support for latest TF update (bug 4506).
|
||||
- Support for latest L4D2 update (bug 4509).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added FindFlagChar native (bug 3776).
|
||||
- Added GetConVarDefault native (bug 4502).
|
||||
- Added forward for TF's GetHoliday function (bug 4462).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.3 [2010-06-23]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.3_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added support for CS:S on Orange Box
|
||||
- Added gamedata for Resistance and Liberation (bug 4418).
|
||||
- Updated gamedata for SourceForts, Empires, Obsidian Conflict, Zombie Master.
|
||||
- Fixed memory corruption and leaks with some voice functionality (bug 4415).
|
||||
- Fixed UI bug in sm_motd (bug 4460).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new player condition (TFCond_CritCola, bug 4447).
|
||||
- Fixed clientprefs deleting cookies twice in rare cases (bug 4412).
|
||||
- Fixed OnClientConnected forward not firing for bots (bug 4443).
|
||||
- Fixed sm_dump_datamaps crash (bug 4424).
|
||||
- Fixed switch case comparisons failing with large numbers (bug 4457).
|
||||
- Fixed rare crash in output hooks (bug 4422).
|
||||
- Fixed bug with dynamically sized arrays being sliced (bug 4428).
|
||||
- Fixed SendConVarValue() on TF2, DOD:S, L4D, and L4D2 (bug 4273).
|
||||
- Fixed TF2 natives not being marked optional (bug 4389).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.2 [2010-05-02]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Support for recent TF, DoD, and L4D2 updates (bug 4356, bug 4361, bug 4371, bug 4374, bug 4375).
|
||||
- Fixed rare crash when replicating cvars to clients (bug 4315).
|
||||
- Lots of extra game support for Insurgency, ZPS, CSProMod, PVKII, and FortressForever (thanks
|
||||
Nicholas "psychonic" hastings).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added TF functions for stunning, conditions, regeneration, and power play (bug 4166, bug 4331).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.1 [2010-02-09]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added extended support for CSProMod (bug 4255).
|
||||
- Fixed client disconnect crash on many third party games (bug 4231).
|
||||
- Improved support for Battlegrounds 2 (bug 4146).
|
||||
- Improved support for Insurgency (bug 4180).
|
||||
- Improved support for Garry's Mod (bug 4230, bug 4268).
|
||||
- Improved support for Synergy (bug 4235).
|
||||
- Updated Day of Defeat support for 20010123 update (bug 4262).
|
||||
- Fixed Webternet extension not loading on Windows 2000 (bug 4234).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Fixed compiler complaints when using |any| tag on array arguments (bug 4274).
|
||||
- Fixed GetClientCookieTime not being exported (bug 4237).
|
||||
- Fixed potential crash in entity handling code (bug 4249).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.0 [2010-01-15]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.0_Release_Notes
|
||||
|
||||
Major Features:
|
||||
* Left 4 Dead 2 support
|
||||
* Non-networked entity support
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added Left 4 Dead 2 support (bug 4075).
|
||||
- Added much richer voting progress feedback (bug 1997).
|
||||
- Improved support for various third-party games (Nicholas "psychonic" Hastings).
|
||||
- Added @spec target (bug 2718).
|
||||
- Added sm_resetcvar command (bug 3636).
|
||||
- Added "motd" chat trigger (bug 2694).
|
||||
- Updated GeoIP to OCT-2009.
|
||||
- Fixed rare map vote error (bug 3905).
|
||||
- Fixed small leak in the nominations plugin (bug 4104).
|
||||
- Fixed last client being excluded from some command effects (bug 3984).
|
||||
- Fixed crashes in plugin [|un|re]loading (bug 4034, bug 4038, bug 4044, bug 4153).
|
||||
- Special target "@me" is now filtered for certain statuses properly (bug 4000).
|
||||
- Improved non-admin to admin chat (bug 3844).
|
||||
- Removed "auto.*" extension folders (bug 3949).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added non-networked entity support (bug 2459).
|
||||
- Added improved random number generator (bug 3831).
|
||||
- Added GetClientCookieTime native (bug 3736).
|
||||
- Added AskPluginLoad2 callback (bug 3716).
|
||||
- Added PlayerRunCmd callback (bug 3289).
|
||||
- Added PointOutsideWorld native (bug 3906).
|
||||
- Added API for "blanket" command hooks (bug 4015).
|
||||
- Added ability to test for SourceMod features (bug 4021).
|
||||
- Added ability to change broadcast status on hooked events (bug 3886).
|
||||
- OnClientCommand no longer receives unconnected clients (bug 3732).
|
||||
- Fixed various bugs in client listening API (bug 3818).
|
||||
- Fixed crash in BanClient (bug 3912).
|
||||
- Fixed various crashes in self-removing callbacks (bug 4059).
|
||||
- Fixed rare HUD text crash on TF (bug 4016).
|
||||
- Fixed OnConfigsExecuted not running on EP1 games with large configs (bug 3828).
|
||||
- Fixed entity output hooks not working (bug 3988).
|
||||
- Gamedata folder matches are now case-insensitive (bug 3913).
|
||||
- Blocked plugins from hooking "sm" command (bug 4013).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.2.4 [2009-10-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.2.4_Release_Notes
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
"banreasons"
|
||||
{
|
||||
"Abusive" "Abusive"
|
||||
"Racism" "Racism"
|
||||
"General cheating/exploits" "General cheating/exploits"
|
||||
"Wallhack" "Wallhack"
|
||||
"Aimbot" "Aimbot"
|
||||
"Speedhacking" "Speedhacking"
|
||||
"Mic spamming" "Mic spamming"
|
||||
"Admin disrespect" "Admin disrespect"
|
||||
"Camping" "Camping"
|
||||
"Team killing" "Team killing"
|
||||
"Unacceptable Spray" "Unacceptable Spray"
|
||||
"Breaking Server Rules" "Breaking Server Rules"
|
||||
"Other" "Other"
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
//This file unloads all plugins, re-loads a few "safe" ones, and then prevents
|
||||
//any more plugins from being loaded.
|
||||
sm plugins unload_all
|
||||
sm plugins load_unlock
|
||||
sm plugins load basebans.smx
|
||||
sm plugins load basecommands.smx
|
||||
sm plugins load admin-flatfile.smx
|
||||
|
||||
@@ -65,10 +65,6 @@ sm_flood_time 0.75
|
||||
// no reserved slot access (spectator players are selected first) is kicked to make room. Thus, the reserved
|
||||
// slots always remains free. The only situation where the reserved slot(s) can become properly occupied is
|
||||
// if the server is full with reserve slot access clients.
|
||||
// 2 : The same as sm_reserve_type 1 except once a certain number of admins have been reached, the reserve slot
|
||||
// stops kicking people and anyone can join to fill the server. You can use this to simulate having a large
|
||||
// number of reserved slots with sm_reserve_type 0 but with only need to have 1 slot unavailable when there are
|
||||
// less admins connected.
|
||||
// --
|
||||
// Requires: reservedslots.smx
|
||||
// Default: 0
|
||||
@@ -84,21 +80,21 @@ sm_reserve_type 0
|
||||
sm_reserved_slots 0
|
||||
|
||||
// Specifies whether or not reserved slots will be hidden (subtracted from max
|
||||
// slot count). Valid values are 0 (Visible) or 1 (Hidden).
|
||||
// slot count). Valid values are 0 (visible) or 1 (hidden).
|
||||
// --
|
||||
// Requires: reservedslots.smx
|
||||
// Default: 0
|
||||
sm_hide_slots 0
|
||||
|
||||
// Specifies whether or not non-admins can send messages to admins using
|
||||
// say_team @<message>. Valid values are 0 (Disabled) or 1 (Enabled)
|
||||
// say_team @<message>. Valid values are 0 (disabled) or 1 (enabled)
|
||||
// --
|
||||
// Requires: basechat.smx
|
||||
// Default: 1
|
||||
sm_chat_mode 1
|
||||
|
||||
// Specifies whether or not "timeleft" will automatically be triggered every
|
||||
// x seconds. Valid values are 0 (Disabled) to 1800 seconds.
|
||||
// Specifies whether or not "timeleft" will automaticly be triggered every
|
||||
// x seconds. Valid values are 0 (disabled) to 1800 seconds.
|
||||
// --
|
||||
// Requires: basetriggers.smx
|
||||
// Default: 0
|
||||
@@ -109,30 +105,5 @@ sm_timeleft_interval 0
|
||||
// 1 (Enabled)
|
||||
// --
|
||||
// Requires: basetriggers.smx
|
||||
// Default: 0
|
||||
sm_trigger_show 0
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// "hint" box (near the bottom of the screen in most games).
|
||||
// Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_hintbox 0
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// chat area. Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_chat 0
|
||||
|
||||
// Specifies whether or not to display vote progress in the server console.
|
||||
// Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_console 0
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// client console. Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_client_console 0
|
||||
// Default: 1
|
||||
sm_trigger_show 1
|
||||
|
||||
+21
-52
@@ -30,12 +30,12 @@
|
||||
"ServerLang" "en"
|
||||
|
||||
/**
|
||||
* List of characters to use for public chat triggers. Set an empty list to disable.
|
||||
* String to use as the public chat trigger. Set an empty string to disable.
|
||||
*/
|
||||
"PublicChatTrigger" "!"
|
||||
|
||||
/**
|
||||
* List of characters to use for silent chat triggers. Set an empty list to disable.
|
||||
* String to use as the silent chat trigger. Set an empty string to disable.
|
||||
*/
|
||||
"SilentChatTrigger" "/"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
* but it does not evaluate to an actual command, it will be displayed
|
||||
* publicly. This setting allows you to suppress accidental typings.
|
||||
*
|
||||
* The default value is "no". A value of "yes" will suppress.
|
||||
* The default value is "no". A value of "yes" will supress.
|
||||
*/
|
||||
"SilentFailSuppress" "no"
|
||||
|
||||
@@ -53,6 +53,24 @@
|
||||
* passwords to work, for security reasons.
|
||||
*/
|
||||
"PassInfoVar" "_password"
|
||||
|
||||
/**
|
||||
* Specifies the sound that gets played when an item is selected from a menu.
|
||||
*/
|
||||
"MenuItemSound" "buttons/button14.wav"
|
||||
|
||||
/**
|
||||
* Specifies the sound that gets played when an "Exit" button is selected
|
||||
* from a menu.
|
||||
*/
|
||||
"MenuExitSound" "buttons/combine_button7.wav"
|
||||
|
||||
/**
|
||||
* Specifies the sound that gets played when an "Exit Back" button is selected
|
||||
* from a menu. This is the special "Back" button that is intended to roll back
|
||||
* to a previous menu.
|
||||
*/
|
||||
"MenuExitBackSound" "buttons/combine_button7.wav"
|
||||
|
||||
/**
|
||||
* Enables or disables whether SourceMod reads a client's cl_language cvar to set
|
||||
@@ -89,53 +107,4 @@
|
||||
* Currently this will log details about the gamedata updating process.
|
||||
*/
|
||||
"DebugSpew" "no"
|
||||
|
||||
/**
|
||||
* If set to yes, SourceMod will validate steamid auth strings with the Steam backend before giving out admin access.
|
||||
* This can prevent malicious users from impersonating admins with stolen Steam apptickets.
|
||||
* If Steam is down, admins will not be authenticated until Steam comes back up.
|
||||
* This option increases the security of your server, but is still experimental.
|
||||
*/
|
||||
"SteamAuthstringValidation" "yes"
|
||||
|
||||
/**
|
||||
* Enables or disables whether SourceMod blocks known or potentially malicious plugins from loading.
|
||||
* It is STRONGLY advised that this is left enabled, there have been cases in the past with plugins that
|
||||
* allow anyone to delete files on the server, gain full rcon control, etc.
|
||||
*
|
||||
* "yes" - Block malware or illegal plugins from loading (default)
|
||||
* "no" - Warn about malware or illegal plugins loading
|
||||
*/
|
||||
"BlockBadPlugins" "yes"
|
||||
|
||||
/**
|
||||
* If a plugin takes too long to execute, hanging or freezing the game server in the process,
|
||||
* SourceMod will attempt to terminate that plugin after the specified timeout length has
|
||||
* passed. You can disable this feature by setting the value to "0".
|
||||
*/
|
||||
"SlowScriptTimeout" "8"
|
||||
|
||||
/**
|
||||
* Per "http://blog.counter-strike.net/index.php/server_guidelines/", certain plugin
|
||||
* functionality will trigger all of the game server owner's Game Server Login Tokens
|
||||
* (GSLTs) to get banned when executed on a Counter-Strike: Global Offensive game server.
|
||||
*
|
||||
* Enabling this option will block plugins from using functionality that is known to cause this.
|
||||
* This option only has any effect on CS:GO. Note that this does NOT guarantee that you cannot
|
||||
* receive a ban.
|
||||
*
|
||||
* Disable this option at your own risk.
|
||||
*/
|
||||
"FollowCSGOServerGuidelines" "yes"
|
||||
|
||||
/**
|
||||
* Controls whether the SourcePawn runtime will generate additional metadata about
|
||||
* JIT-compiled functions for performance profiling or debugging purposes.
|
||||
*
|
||||
* "none" - Don't generate any additional JIT metadata
|
||||
* "default" - Generate basic perf metadata (on Linux) and delete it automatically on quit
|
||||
* "perf" - Generate basic perf metadata (Linux only - function names)
|
||||
* "jitdump" - Generate extended perf metadata (Linux only - function names, bytecode, and source information)
|
||||
*/
|
||||
"JITMetadata" "default"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
{
|
||||
"driver_default" "mysql"
|
||||
|
||||
// When specifying "host", you may use an IP address, a hostname, or a socket file path
|
||||
|
||||
"default"
|
||||
{
|
||||
"driver" "default"
|
||||
|
||||
Binary file not shown.
+1
-35
@@ -1,38 +1,4 @@
|
||||
"Languages"
|
||||
{
|
||||
"ar" "Arabic" // Arabic
|
||||
"bg" "Bulgarian" // Bulgarian
|
||||
"chi" "SChinese" // Chinese (Simplified)
|
||||
"cze" "Czech" // Czech
|
||||
"da" "Danish" // Danish
|
||||
"de" "German" // German
|
||||
"el" "Greek" // Greek
|
||||
"en" "English" // English
|
||||
"es" "Spanish" // Spanish
|
||||
"fi" "Finnish" // Finnish
|
||||
"fr" "French" // French
|
||||
"he" "Hebrew" // Hebrew
|
||||
"hu" "Hungarian" // Hungarian
|
||||
"it" "Italian" // Italian
|
||||
"jp" "Japanese" // Japanese
|
||||
"ko" "Korean" // Korean
|
||||
"ko" "KoreanA" // Korean (https://bugs.alliedmods.net/show_bug.cgi?id=4667)
|
||||
"las" "LatAm" // Latin American Spanish
|
||||
"lt" "Lithuanian" // Lithuanian
|
||||
"lv" "Latvian" // Latvian
|
||||
"nl" "Dutch" // Dutch
|
||||
"no" "Norwegian" // Norwegian
|
||||
"pl" "Polish" // Polish
|
||||
"pt" "Brazilian" // Brazilian Portuguese
|
||||
"pt_p" "Portuguese" // Portuguese
|
||||
"ro" "Romanian" // Romanian
|
||||
"ru" "Russian" // Russian
|
||||
"sk" "Slovak" // Slovak
|
||||
"sv" "Swedish" // Swedish
|
||||
"th" "Thai" // Thai
|
||||
"tr" "Turkish" // Turkish
|
||||
"ua" "Ukrainian" // Ukrainian
|
||||
"vi" "Vietnamese" // Vietnamese
|
||||
"zho" "TChinese" // Chinese (Traditional)
|
||||
|
||||
"en" "English"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Each sub-section of "Plugins" should have a title which specifies a plugin filename.
|
||||
* Filenames have a wildcard of *. Appending .smx is not required.
|
||||
* If the filename has no explicit path, it will be patched to any sub-path in the plugins folder.
|
||||
*
|
||||
* Available properties for plugins are:
|
||||
* "pause" - Whether or not the plugin should load paused - "yes" or "no" (default)
|
||||
* "lifetime" - Lifetime of the plugin. Options:
|
||||
* "mapsync" - Plugins should be reloaded on mapchange if changed (default)
|
||||
* "global" - Plugin will never be unloaded or updated
|
||||
* "blockload" - Plugin will always be blocked from loading. Implicit (automatic) loads
|
||||
* produce no error, but explicit (manual) loads will show an error message.
|
||||
* (Options are one of "yes" or "no")
|
||||
*
|
||||
* You can also have an "Options" section declaring options to pass onto the JIT:
|
||||
* "profile" - Bit flags for profiling level. Add flags together to reach a value.
|
||||
* WARNING: Profiler is _ALPHA_ software! Use it at your own risk for
|
||||
* development cycles only (not production setups).
|
||||
* See the wiki article "SourceMod Profiler" for more information.
|
||||
* 1 - Profile natives
|
||||
* 2 - Profile callbacks
|
||||
* 4 - Profile internal plugin function calls
|
||||
*/
|
||||
|
||||
"Plugins"
|
||||
{
|
||||
"*"
|
||||
{
|
||||
"pause" "no"
|
||||
"lifetime" "mapsync"
|
||||
|
||||
"Options"
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS sm_cookies
|
||||
(
|
||||
id serial,
|
||||
name varchar(30) NOT NULL UNIQUE,
|
||||
description varchar(255),
|
||||
access INTEGER,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sm_cookie_cache
|
||||
(
|
||||
player varchar(65) NOT NULL,
|
||||
cookie_id int NOT NULL,
|
||||
value varchar(100),
|
||||
timestamp int NOT NULL,
|
||||
PRIMARY KEY (player, cookie_id)
|
||||
);
|
||||
|
||||
CREATE LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS
|
||||
$$
|
||||
BEGIN
|
||||
LOOP
|
||||
-- first try to update the it.
|
||||
UPDATE sm_cookie_cache SET value = in_value, timestamp = in_time WHERE player = in_player AND cookie_id = in_cookie;
|
||||
IF found THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
-- not there, so try to insert.
|
||||
-- if someone else inserts the same key concurrently, we could get a unique-key failure.
|
||||
BEGIN
|
||||
INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES (in_player, in_cookie, in_value, in_time);
|
||||
RETURN;
|
||||
EXCEPTION WHEN unique_violation THEN
|
||||
-- do nothing... loop again, and we'll update.
|
||||
END;
|
||||
END LOOP;
|
||||
END;
|
||||
$$
|
||||
LANGUAGE plpgsql;
|
||||
@@ -1,65 +0,0 @@
|
||||
CREATE TABLE sm_admins (
|
||||
id serial,
|
||||
authtype varchar(6) NOT NULL,
|
||||
CHECK (authtype in ('steam', 'name', 'ip')),
|
||||
identity varchar(65) NOT NULL,
|
||||
password varchar(65),
|
||||
flags varchar(30) NOT NULL,
|
||||
name varchar(65) NOT NULL,
|
||||
immunity int NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_groups (
|
||||
id serial,
|
||||
flags varchar(30) NOT NULL,
|
||||
name varchar(120) NOT NULL,
|
||||
immunity_level int NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_group_immunity (
|
||||
group_id int NOT NULL,
|
||||
other_id int NOT NULL,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (other_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (group_id, other_id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_group_overrides (
|
||||
group_id int NOT NULL,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
type varchar(10) NOT NULL,
|
||||
CHECK (type in ('command', 'group')),
|
||||
name varchar(32) NOT NULL,
|
||||
access varchar(5) NOT NULL,
|
||||
CHECK (access in ('allow', 'deny')),
|
||||
PRIMARY KEY (group_id, type, name)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_overrides (
|
||||
type varchar(10) NOT NULL,
|
||||
CHECK (type in ('command', 'group')),
|
||||
name varchar(32) NOT NULL,
|
||||
flags varchar(30) NOT NULL,
|
||||
PRIMARY KEY (type,name)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_admins_groups (
|
||||
admin_id int NOT NULL,
|
||||
group_id int NOT NULL,
|
||||
FOREIGN KEY (admin_id) REFERENCES sm_admins(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
inherit_order int NOT NULL,
|
||||
PRIMARY KEY (admin_id, group_id)
|
||||
);
|
||||
|
||||
-- side note, this is pgsql module, sm_config will not exist if the above stuff exists... and it's being left to the admin
|
||||
-- to figure out if it exists.
|
||||
CREATE TABLE sm_config (
|
||||
cfg_key varchar(32) NOT NULL,
|
||||
cfg_value varchar(255) NOT NULL,
|
||||
PRIMARY KEY (cfg_key)
|
||||
);
|
||||
|
||||
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');
|
||||
+5
-44
@@ -1,49 +1,10 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
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)
|
||||
import ambuild.runner as runner
|
||||
|
||||
# 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)
|
||||
|
||||
parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
||||
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||
help='Root search folder for HL2SDKs')
|
||||
parser.options.add_argument('--mysql-path', type=str, dest='mysql_path', default=None,
|
||||
help='Path to MySQL 5')
|
||||
parser.options.add_argument('--mysql64-path', type=str, dest='mysql64_path', default=None,
|
||||
help='Path to 64-bit MySQL 5')
|
||||
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||
help='Path to Metamod:Source')
|
||||
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
run = runner.Runner()
|
||||
run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
help='Enable debugging symbols')
|
||||
parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||
run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||
help='Enable optimization')
|
||||
parser.options.add_argument('--no-mysql', action='store_false', default=True, dest='hasMySql',
|
||||
help='Disable building MySQL extension')
|
||||
parser.options.add_argument('-s', '--sdks', default='present', dest='sdks',
|
||||
help='Build against specified SDKs; valid args are "none", "all", "present",'
|
||||
' or comma-delimited list of engine names')
|
||||
parser.options.add_argument('--breakpad-dump', action='store_true', dest='breakpad_dump',
|
||||
default=False, help='Dump and upload breakpad symbols')
|
||||
parser.options.add_argument('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
|
||||
default=False, help='Disable the auto versioning script')
|
||||
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
|
||||
help="Override the target architecture (use commas to separate multiple targets).")
|
||||
parser.options.add_argument('--scripting-only', action='store_true', dest='scripting_only', default=False,
|
||||
help="Only build and package the files required for scripting in SourcePawn.")
|
||||
parser.options.add_argument('--enable-asan', action='store_true', dest='enable_asan',
|
||||
default=False, help='Enable ASAN (clang only)')
|
||||
parser.Configure()
|
||||
run.Configure(sys.path[0])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
|
||||
#include "ADTFactory.h"
|
||||
#include "sm_globals.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
ADTFactory g_AdtFactory;
|
||||
@@ -56,30 +57,32 @@ IBasicTrie *ADTFactory::CreateBasicTrie()
|
||||
|
||||
BaseTrie::BaseTrie()
|
||||
{
|
||||
m_pTrie = sm_trie_create();
|
||||
}
|
||||
|
||||
BaseTrie::~BaseTrie()
|
||||
{
|
||||
sm_trie_destroy(m_pTrie);
|
||||
}
|
||||
|
||||
bool BaseTrie::Insert(const char *key, void *value)
|
||||
{
|
||||
return map_.insert(key, value);
|
||||
return sm_trie_insert(m_pTrie, key, value);
|
||||
}
|
||||
|
||||
bool BaseTrie::Retrieve(const char *key, void **value)
|
||||
{
|
||||
return map_.retrieve(key, value);
|
||||
return sm_trie_retrieve(m_pTrie, key, value);
|
||||
}
|
||||
|
||||
bool BaseTrie::Delete(const char *key)
|
||||
{
|
||||
return map_.remove(key);
|
||||
return sm_trie_delete(m_pTrie, key);
|
||||
}
|
||||
|
||||
void BaseTrie::Clear()
|
||||
{
|
||||
map_.clear();
|
||||
sm_trie_clear(m_pTrie);
|
||||
}
|
||||
|
||||
void BaseTrie::Destroy()
|
||||
@@ -89,5 +92,5 @@ void BaseTrie::Destroy()
|
||||
|
||||
bool BaseTrie::Replace(const char *key, void *value)
|
||||
{
|
||||
return map_.replace(key, value);
|
||||
return sm_trie_replace(m_pTrie, key, value);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -33,8 +33,8 @@
|
||||
#define _INCLUDE_SOURCEMOD_ADTFACTORY_H_
|
||||
|
||||
#include <IADTFactory.h>
|
||||
#include "common_logic.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sm_trie.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
virtual void Clear();
|
||||
virtual void Destroy();
|
||||
private:
|
||||
StringHashMap<void *> map_;
|
||||
Trie *m_pTrie;
|
||||
};
|
||||
|
||||
class ADTFactory :
|
||||
+103
-136
@@ -1,141 +1,108 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
|
||||
project = builder.LibraryProject('sourcemod')
|
||||
for i in SM.sdkInfo:
|
||||
sdk = SM.sdkInfo[i]
|
||||
name = 'sourcemod.' + sdk['ext']
|
||||
|
||||
project.sources += [
|
||||
'MenuStyle_Valve.cpp',
|
||||
'logic_bridge.cpp',
|
||||
'smn_entities.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'smn_events.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'ChatTriggers.cpp',
|
||||
'smn_player.cpp',
|
||||
'sourcemod.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'NextMap.cpp',
|
||||
'ConCmdManager.cpp',
|
||||
'ConVarManager.cpp',
|
||||
'PlayerManager.cpp',
|
||||
'TimerSys.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'Logger.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'smn_console.cpp',
|
||||
'UserMessages.cpp',
|
||||
'MenuManager.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_vector.cpp',
|
||||
'EventManager.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'ConsoleDetours.cpp',
|
||||
'smn_commandline.cpp',
|
||||
'GameHooks.cpp',
|
||||
]
|
||||
compiler = SM.DefaultHL2Compiler('core', i)
|
||||
compiler['CDEFINES'].append('SM_DEFAULT_THREADER')
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
compiler['POSTLINKFLAGS'].append('-lpthread')
|
||||
|
||||
# SDK name to shipping gamedir
|
||||
pb_gamedir_map = {
|
||||
'csgo': 'csgo',
|
||||
'blade': 'berimbau',
|
||||
'mcv': 'vietnam',
|
||||
}
|
||||
|
||||
# SDK name to source code gamedir
|
||||
pb_gamesrcdir_map = {
|
||||
'csgo': 'cstrike15',
|
||||
'blade': 'berimbau',
|
||||
'mcv': 'vietnam',
|
||||
}
|
||||
|
||||
for sdk_target in SM.sdk_targets:
|
||||
sdk = sdk_target.sdk
|
||||
cxx = sdk_target.cxx
|
||||
|
||||
binary_name = 'sourcemod.' + sdk['extension']
|
||||
needs_protobuf = sdk['name'] in ['csgo', 'blade', 'mcv']
|
||||
|
||||
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
|
||||
SM.ConfigureForExtension(builder, binary.compiler)
|
||||
|
||||
compiler = binary.compiler
|
||||
compiler.cxxincludes += [
|
||||
builder.sourcePath
|
||||
]
|
||||
|
||||
if needs_protobuf:
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(sdk['path'], 'common', 'protobuf-2.5.0', 'src'),
|
||||
os.path.join(sdk['path'], 'public', 'engine', 'protobuf'),
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf')
|
||||
]
|
||||
|
||||
if compiler.like('msvc'):
|
||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||
if cxx.target.platform == 'linux':
|
||||
compiler.postlink += ['-lpthread', '-lrt']
|
||||
|
||||
if needs_protobuf:
|
||||
if compiler.target.platform == 'linux':
|
||||
if compiler.target.arch == 'x86':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'linux32', 'release', 'libprotobuf.a')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'linux64', 'release', 'libprotobuf.a')
|
||||
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
||||
elif compiler.target.platform == 'mac':
|
||||
if compiler.target.arch == 'x86':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||
elif compiler.target.platform == 'windows':
|
||||
msvc_ver = compiler.version
|
||||
vs_year = ''
|
||||
platform = ''
|
||||
if compiler.target.arch == 'x86':
|
||||
platform = 'win32'
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
platform = 'win64'
|
||||
|
||||
if 1900 <= msvc_ver < 2000:
|
||||
vs_year = '2015'
|
||||
else:
|
||||
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
||||
|
||||
if 'DEBUG' in compiler.defines:
|
||||
lib_path = os.path.join(sdk['path'], 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
else:
|
||||
lib_path = os.path.join(sdk['path'], 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
compiler.linkflags.insert(0, lib_path)
|
||||
|
||||
if needs_protobuf:
|
||||
binary.sources += ['smn_protobuf.cpp']
|
||||
else:
|
||||
binary.sources += ['smn_bitbuffer.cpp']
|
||||
|
||||
if sdk['name'] != 'blade':
|
||||
binary.sources += [
|
||||
'vprof_tool.cpp',
|
||||
]
|
||||
|
||||
if needs_protobuf:
|
||||
binary.sources += [
|
||||
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessages.pb.cc'),
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessage_helpers.cpp'),
|
||||
]
|
||||
if sdk['name'] == 'mcv':
|
||||
binary.sources += [
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_gcmessages.pb.cc'),
|
||||
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'engine_gcmessages.pb.cc'),
|
||||
]
|
||||
|
||||
SM.binaries += builder.Add(project)
|
||||
extension = AMBuild.AddJob(name)
|
||||
binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler)
|
||||
SM.PreSetupHL2Job(extension, binary, i)
|
||||
files = [
|
||||
'AdminCache.cpp',
|
||||
'ExtensionSys.cpp',
|
||||
'MenuStyle_Valve.cpp',
|
||||
'sm_crc32.cpp',
|
||||
'smn_entities.cpp',
|
||||
'smn_maplists.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'ADTFactory.cpp',
|
||||
'ForwardSys.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'sm_memtable.cpp',
|
||||
'smn_events.cpp',
|
||||
'smn_menus.cpp',
|
||||
'sm_trie.cpp',
|
||||
'CDataPack.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'NativeInvoker.cpp',
|
||||
'smn_admin.cpp',
|
||||
'smn_fakenatives.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'ChatTriggers.cpp',
|
||||
'GameConfigs.cpp',
|
||||
'NativeOwner.cpp',
|
||||
'smn_adt_array.cpp',
|
||||
'smn_filesystem.cpp',
|
||||
'smn_player.cpp',
|
||||
'sourcemod.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'NextMap.cpp',
|
||||
'smn_adt_stack.cpp',
|
||||
'smn_float.cpp',
|
||||
'smn_profiler.cpp',
|
||||
'TextParsers.cpp',
|
||||
'ConCmdManager.cpp',
|
||||
'HandleSys.cpp',
|
||||
'PhraseCollection.cpp',
|
||||
'smn_adt_trie.cpp',
|
||||
'smn_functions.cpp',
|
||||
'smn_sorting.cpp',
|
||||
'ThreadSupport.cpp',
|
||||
'ConVarManager.cpp',
|
||||
'LibrarySys.cpp',
|
||||
'PlayerManager.cpp',
|
||||
'smn_banning.cpp',
|
||||
'smn_gameconfigs.cpp',
|
||||
'smn_string.cpp',
|
||||
'TimerSys.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'Logger.cpp',
|
||||
'PluginInfoDatabase.cpp',
|
||||
'smn_bitbuffer.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'smn_textparse.cpp',
|
||||
'Translator.cpp',
|
||||
'MemoryUtils.cpp',
|
||||
'PluginSys.cpp',
|
||||
'smn_console.cpp',
|
||||
'smn_handles.cpp',
|
||||
'smn_timers.cpp',
|
||||
'UserMessages.cpp',
|
||||
'Database.cpp',
|
||||
'MenuManager.cpp',
|
||||
'Profiler.cpp',
|
||||
'smn_core.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'DebugReporter.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'ShareSys.cpp',
|
||||
'smn_database.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_vector.cpp',
|
||||
'EventManager.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'smn_datapacks.cpp',
|
||||
'smn_lang.cpp',
|
||||
'sm_srvcmds.cpp',
|
||||
'thread/ThreadWorker.cpp',
|
||||
'thread/BaseWorker.cpp'
|
||||
]
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
files.append('thread/WinThreads.cpp')
|
||||
else:
|
||||
files.append('thread/PosixThreads.cpp')
|
||||
binary.AddSourceFiles('core', files)
|
||||
SM.PostSetupHL2Job(extension, binary, i)
|
||||
SM.AutoVersion('core', binary)
|
||||
binary.SendToJob()
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,231 +1,208 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <IAdminSystem.h>
|
||||
#include "sm_memtable.h"
|
||||
#include <sm_trie.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
#define GRP_MAGIC_SET 0xDEADFADE
|
||||
#define GRP_MAGIC_UNSET 0xFACEFACE
|
||||
#define USR_MAGIC_SET 0xDEADFACE
|
||||
#define USR_MAGIC_UNSET 0xFADEDEAD
|
||||
|
||||
typedef StringHashMap<OverrideRule> OverrideMap;
|
||||
|
||||
struct AdminGroup
|
||||
{
|
||||
uint32_t magic; /* Magic flag, for memory validation (ugh) */
|
||||
unsigned int immunity_level; /* Immunity level */
|
||||
/* Immune from target table (-1 = nonexistent)
|
||||
* [0] = number of entries
|
||||
* [1...N] = immune targets
|
||||
*/
|
||||
int immune_table;
|
||||
OverrideMap *pCmdTable; /* Command override table (can be NULL) */
|
||||
OverrideMap *pCmdGrpTable; /* Command group override table (can be NULL) */
|
||||
int next_grp; /* Next group in the chain */
|
||||
int prev_grp; /* Previous group in the chain */
|
||||
int nameidx; /* Name */
|
||||
FlagBits addflags; /* Additive flags */
|
||||
};
|
||||
|
||||
struct AuthMethod
|
||||
{
|
||||
String name;
|
||||
StringHashMap<AdminId> identities;
|
||||
|
||||
AuthMethod(const char *name)
|
||||
: name(name)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool matches(const char *name, const AuthMethod *method)
|
||||
{
|
||||
return strcmp(name, method->name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct UserAuth
|
||||
{
|
||||
unsigned int index; /* Index into auth table */
|
||||
int identidx; /* Index into the string table */
|
||||
};
|
||||
|
||||
struct AdminUser
|
||||
{
|
||||
uint32_t magic; /* Magic flag, for memory validation */
|
||||
FlagBits flags; /* Flags */
|
||||
FlagBits eflags; /* Effective flags */
|
||||
int nameidx; /* Name index */
|
||||
int password; /* Password index */
|
||||
unsigned int grp_count; /* Number of groups */
|
||||
unsigned int grp_size; /* Size of groups table */
|
||||
int grp_table; /* Group table itself */
|
||||
int next_user; /* Next user in the list */
|
||||
int prev_user; /* Previous user in the list */
|
||||
UserAuth auth; /* Auth method for this user */
|
||||
unsigned int immunity_level; /* Immunity level */
|
||||
unsigned int serialchange; /* Serial # for changes */
|
||||
};
|
||||
|
||||
class AdminCache :
|
||||
public IAdminSystem,
|
||||
public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
AdminCache();
|
||||
~AdminCache();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModPluginsLoaded();
|
||||
public: //IAdminSystem
|
||||
/** Command cache stuff */
|
||||
void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags);
|
||||
bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *flags);
|
||||
void UnsetCommandOverride(const char *cmd, OverrideType type);
|
||||
/** Group cache stuff */
|
||||
GroupId AddGroup(const char *group_name);
|
||||
GroupId FindGroupByName(const char *group_name);
|
||||
void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled);
|
||||
bool GetGroupAddFlag(GroupId id, AdminFlag flag);
|
||||
FlagBits GetGroupAddFlags(GroupId id);
|
||||
void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled);
|
||||
bool GetGroupGenericImmunity(GroupId id, ImmunityType type);
|
||||
void InvalidateGroup(GroupId id);
|
||||
void AddGroupImmunity(GroupId id, GroupId other_id);
|
||||
unsigned int GetGroupImmunityCount(GroupId id);
|
||||
GroupId GetGroupImmunity(GroupId id, unsigned int number);
|
||||
void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule);
|
||||
bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule);
|
||||
void DumpAdminCache(AdminCachePart part, bool rebuild);
|
||||
void AddAdminListener(IAdminListener *pListener);
|
||||
void RemoveAdminListener(IAdminListener *pListener);
|
||||
/** User stuff */
|
||||
void RegisterAuthIdentType(const char *name);
|
||||
AdminId CreateAdmin(const char *name);
|
||||
const char *GetAdminName(AdminId id);
|
||||
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
|
||||
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
|
||||
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
|
||||
FlagBits GetAdminFlags(AdminId id, AccessMode mode);
|
||||
bool AdminInheritGroup(AdminId id, GroupId gid);
|
||||
unsigned int GetAdminGroupCount(AdminId id);
|
||||
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
|
||||
void SetAdminPassword(AdminId id, const char *password);
|
||||
const char *GetAdminPassword(AdminId id);
|
||||
AdminId FindAdminByIdentity(const char *auth, const char *identity);
|
||||
bool InvalidateAdmin(AdminId id);
|
||||
unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize);
|
||||
FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize);
|
||||
FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags);
|
||||
unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize);
|
||||
bool CheckAdminFlags(AdminId id, FlagBits bits);
|
||||
bool CanAdminTarget(AdminId id, AdminId target);
|
||||
void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
|
||||
bool FindFlag(const char *str, AdminFlag *pFlag);
|
||||
bool FindFlag(char c, AdminFlag *pAdmFlag);
|
||||
FlagBits ReadFlagString(const char *flags, const char **end);
|
||||
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
|
||||
unsigned int GetAdminSerialChange(AdminId id);
|
||||
bool CanAdminUseCommand(int client, const char *cmd);
|
||||
const char *GetGroupName(GroupId gid);
|
||||
unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
|
||||
unsigned int GetGroupImmunityLevel(GroupId gid);
|
||||
unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
|
||||
unsigned int GetAdminImmunityLevel(AdminId id);
|
||||
bool CheckAccess(int client,
|
||||
const char *cmd,
|
||||
FlagBits flags,
|
||||
bool override_only);
|
||||
bool FindFlagChar(AdminFlag flag, char *c);
|
||||
bool IsValidAdmin(AdminId id);
|
||||
bool CheckClientCommandAccess(int client, const char *cmd, FlagBits cmdflags);
|
||||
public:
|
||||
bool DumpCache(const char *filename);
|
||||
AdminGroup *GetGroup(GroupId gid);
|
||||
AdminUser *GetUser(AdminId id);
|
||||
const char *GetString(int idx);
|
||||
bool CheckAdminCommandAccess(AdminId adm, const char *cmd, FlagBits flags);
|
||||
private:
|
||||
void _UnsetCommandOverride(const char *cmd);
|
||||
void _UnsetCommandGroupOverride(const char *group);
|
||||
void InvalidateGroupCache();
|
||||
void InvalidateAdminCache(bool unlink_admins);
|
||||
void DumpCommandOverrideCache(OverrideType type);
|
||||
AuthMethod *GetMethodByIndex(unsigned int index);
|
||||
bool GetMethodIndex(const char *name, unsigned int *_index);
|
||||
const char *GetMethodName(unsigned int index);
|
||||
void NameFlag(const char *str, AdminFlag flag);
|
||||
bool GetUnifiedSteamIdentity(const char *ident, char *out, size_t maxlen);
|
||||
public:
|
||||
typedef StringHashMap<FlagBits> FlagMap;
|
||||
|
||||
BaseStringTable *m_pStrings;
|
||||
BaseMemTable *m_pMemory;
|
||||
FlagMap m_CmdOverrides;
|
||||
FlagMap m_CmdGrpOverrides;
|
||||
int m_FirstGroup;
|
||||
int m_LastGroup;
|
||||
int m_FreeGroupList;
|
||||
StringHashMap<GroupId> m_Groups;
|
||||
List<IAdminListener *> m_hooks;
|
||||
List<AuthMethod *> m_AuthMethods;
|
||||
NameHashSet<AuthMethod *> m_AuthTables;
|
||||
IForward *m_pCacheFwd;
|
||||
int m_FirstUser;
|
||||
int m_LastUser;
|
||||
int m_FreeUserList;
|
||||
bool m_InvalidatingAdmins;
|
||||
bool m_destroying;
|
||||
StringHashMap<AdminFlag> m_LevelNames;
|
||||
};
|
||||
|
||||
extern AdminCache g_Admins;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||
/**
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||
|
||||
#include "sm_memtable.h"
|
||||
#include <sm_trie.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <IAdminSystem.h>
|
||||
#include "sm_globals.h"
|
||||
#include <IForwardSys.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
#define GRP_MAGIC_SET 0xDEADFADE
|
||||
#define GRP_MAGIC_UNSET 0xFACEFACE
|
||||
#define USR_MAGIC_SET 0xDEADFACE
|
||||
#define USR_MAGIC_UNSET 0xFADEDEAD
|
||||
|
||||
struct AdminGroup
|
||||
{
|
||||
uint32_t magic; /* Magic flag, for memory validation (ugh) */
|
||||
unsigned int immunity_level; /* Immunity level */
|
||||
/* Immune from target table (-1 = nonexistent)
|
||||
* [0] = number of entries
|
||||
* [1...N] = immune targets
|
||||
*/
|
||||
int immune_table;
|
||||
Trie *pCmdTable; /* Command override table (can be NULL) */
|
||||
Trie *pCmdGrpTable; /* Command group override table (can be NULL) */
|
||||
int next_grp; /* Next group in the chain */
|
||||
int prev_grp; /* Previous group in the chain */
|
||||
int nameidx; /* Name */
|
||||
FlagBits addflags; /* Additive flags */
|
||||
};
|
||||
|
||||
struct AuthMethod
|
||||
{
|
||||
String name;
|
||||
Trie *table;
|
||||
};
|
||||
|
||||
struct UserAuth
|
||||
{
|
||||
unsigned int index; /* Index into auth table */
|
||||
int identidx; /* Index into the string table */
|
||||
};
|
||||
|
||||
struct AdminUser
|
||||
{
|
||||
uint32_t magic; /* Magic flag, for memory validation */
|
||||
FlagBits flags; /* Flags */
|
||||
FlagBits eflags; /* Effective flags */
|
||||
int nameidx; /* Name index */
|
||||
int password; /* Password index */
|
||||
unsigned int grp_count; /* Number of groups */
|
||||
unsigned int grp_size; /* Size of groups table */
|
||||
int grp_table; /* Group table itself */
|
||||
int next_user; /* Next user in the list */
|
||||
int prev_user; /* Previous user in the list */
|
||||
UserAuth auth; /* Auth method for this user */
|
||||
unsigned int immunity_level; /* Immunity level */
|
||||
unsigned int serialchange; /* Serial # for changes */
|
||||
};
|
||||
|
||||
class AdminCache :
|
||||
public IAdminSystem,
|
||||
public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
AdminCache();
|
||||
~AdminCache();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModPluginsLoaded();
|
||||
public: //IAdminSystem
|
||||
/** Command cache stuff */
|
||||
void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags);
|
||||
bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *flags);
|
||||
void UnsetCommandOverride(const char *cmd, OverrideType type);
|
||||
/** Group cache stuff */
|
||||
GroupId AddGroup(const char *group_name);
|
||||
GroupId FindGroupByName(const char *group_name);
|
||||
void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled);
|
||||
bool GetGroupAddFlag(GroupId id, AdminFlag flag);
|
||||
FlagBits GetGroupAddFlags(GroupId id);
|
||||
void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled);
|
||||
bool GetGroupGenericImmunity(GroupId id, ImmunityType type);
|
||||
void InvalidateGroup(GroupId id);
|
||||
void AddGroupImmunity(GroupId id, GroupId other_id);
|
||||
unsigned int GetGroupImmunityCount(GroupId id);
|
||||
GroupId GetGroupImmunity(GroupId id, unsigned int number);
|
||||
void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule);
|
||||
bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule);
|
||||
void DumpAdminCache(AdminCachePart part, bool rebuild);
|
||||
void AddAdminListener(IAdminListener *pListener);
|
||||
void RemoveAdminListener(IAdminListener *pListener);
|
||||
/** User stuff */
|
||||
void RegisterAuthIdentType(const char *name);
|
||||
AdminId CreateAdmin(const char *name);
|
||||
const char *GetAdminName(AdminId id);
|
||||
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
|
||||
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
|
||||
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
|
||||
FlagBits GetAdminFlags(AdminId id, AccessMode mode);
|
||||
bool AdminInheritGroup(AdminId id, GroupId gid);
|
||||
unsigned int GetAdminGroupCount(AdminId id);
|
||||
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
|
||||
void SetAdminPassword(AdminId id, const char *password);
|
||||
const char *GetAdminPassword(AdminId id);
|
||||
AdminId FindAdminByIdentity(const char *auth, const char *identity);
|
||||
bool InvalidateAdmin(AdminId id);
|
||||
unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize);
|
||||
FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize);
|
||||
FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags);
|
||||
unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize);
|
||||
bool CheckAdminFlags(AdminId id, FlagBits bits);
|
||||
bool CanAdminTarget(AdminId id, AdminId target);
|
||||
void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
|
||||
bool FindFlag(const char *str, AdminFlag *pFlag);
|
||||
bool FindFlag(char c, AdminFlag *pAdmFlag);
|
||||
FlagBits ReadFlagString(const char *flags, const char **end);
|
||||
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
|
||||
unsigned int GetAdminSerialChange(AdminId id);
|
||||
bool CanAdminUseCommand(int client, const char *cmd);
|
||||
const char *GetGroupName(GroupId gid);
|
||||
unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
|
||||
unsigned int GetGroupImmunityLevel(GroupId gid);
|
||||
unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
|
||||
unsigned int GetAdminImmunityLevel(AdminId id);
|
||||
bool CheckAccess(int client,
|
||||
const char *cmd,
|
||||
FlagBits flags,
|
||||
bool override_only);
|
||||
bool FindFlagChar(AdminFlag flag, char *c);
|
||||
public:
|
||||
bool IsValidAdmin(AdminId id);
|
||||
void DumpCache(FILE *fp);
|
||||
AdminGroup *GetGroup(GroupId gid);
|
||||
AdminUser *GetUser(AdminId id);
|
||||
const char *GetString(int idx);
|
||||
private:
|
||||
void _UnsetCommandOverride(const char *cmd);
|
||||
void _UnsetCommandGroupOverride(const char *group);
|
||||
void InvalidateGroupCache();
|
||||
void InvalidateAdminCache(bool unlink_admins);
|
||||
void DumpCommandOverrideCache(OverrideType type);
|
||||
Trie *GetMethodByIndex(unsigned int index);
|
||||
bool GetMethodIndex(const char *name, unsigned int *_index);
|
||||
const char *GetMethodName(unsigned int index);
|
||||
void NameFlag(const char *str, AdminFlag flag);
|
||||
public:
|
||||
BaseStringTable *m_pStrings;
|
||||
BaseMemTable *m_pMemory;
|
||||
Trie *m_pCmdOverrides;
|
||||
Trie *m_pCmdGrpOverrides;
|
||||
int m_FirstGroup;
|
||||
int m_LastGroup;
|
||||
int m_FreeGroupList;
|
||||
Trie *m_pGroups;
|
||||
List<IAdminListener *> m_hooks;
|
||||
List<AuthMethod> m_AuthMethods;
|
||||
Trie *m_pAuthTables;
|
||||
IForward *m_pCacheFwd;
|
||||
int m_FirstUser;
|
||||
int m_LastUser;
|
||||
int m_FreeUserList;
|
||||
bool m_InvalidatingAdmins;
|
||||
bool m_destroying;
|
||||
Trie *m_pLevelNames;
|
||||
};
|
||||
|
||||
extern AdminCache g_Admins;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "CDataPack.h"
|
||||
|
||||
#define DATAPACK_INITIAL_SIZE 512
|
||||
|
||||
CDataPack::CDataPack()
|
||||
{
|
||||
m_pBase = (char *)malloc(DATAPACK_INITIAL_SIZE);
|
||||
m_capacity = DATAPACK_INITIAL_SIZE;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
CDataPack::~CDataPack()
|
||||
{
|
||||
free(m_pBase);
|
||||
}
|
||||
|
||||
void CDataPack::Initialize()
|
||||
{
|
||||
m_curptr = m_pBase;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void CDataPack::CheckSize(size_t typesize)
|
||||
{
|
||||
if (m_curptr - m_pBase + typesize <= m_capacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t pos = m_curptr - m_pBase;
|
||||
do
|
||||
{
|
||||
m_capacity *= 2;
|
||||
m_pBase = (char *)realloc(m_pBase, m_capacity);
|
||||
m_curptr = m_pBase + pos;
|
||||
} while (m_curptr - m_pBase + typesize > m_capacity);
|
||||
}
|
||||
|
||||
void CDataPack::ResetSize()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
size_t CDataPack::CreateMemory(size_t size, void **addr)
|
||||
{
|
||||
CheckSize(sizeof(size_t) + size);
|
||||
size_t pos = m_curptr - m_pBase;
|
||||
|
||||
*(size_t *)m_curptr = size;
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
*addr = m_curptr;
|
||||
}
|
||||
|
||||
m_curptr += size;
|
||||
m_size += sizeof(size_t) + size;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void CDataPack::PackCell(cell_t cell)
|
||||
{
|
||||
CheckSize(sizeof(size_t) + sizeof(cell_t));
|
||||
|
||||
*(size_t *)m_curptr = sizeof(cell_t);
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
*(cell_t *)m_curptr = cell;
|
||||
m_curptr += sizeof(cell_t);
|
||||
|
||||
m_size += sizeof(size_t) + sizeof(cell_t);
|
||||
}
|
||||
|
||||
void CDataPack::PackFloat(float val)
|
||||
{
|
||||
CheckSize(sizeof(size_t) + sizeof(float));
|
||||
|
||||
*(size_t *)m_curptr = sizeof(float);
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
*(float *)m_curptr = val;
|
||||
m_curptr += sizeof(float);
|
||||
|
||||
m_size += sizeof(size_t) + sizeof(float);
|
||||
}
|
||||
|
||||
void CDataPack::PackString(const char *string)
|
||||
{
|
||||
size_t len = strlen(string);
|
||||
size_t maxsize = sizeof(size_t) + len + 1;
|
||||
CheckSize(maxsize);
|
||||
|
||||
// Pack the string length first for buffer overrun checking.
|
||||
*(size_t *)m_curptr = len;
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
// Now pack the string.
|
||||
memcpy(m_curptr, string, len);
|
||||
m_curptr[len] = '\0';
|
||||
m_curptr += len + 1;
|
||||
|
||||
m_size += maxsize;
|
||||
}
|
||||
|
||||
void CDataPack::Reset() const
|
||||
{
|
||||
m_curptr = m_pBase;
|
||||
}
|
||||
|
||||
size_t CDataPack::GetPosition() const
|
||||
{
|
||||
return static_cast<size_t>(m_curptr - m_pBase);
|
||||
}
|
||||
|
||||
bool CDataPack::SetPosition(size_t pos) const
|
||||
{
|
||||
if (pos > m_size-1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_curptr = m_pBase + pos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cell_t CDataPack::ReadCell() const
|
||||
{
|
||||
if (!IsReadable(sizeof(size_t) + sizeof(cell_t)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
cell_t val = *reinterpret_cast<cell_t *>(m_curptr);
|
||||
m_curptr += sizeof(cell_t);
|
||||
return val;
|
||||
}
|
||||
|
||||
float CDataPack::ReadFloat() const
|
||||
{
|
||||
if (!IsReadable(sizeof(size_t) + sizeof(float)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
float val = *reinterpret_cast<float *>(m_curptr);
|
||||
m_curptr += sizeof(float);
|
||||
return val;
|
||||
}
|
||||
|
||||
bool CDataPack::IsReadable(size_t bytes) const
|
||||
{
|
||||
return (bytes + (m_curptr - m_pBase) > m_size) ? false : true;
|
||||
}
|
||||
|
||||
const char *CDataPack::ReadString(size_t *len) const
|
||||
{
|
||||
if (!IsReadable(sizeof(size_t)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t real_len = *(size_t *)m_curptr;
|
||||
|
||||
m_curptr += sizeof(size_t);
|
||||
char *str = (char *)m_curptr;
|
||||
|
||||
if ((strlen(str) != real_len) || !(IsReadable(real_len+1)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
*len = real_len;
|
||||
}
|
||||
|
||||
m_curptr += real_len + 1;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void *CDataPack::GetMemory() const
|
||||
{
|
||||
return m_curptr;
|
||||
}
|
||||
|
||||
void *CDataPack::ReadMemory(size_t *size) const
|
||||
{
|
||||
if (!IsReadable(sizeof(size_t)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t bytecount = *(size_t *)m_curptr;
|
||||
m_curptr += sizeof(size_t);
|
||||
|
||||
if (!IsReadable(bytecount))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ptr = m_curptr;
|
||||
|
||||
if (size)
|
||||
{
|
||||
*size = bytecount;
|
||||
}
|
||||
|
||||
m_curptr += bytecount;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Team Fortress 2 Extension
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
@@ -29,50 +29,43 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_HOLIDAY_H_
|
||||
#define _INCLUDE_SOURCEMOD_HOLIDAY_H_
|
||||
#ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
#define _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
|
||||
#include "extension.h"
|
||||
#include <ISDKTools.h>
|
||||
#include <IDataPack.h>
|
||||
|
||||
class HolidayManager : public IPluginsListener
|
||||
using namespace SourceMod;
|
||||
|
||||
class CDataPack : public IDataPack
|
||||
{
|
||||
public:
|
||||
HolidayManager();
|
||||
|
||||
CDataPack();
|
||||
~CDataPack();
|
||||
public: //IDataReader
|
||||
void Reset() const;
|
||||
size_t GetPosition() const;
|
||||
bool SetPosition(size_t pos) const;
|
||||
cell_t ReadCell() const;
|
||||
float ReadFloat() const;
|
||||
bool IsReadable(size_t bytes) const;
|
||||
const char *ReadString(size_t *len) const;
|
||||
void *GetMemory() const;
|
||||
void *ReadMemory(size_t *size) const;
|
||||
public: //IDataPack
|
||||
void ResetSize();
|
||||
void PackCell(cell_t cell);
|
||||
void PackFloat(float val);
|
||||
void PackString(const char *string);
|
||||
size_t CreateMemory(size_t size, void **addr);
|
||||
public:
|
||||
void OnSDKLoad(bool bLate);
|
||||
void OnSDKUnload();
|
||||
void OnServerActivated();
|
||||
|
||||
public: //IPluginsListener
|
||||
void OnPluginLoaded(IPlugin *plugin);
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
|
||||
public:
|
||||
bool Hook_IsHolidayActive(int holiday);
|
||||
void Hook_LevelShutdown();
|
||||
|
||||
void Initialize();
|
||||
private:
|
||||
bool IsHookEnabled() const { return m_iHookID != 0; }
|
||||
void *GetGameRules();
|
||||
void HookIfNecessary();
|
||||
void Unhook();
|
||||
|
||||
void CheckSize(size_t sizetype);
|
||||
private:
|
||||
int m_iHookID;
|
||||
IForward *m_isHolidayForward;
|
||||
bool m_bInMap;
|
||||
char *m_pBase;
|
||||
mutable char *m_curptr;
|
||||
size_t m_capacity;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
inline void *HolidayManager::GetGameRules()
|
||||
{
|
||||
if (!g_pSDKTools)
|
||||
return NULL;
|
||||
|
||||
return g_pSDKTools->GetGameRules();
|
||||
}
|
||||
|
||||
extern HolidayManager g_HolidayManager;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_HOLIDAY_H_
|
||||
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
@@ -29,17 +29,12 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_CELLARRAY_H_
|
||||
#define _INCLUDE_SOURCEMOD_CELLARRAY_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ICellArray.h>
|
||||
#include <amtl/am-bits.h>
|
||||
|
||||
extern HandleType_t htCellArray;
|
||||
|
||||
class CellArray : public ICellArray
|
||||
class CellArray
|
||||
{
|
||||
public:
|
||||
CellArray(size_t blocksize) : m_Data(NULL), m_BlockSize(blocksize), m_AllocSize(0), m_Size(0)
|
||||
@@ -51,31 +46,6 @@ public:
|
||||
free(m_Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a cell array object.
|
||||
*
|
||||
* @param blocksize The number of cells each member of the array can
|
||||
* hold. For example, 32 cells is equivalent to:
|
||||
* new Array[X][32]
|
||||
* @return A new ICellArray object.
|
||||
*/
|
||||
static ICellArray *New(size_t blocksize)
|
||||
{
|
||||
return new CellArray(blocksize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a cell array's resources.
|
||||
*
|
||||
* @param pack An ICellArray object to release.
|
||||
*/
|
||||
static void Free(ICellArray *arr)
|
||||
{
|
||||
delete arr;
|
||||
}
|
||||
|
||||
// ICellArray
|
||||
public:
|
||||
size_t size() const
|
||||
{
|
||||
return m_Size;
|
||||
@@ -181,18 +151,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
ICellArray *clone()
|
||||
CellArray *clone()
|
||||
{
|
||||
CellArray *array = new CellArray(m_BlockSize);
|
||||
array->m_AllocSize = m_AllocSize;
|
||||
array->m_Size = m_Size;
|
||||
array->m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
|
||||
if (!array->m_Data)
|
||||
{
|
||||
delete array;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(array->m_Data, m_Data, sizeof(cell_t) * m_BlockSize * m_Size);
|
||||
return array;
|
||||
}
|
||||
@@ -215,34 +179,24 @@ private:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
size_t newAllocSize = m_AllocSize;
|
||||
/* Set a base allocation size of 8 items */
|
||||
if (!newAllocSize)
|
||||
if (!m_AllocSize)
|
||||
{
|
||||
newAllocSize = 8;
|
||||
}
|
||||
if (!ke::IsUintPtrAddSafe(m_Size, count))
|
||||
{
|
||||
return false;
|
||||
m_AllocSize = 8;
|
||||
}
|
||||
/* If it's not enough, keep doubling */
|
||||
while (m_Size + count > newAllocSize)
|
||||
while (m_Size + count > m_AllocSize)
|
||||
{
|
||||
if (!ke::IsUintPtrMultiplySafe(newAllocSize, 2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
newAllocSize *= 2;
|
||||
m_AllocSize *= 2;
|
||||
}
|
||||
/* finally, allocate the new block */
|
||||
cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * newAllocSize));
|
||||
/* Update state if allocation was successful */
|
||||
if (data)
|
||||
if (m_Data)
|
||||
{
|
||||
m_AllocSize = newAllocSize;
|
||||
m_Data = data;
|
||||
m_Data = (cell_t *)realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize);
|
||||
} else {
|
||||
m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize);
|
||||
}
|
||||
return (data != nullptr);
|
||||
return (m_Data != NULL);
|
||||
}
|
||||
private:
|
||||
cell_t *m_Data;
|
||||
@@ -250,6 +204,3 @@ private:
|
||||
size_t m_AllocSize;
|
||||
size_t m_Size;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_CELLARRAY_H_ */
|
||||
|
||||
@@ -81,17 +81,11 @@ inline int CellRecipientFilter::GetRecipientCount() const
|
||||
|
||||
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
|
||||
{
|
||||
int ret;
|
||||
if ((slot < 0) || (slot >= GetRecipientCount()))
|
||||
{
|
||||
ret = -1;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = static_cast<int>(m_Players[slot]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return static_cast<int>(m_Players[slot]);
|
||||
}
|
||||
|
||||
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
|
||||
|
||||
+184
-244
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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
|
||||
@@ -29,78 +29,71 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <ITextParsers.h>
|
||||
#include "ChatTriggers.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "ConCmdManager.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "Translator.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "sourcemod.h"
|
||||
#include "provider.h"
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
/* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
|
||||
* While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one
|
||||
* can technically be compiled against any MM:S version after 1.4.2.
|
||||
*/
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
|
||||
#else
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#if SH_IMPL_VERSION >= 5
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#elif SH_IMPL_VERSION == 4
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#elif SH_IMPL_VERSION == 3
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#endif //SH_IMPL_VERSION
|
||||
#endif //SE_ORANGEBOX
|
||||
|
||||
ChatTriggers g_ChatTriggers;
|
||||
bool g_bSupressSilentFails = false;
|
||||
|
||||
ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false),
|
||||
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
|
||||
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
|
||||
m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
|
||||
{
|
||||
m_PubTrigger = "!";
|
||||
m_PrivTrigger = "/";
|
||||
m_PubTrigger = sm_strdup("!");
|
||||
m_PrivTrigger = sm_strdup("/");
|
||||
m_PubTriggerSize = 1;
|
||||
m_PrivTriggerSize = 1;
|
||||
m_bIsChatTrigger = false;
|
||||
m_bPluginIgnored = true;
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
m_bIsINS = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
ChatTriggers::~ChatTriggers()
|
||||
{
|
||||
delete [] m_ArgSBackup;
|
||||
m_ArgSBackup = NULL;
|
||||
delete [] m_PubTrigger;
|
||||
m_PubTrigger = NULL;
|
||||
delete [] m_PrivTrigger;
|
||||
m_PrivTrigger = NULL;
|
||||
}
|
||||
|
||||
void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
|
||||
{
|
||||
std::unique_ptr<char[]> filtered(new char[strlen(value) + 1]);
|
||||
|
||||
const char *src = value;
|
||||
char *dest = filtered.get();
|
||||
char c;
|
||||
while ((c = *src++) != '\0') {
|
||||
if (c <= ' ' || c == '"' || c == '\'' || (c >= '0' && c <= '9') || c == ';' || (c >= 'A' && c <= 'Z') || c == '\\' || (c >= 'a' && c <= 'z') || c >= 0x7F) {
|
||||
logger->LogError("Ignoring %s chat trigger character '%c', not in valid set: %s", (type == ChatTrigger_Private ? "silent" : "public"), c, "!#$%&()*+,-./:<=>?@[]^_`{|}~");
|
||||
continue;
|
||||
}
|
||||
*dest++ = c;
|
||||
}
|
||||
*dest = '\0';
|
||||
|
||||
if (type == ChatTrigger_Private) {
|
||||
m_PrivTrigger = filtered.get();
|
||||
} else {
|
||||
m_PubTrigger = filtered.get();
|
||||
}
|
||||
}
|
||||
|
||||
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
char *error,
|
||||
size_t maxlength)
|
||||
{
|
||||
if (strcmp(key, "PublicChatTrigger") == 0)
|
||||
{
|
||||
SetChatTrigger(ChatTrigger_Public, value);
|
||||
delete [] m_PubTrigger;
|
||||
m_PubTrigger = sm_strdup(value);
|
||||
m_PubTriggerSize = strlen(m_PubTrigger);
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
else if (strcmp(key, "SilentChatTrigger") == 0)
|
||||
{
|
||||
SetChatTrigger(ChatTrigger_Private, value);
|
||||
delete [] m_PrivTrigger;
|
||||
m_PrivTrigger = sm_strdup(value);
|
||||
m_PrivTriggerSize = strlen(m_PrivTrigger);
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
else if (strcmp(key, "SilentFailSuppress") == 0)
|
||||
@@ -114,238 +107,204 @@ ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
|
||||
|
||||
void ChatTriggers::OnSourceModAllInitialized()
|
||||
{
|
||||
m_pShouldFloodBlock = forwardsys->CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
|
||||
m_pDidFloodBlock = forwardsys->CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
|
||||
m_pOnClientSayCmd = forwardsys->CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String);
|
||||
m_pOnClientSayCmd_Post = forwardsys->CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
|
||||
m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
|
||||
m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
logicore.AddCorePhraseFile("antiflood.phrases");
|
||||
g_pCorePhrases->AddPhraseFile("antiflood.phrases");
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModGameInitialized()
|
||||
{
|
||||
ConCommand *say_team = FindCommand("say_team");
|
||||
m_pSayCmd = FindCommand("say");
|
||||
m_pSayTeamCmd = FindCommand("say_team");
|
||||
|
||||
CommandHook::Callback pre_hook = [this] (int client, const ICommandArgs *args) -> bool {
|
||||
return this->OnSayCommand_Pre(client, args);
|
||||
};
|
||||
CommandHook::Callback post_hook = [this] (int client, const ICommandArgs *args) -> bool {
|
||||
return this->OnSayCommand_Post(client, args);
|
||||
};
|
||||
|
||||
if (ConCommand *say = FindCommand("say")) {
|
||||
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say, pre_hook));
|
||||
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say, post_hook));
|
||||
if (m_pSayCmd)
|
||||
{
|
||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
}
|
||||
if (ConCommand *say_team = FindCommand("say_team")) {
|
||||
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_team, pre_hook));
|
||||
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook));
|
||||
if (m_pSayTeamCmd)
|
||||
{
|
||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
||||
if (m_bIsINS) {
|
||||
if (ConCommand *say2 = FindCommand("say2")) {
|
||||
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say2, pre_hook));
|
||||
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say2, post_hook));
|
||||
}
|
||||
}
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
if (ConCommand *say_squad = FindCommand("say_squad")) {
|
||||
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook));
|
||||
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModShutdown()
|
||||
{
|
||||
hooks_.clear();
|
||||
if (m_pSayTeamCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
}
|
||||
if (m_pSayCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
}
|
||||
|
||||
forwardsys->ReleaseForward(m_pShouldFloodBlock);
|
||||
forwardsys->ReleaseForward(m_pDidFloodBlock);
|
||||
forwardsys->ReleaseForward(m_pOnClientSayCmd);
|
||||
forwardsys->ReleaseForward(m_pOnClientSayCmd_Post);
|
||||
g_Forwards.ReleaseForward(m_pShouldFloodBlock);
|
||||
g_Forwards.ReleaseForward(m_pDidFloodBlock);
|
||||
}
|
||||
|
||||
bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
void ChatTriggers::OnSayCommand_Pre()
|
||||
{
|
||||
CCommand command;
|
||||
#endif
|
||||
int client;
|
||||
CPlayer *pPlayer;
|
||||
|
||||
client = g_ConCmds.GetCommandClient();
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
m_bPluginIgnored = true;
|
||||
|
||||
const char *args = command->ArgS();
|
||||
|
||||
if (!args)
|
||||
return false;
|
||||
|
||||
/* Save these off for post hook as the command data returned from the engine in older engine versions
|
||||
* can be NULL, despite the data still being there and valid. */
|
||||
m_Arg0Backup = command->Arg(0);
|
||||
size_t len = strlen(args);
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (m_bIsINS)
|
||||
{
|
||||
if (strcmp(m_Arg0Backup, "say2") == 0 && len >= 4)
|
||||
{
|
||||
args += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The first pair of quotes are stripped from client say commands, but not console ones.
|
||||
* We do not want the forwards to differ from what is displayed.
|
||||
* So only strip the first pair of quotes from client say commands. */
|
||||
bool is_quoted = false;
|
||||
|
||||
if (
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
!m_bIsINS &&
|
||||
#endif
|
||||
client != 0 && args[0] == '"' && args[len-1] == '"')
|
||||
{
|
||||
/* The server normally won't display empty say commands, but in this case it does.
|
||||
* I don't think it's desired so let's block it. */
|
||||
if (len <= 2)
|
||||
return true;
|
||||
|
||||
args++;
|
||||
len--;
|
||||
is_quoted = true;
|
||||
}
|
||||
|
||||
/* Some? engines strip the last quote when printing the string to chat.
|
||||
* This results in having a double-quoted message passed to the OnClientSayCommand ("message") forward,
|
||||
* but losing the last quote in the OnClientSayCommand_Post ("message) forward.
|
||||
* To compensate this, we copy the args into our own buffer where the engine won't mess with
|
||||
* and strip the quotes. */
|
||||
delete [] m_ArgSBackup;
|
||||
m_ArgSBackup = new char[CCommand::MaxCommandLength()+1];
|
||||
memcpy(m_ArgSBackup, args, len+1);
|
||||
|
||||
/* Strip the quotes from the argument */
|
||||
if (is_quoted)
|
||||
{
|
||||
if (m_ArgSBackup[len-1] == '"')
|
||||
{
|
||||
m_ArgSBackup[--len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* The server console cannot do this */
|
||||
if (client == 0)
|
||||
if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
|
||||
{
|
||||
if (CallOnClientSayCommand(client) >= Pl_Handled)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
|
||||
/* We guarantee the client is connected */
|
||||
if (!pPlayer || !pPlayer->IsConnected())
|
||||
return false;
|
||||
if (!pPlayer->IsConnected())
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
const char *args = command.ArgS();
|
||||
|
||||
if (!args)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/* Check if we need to block this message from being sent */
|
||||
if (ClientIsFlooding(client))
|
||||
{
|
||||
char buffer[128];
|
||||
|
||||
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client))
|
||||
ke::SafeSprintf(buffer, sizeof(buffer), "You are flooding the server!");
|
||||
if (!CoreTranslate(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%T",
|
||||
2,
|
||||
NULL,
|
||||
"Flooding the server",
|
||||
&client))
|
||||
{
|
||||
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
|
||||
}
|
||||
|
||||
/* :TODO: we should probably kick people who spam too much. */
|
||||
|
||||
char fullbuffer[192];
|
||||
ke::SafeSprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
|
||||
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s", buffer);
|
||||
g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
|
||||
|
||||
m_bWasFloodedMessage = true;
|
||||
return true;
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
/* Handle quoted string sets */
|
||||
bool is_quoted = false;
|
||||
if (args[0] == '"')
|
||||
{
|
||||
args++;
|
||||
is_quoted = true;
|
||||
}
|
||||
|
||||
bool is_trigger = false;
|
||||
bool is_silent = false;
|
||||
|
||||
// Prefer the silent trigger in case of clashes.
|
||||
if (strchr(m_PrivTrigger.c_str(), m_ArgSBackup[0])) {
|
||||
/* Check for either trigger */
|
||||
if (m_PubTriggerSize && strncmp(args, m_PubTrigger, m_PubTriggerSize) == 0)
|
||||
{
|
||||
is_trigger = true;
|
||||
args = &args[m_PubTriggerSize];
|
||||
}
|
||||
else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0)
|
||||
{
|
||||
is_trigger = true;
|
||||
is_silent = true;
|
||||
} else if (strchr(m_PubTrigger.c_str(), m_ArgSBackup[0])) {
|
||||
is_trigger = true;
|
||||
args = &args[m_PrivTriggerSize];
|
||||
}
|
||||
|
||||
if (is_trigger) {
|
||||
// Bump the args past the chat trigger - we only support single-character triggers now.
|
||||
args = &m_ArgSBackup[1];
|
||||
if (!is_trigger)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this is actually a command!
|
||||
*/
|
||||
if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args))
|
||||
if (!PreProcessTrigger(PEntityOfEntIndex(client), args, is_quoted))
|
||||
{
|
||||
m_bIsChatTrigger = true;
|
||||
|
||||
/**
|
||||
* We'll execute it in post.
|
||||
*/
|
||||
m_bWillProcessInPost = true;
|
||||
CPlayer *pPlayer;
|
||||
if (is_silent
|
||||
&& g_bSupressSilentFails
|
||||
&& client != 0
|
||||
&& (pPlayer = g_Players.GetPlayerByIndex(client)) != NULL
|
||||
&& pPlayer->GetAdminId() != INVALID_ADMIN_ID)
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
|
||||
return true;
|
||||
m_bIsChatTrigger = true;
|
||||
|
||||
if (CallOnClientSayCommand(client) >= Pl_Handled)
|
||||
return true;
|
||||
/**
|
||||
* We'll execute it in post.
|
||||
*/
|
||||
m_bWillProcessInPost = true;
|
||||
m_bTriggerWasSilent = is_silent;
|
||||
|
||||
/* If we're silent, block */
|
||||
if (is_silent)
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
/* Otherwise, let the command continue */
|
||||
return false;
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool ChatTriggers::OnSayCommand_Post(int client, const ICommandArgs *command)
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
|
||||
#else
|
||||
void ChatTriggers::OnSayCommand_Post()
|
||||
#endif
|
||||
{
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
if (m_bWillProcessInPost)
|
||||
{
|
||||
/* Reset this for re-entrancy */
|
||||
m_bWillProcessInPost = false;
|
||||
|
||||
|
||||
/* Execute the cached command */
|
||||
int client = g_ConCmds.GetCommandClient();
|
||||
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
|
||||
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
|
||||
SetReplyTo(old);
|
||||
}
|
||||
|
||||
if (!m_bPluginIgnored && m_pOnClientSayCmd_Post->GetFunctionCount() != 0)
|
||||
{
|
||||
m_pOnClientSayCmd_Post->PushCell(client);
|
||||
m_pOnClientSayCmd_Post->PushString(m_Arg0Backup);
|
||||
m_pOnClientSayCmd_Post->PushString(m_ArgSBackup);
|
||||
m_pOnClientSayCmd_Post->Execute(NULL);
|
||||
}
|
||||
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
||||
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
|
||||
{
|
||||
/* Extract a command. This is kind of sloppy. */
|
||||
/* Extract a command. This is kind of sloppy. */
|
||||
char cmd_buf[64];
|
||||
size_t cmd_len = 0;
|
||||
const char *inptr = args;
|
||||
while (*inptr != '\0'
|
||||
&& !textparsers->IsWhitespace(inptr)
|
||||
while (*inptr != '\0'
|
||||
&& !textparsers->IsWhitespace(inptr)
|
||||
&& *inptr != '"'
|
||||
&& cmd_len < sizeof(cmd_buf) - 1)
|
||||
{
|
||||
@@ -363,54 +322,55 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
||||
if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
|
||||
{
|
||||
/* Check if we had an "sm_" prefix */
|
||||
if (strncasecmp(cmd_buf, "sm_", 3) == 0)
|
||||
if (strncmp(cmd_buf, "sm_", 3) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now, prepend. Don't worry about the buffers. This will
|
||||
/* Now, prepend. Don't worry about the buffers. This will
|
||||
* work because the sizes are limited from earlier.
|
||||
*/
|
||||
char new_buf[80];
|
||||
strcpy(new_buf, "sm_");
|
||||
ke::SafeStrcpy(&new_buf[3], sizeof(new_buf)-3, cmd_buf);
|
||||
strncopy(&new_buf[3], cmd_buf, sizeof(new_buf)-3);
|
||||
|
||||
/* Recheck */
|
||||
if (!g_ConCmds.LookForSourceModCommand(new_buf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
prepended = true;
|
||||
}
|
||||
|
||||
/* See if we need to do extra string manipulation */
|
||||
if (prepended)
|
||||
if (is_quoted || prepended)
|
||||
{
|
||||
ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
|
||||
size_t len;
|
||||
|
||||
/* Check if we need to prepend sm_ */
|
||||
if (prepended)
|
||||
{
|
||||
len = UTIL_Format(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
|
||||
} else {
|
||||
len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
||||
}
|
||||
|
||||
/* Check if we need to strip a quote */
|
||||
if (is_quoted)
|
||||
{
|
||||
if (m_ToExecute[len-1] == '"')
|
||||
{
|
||||
m_ToExecute[--len] = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
||||
strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cell_t ChatTriggers::CallOnClientSayCommand(int client)
|
||||
{
|
||||
cell_t res = Pl_Continue;
|
||||
if (m_pOnClientSayCmd->GetFunctionCount() != 0)
|
||||
{
|
||||
m_pOnClientSayCmd->PushCell(client);
|
||||
m_pOnClientSayCmd->PushString(m_Arg0Backup);
|
||||
m_pOnClientSayCmd->PushString(m_ArgSBackup);
|
||||
m_pOnClientSayCmd->Execute(&res);
|
||||
}
|
||||
|
||||
m_bPluginIgnored = (res >= Pl_Stop);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
|
||||
{
|
||||
unsigned int old = m_ReplyTo;
|
||||
@@ -461,23 +421,3 @@ bool ChatTriggers::WasFloodedMessage()
|
||||
{
|
||||
return m_bWasFloodedMessage;
|
||||
}
|
||||
|
||||
const char *ChatTriggers::GetPublicChatTrigger()
|
||||
{
|
||||
if (!m_PubTrigger.length())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_PubTrigger.c_str();
|
||||
}
|
||||
|
||||
const char *ChatTriggers::GetPrivateChatTrigger()
|
||||
{
|
||||
if (!m_PrivTrigger.length())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_PrivTrigger.c_str();
|
||||
}
|
||||
|
||||
+20
-29
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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
|
||||
@@ -34,11 +34,9 @@
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "GameHooks.h"
|
||||
#include <IGameHelpers.h>
|
||||
#include <compat_wrappers.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
class ChatTriggers : public SMGlobalClass
|
||||
{
|
||||
@@ -50,49 +48,42 @@ public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized_Post();
|
||||
void OnSourceModGameInitialized();
|
||||
void OnSourceModShutdown();
|
||||
ConfigResult OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigResult OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
private: //ConCommand
|
||||
bool OnSayCommand_Pre(int client, const ICommandArgs *args);
|
||||
bool OnSayCommand_Post(int client, const ICommandArgs *args);
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnSayCommand_Pre(const CCommand &command);
|
||||
void OnSayCommand_Post(const CCommand &command);
|
||||
#else
|
||||
void OnSayCommand_Pre();
|
||||
void OnSayCommand_Post();
|
||||
#endif
|
||||
public:
|
||||
unsigned int GetReplyTo();
|
||||
unsigned int SetReplyTo(unsigned int reply);
|
||||
bool IsChatTrigger();
|
||||
bool WasFloodedMessage();
|
||||
const char *GetPublicChatTrigger();
|
||||
const char *GetPrivateChatTrigger();
|
||||
private:
|
||||
enum ChatTriggerType {
|
||||
ChatTrigger_Public,
|
||||
ChatTrigger_Private,
|
||||
};
|
||||
void SetChatTrigger(ChatTriggerType type, const char *value);
|
||||
bool PreProcessTrigger(edict_t *pEdict, const char *args);
|
||||
bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
|
||||
bool ClientIsFlooding(int client);
|
||||
cell_t CallOnClientSayCommand(int client);
|
||||
private:
|
||||
std::vector<ke::RefPtr<CommandHook>> hooks_;
|
||||
std::string m_PubTrigger;
|
||||
std::string m_PrivTrigger;
|
||||
ConCommand *m_pSayCmd;
|
||||
ConCommand *m_pSayTeamCmd;
|
||||
char *m_PubTrigger;
|
||||
size_t m_PubTriggerSize;
|
||||
char *m_PrivTrigger;
|
||||
size_t m_PrivTriggerSize;
|
||||
bool m_bWillProcessInPost;
|
||||
bool m_bTriggerWasSilent;
|
||||
bool m_bIsChatTrigger;
|
||||
bool m_bWasFloodedMessage;
|
||||
bool m_bPluginIgnored;
|
||||
unsigned int m_ReplyTo;
|
||||
char m_ToExecute[300];
|
||||
const char *m_Arg0Backup;
|
||||
char *m_ArgSBackup;
|
||||
IForward *m_pShouldFloodBlock;
|
||||
IForward *m_pDidFloodBlock;
|
||||
IForward *m_pOnClientSayCmd;
|
||||
IForward *m_pOnClientSayCmd_Post;
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
bool m_bIsINS;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern ChatTriggers g_ChatTriggers;
|
||||
|
||||
+641
-256
File diff suppressed because it is too large
Load Diff
+51
-88
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -32,120 +32,77 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||
#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <am-inlinelist.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <am-utility.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <IForwardSys.h>
|
||||
#include "ForwardSys.h"
|
||||
#include "sm_trie.h"
|
||||
#include "sm_memtable.h"
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <IAdminSystem.h>
|
||||
#include "concmd_cleaner.h"
|
||||
#include "GameHooks.h"
|
||||
#include <sm_namehashset.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct CmdHook;
|
||||
struct ConCmdInfo;
|
||||
|
||||
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
||||
enum CmdType
|
||||
{
|
||||
std::list<CmdHook *> hooks;
|
||||
Cmd_Server,
|
||||
Cmd_Console,
|
||||
Cmd_Admin,
|
||||
};
|
||||
|
||||
struct AdminCmdInfo
|
||||
{
|
||||
AdminCmdInfo(const ke::RefPtr<CommandGroup> &group, FlagBits flags)
|
||||
: group(group),
|
||||
flags(flags),
|
||||
eflags(0)
|
||||
AdminCmdInfo()
|
||||
{
|
||||
cmdGrpId = -1;
|
||||
flags = 0;
|
||||
eflags = 0;
|
||||
}
|
||||
ke::RefPtr<CommandGroup> group;
|
||||
int cmdGrpId; /* index into cmdgroup string table */
|
||||
FlagBits flags; /* default flags */
|
||||
FlagBits eflags; /* effective flags */
|
||||
};
|
||||
|
||||
struct CmdHook : public ke::InlineListNode<CmdHook>
|
||||
struct CmdHook
|
||||
{
|
||||
enum Type {
|
||||
Server,
|
||||
Client
|
||||
};
|
||||
|
||||
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description, IPlugin *plugin)
|
||||
: type(type),
|
||||
info(cmd),
|
||||
pf(fun),
|
||||
plugin(plugin),
|
||||
helptext(description)
|
||||
CmdHook()
|
||||
{
|
||||
pf = NULL;
|
||||
pAdmin = NULL;
|
||||
}
|
||||
|
||||
Type type;
|
||||
ConCmdInfo *info;
|
||||
IPluginFunction *pf; /* function hook */
|
||||
IPlugin *plugin; /* owning plugin */
|
||||
std::string helptext; /* help text */
|
||||
std::unique_ptr<AdminCmdInfo> admin; /* admin requirements, if any */
|
||||
IPluginFunction *pf; /* function hook */
|
||||
String helptext; /* help text */
|
||||
AdminCmdInfo *pAdmin; /* admin requirements, if any */
|
||||
};
|
||||
|
||||
typedef ke::InlineList<CmdHook> CmdHookList;
|
||||
|
||||
struct ConCmdInfo
|
||||
{
|
||||
ConCmdInfo()
|
||||
{
|
||||
pPlugin = nullptr;
|
||||
sourceMod = false;
|
||||
pCmd = nullptr;
|
||||
eflags = 0;
|
||||
pCmd = NULL;
|
||||
}
|
||||
|
||||
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
||||
ConCommand *pCmd; /**< Pointer to the command itself */
|
||||
CmdHookList hooks; /**< Hook list */
|
||||
FlagBits eflags; /**< Effective admin flags */
|
||||
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
|
||||
IPlugin *pPlugin; /**< Owning plugin handle. */
|
||||
|
||||
struct ConCmdPolicy
|
||||
{
|
||||
static inline bool matches(const char *name, ConCmdInfo *info)
|
||||
{
|
||||
const char *conCmdChars = info->pCmd->GetName();
|
||||
|
||||
std::string concmdName = ke::Lowercase(conCmdChars);
|
||||
std::string input = ke::Lowercase(name);
|
||||
|
||||
return concmdName == input;
|
||||
}
|
||||
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
std::string lower = ke::Lowercase(key.c_str());
|
||||
return detail::CharsAndLength(lower.c_str()).hash();
|
||||
}
|
||||
};
|
||||
List<CmdHook *> srvhooks; /**< Hooks as a server command */
|
||||
List<CmdHook *> conhooks; /**< Hooks as a console command */
|
||||
AdminCmdInfo admin; /**< Admin info, if any */
|
||||
bool is_admin_set; /**< Whether or not admin info is set */
|
||||
};
|
||||
|
||||
typedef List<ConCmdInfo *> ConCmdList;
|
||||
|
||||
class ConCmdManager :
|
||||
public SMGlobalClass,
|
||||
public IRootConsoleCommand,
|
||||
public IPluginsListener,
|
||||
public IConCommandTracker
|
||||
{
|
||||
friend void CommandCallback(DISPATCH_ARGS);
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
friend void CommandCallback(const CCommand &command);
|
||||
#else
|
||||
friend void CommandCallback();
|
||||
#endif
|
||||
public:
|
||||
ConCmdManager();
|
||||
~ConCmdManager();
|
||||
@@ -155,44 +112,50 @@ public: //SMGlobalClass
|
||||
public: //IPluginsListener
|
||||
void OnPluginDestroyed(IPlugin *plugin);
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override;
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public: //IConCommandTracker
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override;
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||
public:
|
||||
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags, IPlugin *pPlugin);
|
||||
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
|
||||
bool AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
|
||||
bool AddAdminCommand(IPluginFunction *pFunction,
|
||||
const char *name,
|
||||
const char *group,
|
||||
int adminflags,
|
||||
const char *description,
|
||||
int flags,
|
||||
IPlugin *pPlugin);
|
||||
int flags);
|
||||
ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type);
|
||||
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
|
||||
bool LookForSourceModCommand(const char *cmd);
|
||||
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
|
||||
bool CheckCommandAccess(int client, const char *cmd, FlagBits flags);
|
||||
private:
|
||||
bool InternalDispatch(int client, const ICommandArgs *args);
|
||||
void InternalDispatch(const CCommand &command);
|
||||
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
|
||||
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags, IPlugin *pPlugin);
|
||||
ConCmdInfo *AddOrFindCommand(const char *name, const char *description, int flags);
|
||||
void SetCommandClient(int client);
|
||||
void AddToCmdList(ConCmdInfo *info);
|
||||
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
|
||||
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool is_read_safe, bool untrack);
|
||||
void RemoveConCmds(List<CmdHook *> &cmdlist);
|
||||
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
|
||||
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
||||
ConCmdInfo *FindInTrie(const char *name);
|
||||
public:
|
||||
inline int GetCommandClient()
|
||||
{
|
||||
return m_CmdClient;
|
||||
}
|
||||
inline const List<ConCmdInfo *> & GetCommandList()
|
||||
{
|
||||
return m_CmdList;
|
||||
}
|
||||
private:
|
||||
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap;
|
||||
|
||||
NameHashSet<ConCmdInfo *, ConCmdInfo::ConCmdPolicy> m_Cmds; /* command lookup */
|
||||
GroupMap m_CmdGrps; /* command group map */
|
||||
ConCmdList m_CmdList; /* command list */
|
||||
Trie *m_pCmds; /* command lookup */
|
||||
Trie *m_pCmdGrps; /* command group lookup */
|
||||
List<ConCmdInfo *> m_CmdList; /* command list */
|
||||
int m_CmdClient; /* current client */
|
||||
BaseStringTable m_Strings; /* string table */
|
||||
};
|
||||
|
||||
extern ConCmdManager g_ConCmds;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#ifndef _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
|
||||
#define _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
class ConCommandBaseIterator
|
||||
{
|
||||
public:
|
||||
inline ConCommandBaseIterator() : iter(icvar)
|
||||
{
|
||||
iter.SetFirst();
|
||||
}
|
||||
|
||||
inline bool IsValid()
|
||||
{
|
||||
return iter.IsValid();
|
||||
}
|
||||
|
||||
inline void Next()
|
||||
{
|
||||
iter.Next();
|
||||
}
|
||||
|
||||
inline ConCommandBase *Get()
|
||||
{
|
||||
return iter.Get();
|
||||
}
|
||||
private:
|
||||
ICvar::Iterator iter;
|
||||
};
|
||||
#else
|
||||
class ConCommandBaseIterator
|
||||
{
|
||||
public:
|
||||
inline ConCommandBaseIterator()
|
||||
{
|
||||
iter = icvar->GetCommands();
|
||||
}
|
||||
|
||||
inline bool IsValid()
|
||||
{
|
||||
return iter != NULL;
|
||||
}
|
||||
|
||||
inline void Next()
|
||||
{
|
||||
iter = const_cast<ConCommandBase *>(iter->GetNext());
|
||||
}
|
||||
|
||||
inline ConCommandBase *Get()
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
private:
|
||||
ConCommandBase *iter;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_ */
|
||||
|
||||
+171
-196
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -25,63 +25,42 @@
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ConVarManager.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ForwardSys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "sm_srvcmds.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include <sh_vector.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "logic_bridge.h"
|
||||
#include "sourcemod.h"
|
||||
#include "provider.h"
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
|
||||
ConVarManager g_ConVarManager;
|
||||
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
#define CallGlobalChangeCallbacks CallGlobalChangeCallback
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
|
||||
#else
|
||||
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||
#endif
|
||||
|
||||
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
||||
typedef List<const ConVar *> ConVarList;
|
||||
NameHashSet<ConVarInfo *, ConVarInfo::ConVarPolicy> convar_cache;
|
||||
KTrie<ConVarInfo *> convar_cache;
|
||||
|
||||
enum {
|
||||
eQueryCvarValueStatus_Cancelled = -1,
|
||||
};
|
||||
|
||||
class ConVarReentrancyGuard
|
||||
{
|
||||
ConVar *cvar;
|
||||
ConVarReentrancyGuard *up;
|
||||
public:
|
||||
static ConVarReentrancyGuard *chain;
|
||||
|
||||
ConVarReentrancyGuard(ConVar *cvar)
|
||||
: cvar(cvar), up(chain)
|
||||
{
|
||||
chain = this;
|
||||
}
|
||||
|
||||
~ConVarReentrancyGuard()
|
||||
{
|
||||
assert(chain == this);
|
||||
chain = up;
|
||||
}
|
||||
|
||||
static bool IsCvarInChain(ConVar *cvar)
|
||||
{
|
||||
ConVarReentrancyGuard *guard = chain;
|
||||
while (guard != NULL)
|
||||
{
|
||||
if (guard->cvar == cvar)
|
||||
return true;
|
||||
guard = guard->up;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
ConVarReentrancyGuard *ConVarReentrancyGuard::chain = NULL;
|
||||
|
||||
ConVarManager::ConVarManager() : m_ConVarType(0)
|
||||
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -99,17 +78,26 @@ void ConVarManager::OnSourceModStartup(bool late)
|
||||
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
||||
|
||||
/* Create the 'ConVar' handle type */
|
||||
m_ConVarType = handlesys->CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||
m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
void ConVarManager::OnSourceModAllInitialized()
|
||||
{
|
||||
g_Players.AddClientListener(this);
|
||||
/**
|
||||
* Episode 2 has this function by default, but the older versions do not.
|
||||
*/
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (g_SMAPI->GetGameDLLVersion() >= 6)
|
||||
{
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
m_bIsDLLQueryHooked = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
scripts->AddPluginsListener(this);
|
||||
SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
|
||||
|
||||
/* Add the 'convars' option to the 'sm' console command */
|
||||
rootmenu->AddRootConsoleCommand3("cvars", "View convars created by a plugin", this);
|
||||
g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
|
||||
}
|
||||
|
||||
void ConVarManager::OnSourceModShutdown()
|
||||
@@ -124,10 +112,10 @@ void ConVarManager::OnSourceModShutdown()
|
||||
|
||||
iter = m_ConVars.erase(iter);
|
||||
|
||||
handlesys->FreeHandle(pInfo->handle, &sec);
|
||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
||||
if (pInfo->pChangeForward != NULL)
|
||||
{
|
||||
forwardsys->ReleaseForward(pInfo->pChangeForward);
|
||||
g_Forwards.ReleaseForward(pInfo->pChangeForward);
|
||||
}
|
||||
if (pInfo->sourceMod)
|
||||
{
|
||||
@@ -155,23 +143,77 @@ void ConVarManager::OnSourceModShutdown()
|
||||
}
|
||||
convar_cache.clear();
|
||||
|
||||
g_Players.RemoveClientListener(this);
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
/* Unhook things */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
m_bIsDLLQueryHooked = false;
|
||||
}
|
||||
else if (m_bIsVSPQueryHooked)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
m_bIsVSPQueryHooked = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
SH_REMOVE_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
|
||||
|
||||
/* Remove the 'convars' option from the 'sm' console command */
|
||||
rootmenu->RemoveRootConsoleCommand("cvars", this);
|
||||
|
||||
scripts->RemovePluginsListener(this);
|
||||
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
|
||||
|
||||
/* Remove the 'ConVar' handle type */
|
||||
handlesys->RemoveType(m_ConVarType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orange Box will never use this.
|
||||
*/
|
||||
void ConVarManager::OnSourceModVSPReceived()
|
||||
{
|
||||
/**
|
||||
* Don't bother if the DLL is already hooked.
|
||||
*/
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* For later MM:S versions, use the updated API, since it's cleaner. */
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
int engine = g_SMAPI->GetSourceEngineBuild();
|
||||
if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (g_HL2.IsOriginalEngine() || vsp_version < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
m_bIsVSPQueryHooked = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
|
||||
{
|
||||
return convar_cache.retrieve(name, pVar);
|
||||
ConVarInfo **pLookup = convar_cache.retrieve(name);
|
||||
if (pLookup != NULL)
|
||||
{
|
||||
*pVar = *pLookup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name)
|
||||
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
|
||||
{
|
||||
/* Only check convars that have not been created by SourceMod's core */
|
||||
ConVarInfo *pInfo;
|
||||
@@ -187,7 +229,7 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
||||
convar_cache.remove(name);
|
||||
|
||||
/* Now make sure no plugins are referring to this pointer */
|
||||
IPluginIterator *pl_iter = scripts->GetPluginIterator();
|
||||
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
|
||||
while (pl_iter->MorePlugins())
|
||||
{
|
||||
IPlugin *pl = pl_iter->GetPlugin();
|
||||
@@ -203,73 +245,19 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
||||
}
|
||||
|
||||
/* Free resources */
|
||||
handlesys->FreeHandle(pInfo->handle, &sec);
|
||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
||||
delete pInfo;
|
||||
}
|
||||
|
||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
ConVarList *pConVarList;
|
||||
|
||||
/* If plugin has a convar list, free its memory */
|
||||
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
||||
{
|
||||
delete pConVarList;
|
||||
}
|
||||
|
||||
/* Clear any references to this plugin as the convar creator */
|
||||
for (List<ConVarInfo *>::iterator iter = m_ConVars.begin(); iter != m_ConVars.end(); ++iter)
|
||||
{
|
||||
ConVarInfo *pInfo = (*iter);
|
||||
|
||||
if (pInfo->pPlugin == plugin)
|
||||
{
|
||||
pInfo->pPlugin = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
||||
|
||||
/* Remove convar queries for this plugin that haven't returned results yet */
|
||||
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||
{
|
||||
ConVarQuery &query = (*iter);
|
||||
if (query.pCallback->GetParentRuntime() == pRuntime)
|
||||
{
|
||||
iter = m_ConVarQueries.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void ConVarManager::OnClientDisconnected(int client)
|
||||
{
|
||||
/* Remove convar queries for this client that haven't returned results yet */
|
||||
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||
{
|
||||
ConVarQuery &query = (*iter);
|
||||
if (query.client == client)
|
||||
{
|
||||
IPluginFunction *pCallback = query.pCallback;
|
||||
if (pCallback)
|
||||
{
|
||||
cell_t ret;
|
||||
|
||||
pCallback->PushCell(query.cookie);
|
||||
pCallback->PushCell(client);
|
||||
pCallback->PushCell(eQueryCvarValueStatus_Cancelled);
|
||||
pCallback->PushString("");
|
||||
pCallback->PushString("");
|
||||
pCallback->PushCell(query.value);
|
||||
pCallback->Execute(&ret);
|
||||
}
|
||||
iter = m_ConVarQueries.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
@@ -282,27 +270,20 @@ bool ConVarManager::GetHandleApproxSize(HandleType_t type, void *object, unsigne
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command)
|
||||
void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||
{
|
||||
int argcount = command->ArgC();
|
||||
int argcount = command.ArgC();
|
||||
if (argcount >= 3)
|
||||
{
|
||||
bool wantReset = false;
|
||||
|
||||
/* Get plugin index that was passed */
|
||||
const char *arg = command->Arg(2);
|
||||
if (argcount >= 4 && strcmp(arg, "reset") == 0)
|
||||
{
|
||||
wantReset = true;
|
||||
arg = command->Arg(3);
|
||||
}
|
||||
const char *arg = command.Arg(2);
|
||||
|
||||
/* Get plugin object */
|
||||
IPlugin *plugin = scripts->FindPluginByConsoleArg(arg);
|
||||
CPlugin *plugin = g_PluginSys.FindPluginByConsoleArg(arg);
|
||||
|
||||
if (!plugin)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Plugin \"%s\" was not found.", arg);
|
||||
g_RootMenu.ConsolePrint("[SM] Plugin \"%s\" was not found.", arg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -316,38 +297,25 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
||||
/* If no convar list... */
|
||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] No convars found for: %s", plname);
|
||||
g_RootMenu.ConsolePrint("[SM] No convars found for: %s", plname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wantReset)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
|
||||
UTIL_ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
|
||||
}
|
||||
|
||||
/* Iterate convar list and display/reset each one */
|
||||
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
|
||||
|
||||
/* Iterate convar list and display each one */
|
||||
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
|
||||
{
|
||||
/*const */ConVar *pConVar = const_cast<ConVar *>(*iter);
|
||||
if (!wantReset)
|
||||
{
|
||||
UTIL_ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
||||
} else {
|
||||
pConVar->Revert();
|
||||
}
|
||||
}
|
||||
|
||||
if (wantReset)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Reset %d convars for: %s", pConVarList->size(), plname);
|
||||
const ConVar *pConVar = (*iter);
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Display usage of subcommand */
|
||||
UTIL_ConsolePrint("[SM] Usage: sm cvars [reset] <plugin #>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm convars <plugin #>");
|
||||
}
|
||||
|
||||
Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *description, int flags, bool hasMin, float min, bool hasMax, float max)
|
||||
@@ -356,8 +324,6 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
ConVarInfo *pInfo = NULL;
|
||||
Handle_t hndl = 0;
|
||||
|
||||
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
||||
|
||||
/* Find out if the convar exists already */
|
||||
pConVar = icvar->FindVar(name);
|
||||
|
||||
@@ -365,16 +331,11 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
if (pConVar)
|
||||
{
|
||||
/* Add convar to plugin's list */
|
||||
AddConVarToPluginList(plugin, pConVar);
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
|
||||
/* First find out if we already have a handle to it */
|
||||
if (convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
/* If the convar doesn't have an owning plugin, but SM created it, adopt it */
|
||||
if (pInfo->sourceMod && pInfo->pPlugin == nullptr) {
|
||||
pInfo->pPlugin = plugin;
|
||||
}
|
||||
|
||||
return pInfo->handle;
|
||||
}
|
||||
else
|
||||
@@ -386,7 +347,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* If we don't, then create a new handle from the convar */
|
||||
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
delete pInfo;
|
||||
@@ -415,10 +376,9 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
pInfo->handle = hndl;
|
||||
pInfo->sourceMod = true;
|
||||
pInfo->pChangeForward = NULL;
|
||||
pInfo->pPlugin = plugin;
|
||||
|
||||
/* Create a handle from the new convar */
|
||||
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
delete pInfo;
|
||||
@@ -432,7 +392,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* Add convar to plugin's list */
|
||||
AddConVarToPluginList(plugin, pConVar);
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
|
||||
/* Insert struct into caches */
|
||||
m_ConVars.push_back(pInfo);
|
||||
@@ -447,13 +407,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
||||
ConVarInfo *pInfo;
|
||||
Handle_t hndl;
|
||||
|
||||
/* Check convar cache to find out if we already have a handle */
|
||||
if (convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
return pInfo->handle;
|
||||
}
|
||||
|
||||
/* Couldn't find it in cache, so search for it */
|
||||
/* Search for convar */
|
||||
pConVar = icvar->FindVar(name);
|
||||
|
||||
/* If it doesn't exist, then return an invalid handle */
|
||||
@@ -462,6 +416,12 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
/* At this point, the convar exists. So, find out if we already have a handle */
|
||||
if (convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
return pInfo->handle;
|
||||
}
|
||||
|
||||
/* Create and initialize ConVarInfo structure */
|
||||
pInfo = new ConVarInfo();
|
||||
pInfo->sourceMod = false;
|
||||
@@ -469,7 +429,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* If we don't have a handle, then create a new one */
|
||||
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
delete pInfo;
|
||||
@@ -527,7 +487,7 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction
|
||||
/* If forward does not exist, create it */
|
||||
if (!pForward)
|
||||
{
|
||||
pForward = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
|
||||
pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
|
||||
pInfo->pChangeForward = pForward;
|
||||
}
|
||||
|
||||
@@ -563,11 +523,10 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
|
||||
}
|
||||
|
||||
/* If the forward now has 0 functions in it... */
|
||||
if (pForward->GetFunctionCount() == 0 &&
|
||||
!ConVarReentrancyGuard::IsCvarInChain(pConVar))
|
||||
if (pForward->GetFunctionCount() == 0)
|
||||
{
|
||||
/* Free this forward */
|
||||
forwardsys->ReleaseForward(pForward);
|
||||
g_Forwards.ReleaseForward(pForward);
|
||||
pInfo->pChangeForward = NULL;
|
||||
}
|
||||
}
|
||||
@@ -575,24 +534,39 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
|
||||
|
||||
QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl)
|
||||
{
|
||||
QueryCvarCookie_t cookie = sCoreProviderImpl.QueryClientConVar(IndexOfEdict(pPlayer), name);
|
||||
QueryCvarCookie_t cookie = 0;
|
||||
|
||||
if (pCallback != NULL)
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) };
|
||||
m_ConVarQueries.push_back(query);
|
||||
cookie = engine->StartQueryCvarValue(pPlayer, name);
|
||||
}
|
||||
else if (m_bIsVSPQueryHooked)
|
||||
{
|
||||
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InvalidQueryCvarCookie;
|
||||
}
|
||||
|
||||
ConVarQuery query = {cookie, pCallback, hndl};
|
||||
m_ConVarQueries.push_back(query);
|
||||
#endif
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
void ConVarManager::AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar)
|
||||
void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar)
|
||||
{
|
||||
ConVarList *pConVarList;
|
||||
ConVarList::iterator iter;
|
||||
bool inserted = false;
|
||||
const char *orig = pConVar->GetName();
|
||||
|
||||
IPlugin *plugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
|
||||
|
||||
/* Check plugin for an existing convar list */
|
||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||
{
|
||||
@@ -622,7 +596,11 @@ void ConVarManager::AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
|
||||
#else
|
||||
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
||||
#endif
|
||||
{
|
||||
/* If the values are the same, exit early in order to not trigger callbacks */
|
||||
if (strcmp(pConVar->GetString(), oldValue) == 0)
|
||||
@@ -642,14 +620,20 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float
|
||||
|
||||
if (pInfo->changeListeners.size() != 0)
|
||||
{
|
||||
for (auto i = pInfo->changeListeners.begin(); i != pInfo->changeListeners.end(); i++)
|
||||
for (List<IConVarChangeListener *>::iterator i = pInfo->changeListeners.begin();
|
||||
i != pInfo->changeListeners.end();
|
||||
i++)
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
(*i)->OnConVarChanged(pConVar, oldValue, flOldValue);
|
||||
#else
|
||||
(*i)->OnConVarChanged(pConVar, oldValue, atof(oldValue));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (pForward != NULL)
|
||||
{
|
||||
ConVarReentrancyGuard guard(pConVar);
|
||||
|
||||
/* Now call forwards in plugins that have hooked this */
|
||||
pForward->PushCell(pInfo->handle);
|
||||
pForward->PushString(oldValue);
|
||||
@@ -660,15 +644,11 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float
|
||||
|
||||
bool ConVarManager::IsQueryingSupported()
|
||||
{
|
||||
return sCoreProviderImpl.IsClientConVarQueryingSupported();
|
||||
return (m_bIsDLLQueryHooked || m_bIsVSPQueryHooked);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
||||
int client,
|
||||
EQueryCvarValueStatus result,
|
||||
const char *cvarName,
|
||||
const char *cvarValue)
|
||||
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||
{
|
||||
IPluginFunction *pCallback = NULL;
|
||||
cell_t value = 0;
|
||||
@@ -690,7 +670,7 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
||||
cell_t ret;
|
||||
|
||||
pCallback->PushCell(cookie);
|
||||
pCallback->PushCell(client);
|
||||
pCallback->PushCell(IndexOfEdict(pPlayer));
|
||||
pCallback->PushCell(result);
|
||||
pCallback->PushString(cvarName);
|
||||
|
||||
@@ -711,12 +691,12 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
||||
}
|
||||
#endif
|
||||
|
||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin)
|
||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
||||
{
|
||||
ConVarInfo *pInfo;
|
||||
HandleError error;
|
||||
|
||||
if ((error = handlesys->ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
|
||||
if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
@@ -726,10 +706,5 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugi
|
||||
*pVar = pInfo->pVar;
|
||||
}
|
||||
|
||||
if (ppPlugin)
|
||||
{
|
||||
*ppPlugin = pInfo->pPlugin;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
+31
-44
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -39,11 +39,13 @@
|
||||
#include <IForwardSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <compat_wrappers.h>
|
||||
#include "concmd_cleaner.h"
|
||||
#include "PlayerManager.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
|
||||
#if SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
class EQueryCvarValueStatus;
|
||||
typedef int QueryCvarCookie_t;
|
||||
#endif
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@@ -62,27 +64,7 @@ struct ConVarInfo
|
||||
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
|
||||
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
||||
ConVar *pVar; /**< The actual convar */
|
||||
IPlugin *pPlugin; /**< Originally owning plugin */
|
||||
List<IConVarChangeListener *> changeListeners;
|
||||
|
||||
struct ConVarPolicy
|
||||
{
|
||||
static inline bool matches(const char *name, ConVarInfo *info)
|
||||
{
|
||||
const char *conVarChars = info->pVar->GetName();
|
||||
|
||||
std::string convarName = ke::Lowercase(conVarChars);
|
||||
std::string input = ke::Lowercase(name);
|
||||
|
||||
return convarName == input;
|
||||
}
|
||||
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
std::string lower = ke::Lowercase(key.c_str());
|
||||
return detail::CharsAndLength(lower.c_str()).hash();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,7 +75,6 @@ struct ConVarQuery
|
||||
QueryCvarCookie_t cookie; /**< Cookie that identifies query */
|
||||
IPluginFunction *pCallback; /**< Function that will be called when query is finished */
|
||||
cell_t value; /**< Optional value passed to query function */
|
||||
cell_t client; /**< Only used for cleaning up on client disconnection */
|
||||
};
|
||||
|
||||
class ConVarManager :
|
||||
@@ -101,8 +82,7 @@ class ConVarManager :
|
||||
public IHandleTypeDispatch,
|
||||
public IPluginsListener,
|
||||
public IRootConsoleCommand,
|
||||
public IConCommandTracker,
|
||||
public IClientListener
|
||||
public IConCommandTracker
|
||||
{
|
||||
public:
|
||||
ConVarManager();
|
||||
@@ -111,17 +91,16 @@ public: // SMGlobalClass
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModVSPReceived();
|
||||
public: // IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
||||
public: // IPluginsListener
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override;
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public: //IConCommandTracker
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) override;
|
||||
public: //IClientListener
|
||||
void OnClientDisconnected(int client);
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||
public:
|
||||
/**
|
||||
* Create a convar and return a handle to it.
|
||||
@@ -155,28 +134,36 @@ public:
|
||||
|
||||
bool IsQueryingSupported();
|
||||
|
||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin = nullptr);
|
||||
|
||||
// Called via game hooks.
|
||||
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void OnClientQueryFinished(
|
||||
QueryCvarCookie_t cookie,
|
||||
int client,
|
||||
EQueryCvarValueStatus result,
|
||||
const char *cvarName,
|
||||
const char *cvarValue);
|
||||
#endif
|
||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Adds a convar to a plugin's list.
|
||||
*/
|
||||
static void AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar);
|
||||
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
|
||||
|
||||
/**
|
||||
* Static callback that Valve's ConVar object executes when the convar's value changes.
|
||||
*/
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
static void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||
#else
|
||||
static void OnConVarChanged(ConVar *pConVar, const char *oldValue);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Callback for when StartQueryCvarValue() has finished.
|
||||
*/
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
|
||||
const char *cvarName, const char *cvarValue);
|
||||
#endif
|
||||
private:
|
||||
HandleType_t m_ConVarType;
|
||||
List<ConVarInfo *> m_ConVars;
|
||||
List<ConVarQuery> m_ConVarQueries;
|
||||
bool m_bIsDLLQueryHooked;
|
||||
bool m_bIsVSPQueryHooked;
|
||||
};
|
||||
|
||||
extern ConVarManager g_ConVarManager;
|
||||
|
||||
@@ -1,409 +0,0 @@
|
||||
/**
|
||||
* 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>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* On SourceHook v4.3 or lower, there are no DVP hooks. Very sad, right?
|
||||
* Only do this on newer versions. For the older code, we'll do an incredibly
|
||||
* hacky detour.
|
||||
*
|
||||
* The idea of the "non-hacky" (yeah... no) code is that every unique
|
||||
* ConCommand vtable gets its own DVP hook. We watch for unloading and
|
||||
* loading commands to remove stale hooks from SH.
|
||||
*/
|
||||
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "Logger.h"
|
||||
#include "compat_wrappers.h"
|
||||
#include "ConsoleDetours.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "ConCmdManager.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "ConCommandBaseIterator.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "command_args.h"
|
||||
#include "provider.h"
|
||||
#include <am-utility.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
|
||||
#if defined PLATFORM_POSIX
|
||||
# include <dlfcn.h>
|
||||
# include <sys/mman.h>
|
||||
# include <stdint.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
#endif
|
||||
|
||||
class GenericCommandHooker : public IConCommandLinkListener
|
||||
{
|
||||
struct HackInfo
|
||||
{
|
||||
void **vtable;
|
||||
int hook;
|
||||
unsigned int refcount;
|
||||
};
|
||||
CVector<HackInfo> vtables;
|
||||
bool enabled;
|
||||
SourceHook::MemFuncInfo dispatch;
|
||||
|
||||
inline void **GetVirtualTable(ConCommandBase *pBase)
|
||||
{
|
||||
return *reinterpret_cast<void***>(reinterpret_cast<char*>(pBase) +
|
||||
dispatch.thisptroffs +
|
||||
dispatch.vtbloffs);
|
||||
}
|
||||
|
||||
inline bool FindVtable(void **ptr, size_t& index)
|
||||
{
|
||||
for (size_t i = 0; i < vtables.size(); i++)
|
||||
{
|
||||
if (vtables[i].vtable == ptr)
|
||||
{
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MakeHookable(ConCommandBase *pBase)
|
||||
{
|
||||
if (!pBase->IsCommand())
|
||||
return;
|
||||
|
||||
ConCommand *cmd = (ConCommand*)pBase;
|
||||
void **vtable = GetVirtualTable(cmd);
|
||||
|
||||
size_t index;
|
||||
if (!FindVtable(vtable, index))
|
||||
{
|
||||
HackInfo hack;
|
||||
hack.vtable = vtable;
|
||||
hack.hook = SH_ADD_VPHOOK(ConCommand, Dispatch, cmd, SH_MEMBER(this, &GenericCommandHooker::Dispatch), false);
|
||||
hack.refcount = 1;
|
||||
vtables.push_back(hack);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtables[index].refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void Dispatch(const CCommand& args)
|
||||
#else
|
||||
void Dispatch()
|
||||
#endif
|
||||
{
|
||||
cell_t res = ConsoleDetours::Dispatch(META_IFACEPTR(ConCommand)
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
, args
|
||||
#endif
|
||||
);
|
||||
if (res >= Pl_Handled)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void ReparseCommandList()
|
||||
{
|
||||
for (size_t i = 0; i < vtables.size(); i++)
|
||||
vtables[i].refcount = 0;
|
||||
for (ConCommandBaseIterator iter; iter.IsValid(); iter.Next())
|
||||
MakeHookable(iter.Get());
|
||||
CVector<HackInfo>::iterator iter = vtables.begin();
|
||||
while (iter != vtables.end())
|
||||
{
|
||||
if ((*iter).refcount)
|
||||
{
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
/* Damn it. This event happens AFTER the plugin has unloaded!
|
||||
* There's two options. Remove the hook now and hope SH's memory
|
||||
* protection will prevent a crash. Otherwise, we can wait until
|
||||
* the server shuts down and more likely crash then.
|
||||
*
|
||||
* This situation only arises if:
|
||||
* 1) Someone has used AddCommandFilter()
|
||||
* 2) ... on a Dark Messiah server (mm:s new api)
|
||||
* 3) ... and another MM:S plugin that uses ConCommands has unloaded.
|
||||
*
|
||||
* Even though the impact is really small, we'll wait until the
|
||||
* server shuts down, so normal operation isn't interrupted.
|
||||
*
|
||||
* See bug 4018.
|
||||
*/
|
||||
iter = vtables.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void UnhookCommand(ConCommandBase *pBase)
|
||||
{
|
||||
if (!pBase->IsCommand())
|
||||
return;
|
||||
|
||||
ConCommand *cmd = (ConCommand*)pBase;
|
||||
void **vtable = GetVirtualTable(cmd);
|
||||
|
||||
size_t index;
|
||||
if (!FindVtable(vtable, index))
|
||||
{
|
||||
logger->LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vtables[index].refcount > 0);
|
||||
vtables[index].refcount--;
|
||||
if (vtables[index].refcount == 0)
|
||||
{
|
||||
SH_REMOVE_HOOK_ID(vtables[index].hook);
|
||||
vtables.erase(vtables.iterAt(index));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GenericCommandHooker() : enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool Enable()
|
||||
{
|
||||
SourceHook::GetFuncInfo(&ConCommand::Dispatch, dispatch);
|
||||
|
||||
if (dispatch.thisptroffs < 0)
|
||||
{
|
||||
logger->LogError("Command filter could not determine ConCommand layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ConCommandBaseIterator iter; iter.IsValid(); iter.Next())
|
||||
MakeHookable(iter.Get());
|
||||
|
||||
if (!vtables.size())
|
||||
{
|
||||
logger->LogError("Command filter could not find any cvars!");
|
||||
return false;
|
||||
}
|
||||
|
||||
enabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
for (size_t i = 0; i < vtables.size(); i++)
|
||||
SH_REMOVE_HOOK_ID(vtables[i].hook);
|
||||
vtables.clear();
|
||||
}
|
||||
|
||||
virtual void OnLinkConCommand(ConCommandBase *pBase)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
MakeHookable(pBase);
|
||||
}
|
||||
|
||||
virtual void OnUnlinkConCommand(ConCommandBase *pBase)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
if (pBase == NULL)
|
||||
ReparseCommandList();
|
||||
else
|
||||
UnhookCommand(pBase);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* BEGIN THE ACTUALLY GENERIC CODE.
|
||||
*/
|
||||
|
||||
#define FEATURECAP_COMMANDLISTENER "command listener"
|
||||
|
||||
static GenericCommandHooker s_GenericHooker;
|
||||
ConsoleDetours g_ConsoleDetours;
|
||||
|
||||
ConsoleDetours::ConsoleDetours() : status(FeatureStatus_Unknown)
|
||||
{
|
||||
}
|
||||
|
||||
void ConsoleDetours::OnSourceModAllInitialized()
|
||||
{
|
||||
m_pForward = forwardsys->CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
|
||||
Param_String, Param_Cell);
|
||||
sharesys->AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
|
||||
}
|
||||
|
||||
void ConsoleDetours::OnSourceModShutdown()
|
||||
{
|
||||
for (StringHashMap<IChangeableForward *>::iterator iter = m_Listeners.iter();
|
||||
!iter.empty();
|
||||
iter.next())
|
||||
{
|
||||
forwardsys->ReleaseForward(iter->value);
|
||||
}
|
||||
|
||||
forwardsys->ReleaseForward(m_pForward);
|
||||
s_GenericHooker.Disable();
|
||||
}
|
||||
|
||||
FeatureStatus ConsoleDetours::GetFeatureStatus(FeatureType type, const char *name)
|
||||
{
|
||||
return GetStatus();
|
||||
}
|
||||
|
||||
FeatureStatus ConsoleDetours::GetStatus()
|
||||
{
|
||||
if (status == FeatureStatus_Unknown)
|
||||
{
|
||||
status = s_GenericHooker.Enable() ? FeatureStatus_Available : FeatureStatus_Unavailable;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
||||
{
|
||||
if (GetStatus() != FeatureStatus_Available)
|
||||
return false;
|
||||
|
||||
if (command == NULL)
|
||||
{
|
||||
m_pForward->AddFunction(fun);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||
IChangeableForward *forward;
|
||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||
{
|
||||
forward = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
|
||||
Param_String, Param_Cell);
|
||||
m_Listeners.insert(str.get(), forward);
|
||||
}
|
||||
forward->AddFunction(fun);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
|
||||
{
|
||||
if (command == NULL)
|
||||
{
|
||||
return m_pForward->RemoveFunction(fun);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||
IChangeableForward *forward;
|
||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||
return false;
|
||||
return forward->RemoveFunction(fun);
|
||||
}
|
||||
}
|
||||
|
||||
cell_t ConsoleDetours::InternalDispatch(int client, const ICommandArgs *args)
|
||||
{
|
||||
char name[255];
|
||||
const char *realname = args->Arg(0);
|
||||
size_t len = strlen(realname);
|
||||
|
||||
// Disallow command strings that are too long, for now.
|
||||
if (len >= sizeof(name) - 1)
|
||||
return Pl_Continue;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (realname[i] >= 'A' && realname[i] <= 'Z')
|
||||
name[i] = tolower(realname[i]);
|
||||
else
|
||||
name[i] = realname[i];
|
||||
}
|
||||
name[len] = '\0';
|
||||
|
||||
cell_t result = Pl_Continue;
|
||||
m_pForward->PushCell(client);
|
||||
m_pForward->PushString(name);
|
||||
m_pForward->PushCell(args->ArgC() - 1);
|
||||
m_pForward->Execute(&result, NULL);
|
||||
|
||||
/* Don't let plugins block this. */
|
||||
if (strcmp(name, "sm") == 0)
|
||||
result = Pl_Continue;
|
||||
|
||||
if (result >= Pl_Handled)
|
||||
return result;
|
||||
|
||||
IChangeableForward *forward;
|
||||
if (!m_Listeners.retrieve(name, &forward))
|
||||
return result;
|
||||
if (forward->GetFunctionCount() == 0)
|
||||
return result;
|
||||
|
||||
cell_t result2 = Pl_Continue;
|
||||
forward->PushCell(client);
|
||||
forward->PushString(name);
|
||||
forward->PushCell(args->ArgC() - 1);
|
||||
forward->Execute(&result2, NULL);
|
||||
|
||||
if (result2 > result)
|
||||
result = result2;
|
||||
|
||||
/* "sm" should not have flown through the above. */
|
||||
assert(strcmp(name, "sm") != 0 || result == Pl_Continue);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
cell_t ConsoleDetours::Dispatch(ConCommand *pBase, const CCommand& args)
|
||||
{
|
||||
#else
|
||||
cell_t ConsoleDetours::Dispatch(ConCommand *pBase)
|
||||
{
|
||||
CCommand args;
|
||||
#endif
|
||||
EngineArgs cargs(args);
|
||||
cell_t res;
|
||||
{
|
||||
AutoEnterCommand autoEnterCommand(&cargs);
|
||||
res = g_ConsoleDetours.InternalDispatch(sCoreProviderImpl.CommandClient(), &cargs);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
+83
-128
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -33,20 +33,14 @@
|
||||
#include "CoreConfig.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "Logger.h"
|
||||
#include "frame_hooks.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "compat_wrappers.h"
|
||||
#include "sm_srvcmds.h"
|
||||
#include <sourcemod_version.h>
|
||||
#include <amtl/os/am-path.h>
|
||||
#include <amtl/os/am-fsutil.h>
|
||||
#include <sh_list.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
#include "sm_stringutil.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "Logger.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ForwardSys.h"
|
||||
#include "frame_hooks.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
|
||||
@@ -70,9 +64,13 @@ void CheckAndFinalizeConfigs();
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
void Hook_ExecDispatchPre(const CCommand &cmd)
|
||||
#else
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
void Hook_ExecDispatchPre()
|
||||
#else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
void Hook_ExecDispatchPre()
|
||||
#endif
|
||||
{
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
@@ -105,19 +103,23 @@ void CheckAndFinalizeConfigs()
|
||||
{
|
||||
if ((g_bServerExecd || g_ServerCfgFile == NULL) && g_bGotServerStart)
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
g_PendingInternalPush = true;
|
||||
#else
|
||||
SM_InternalCmdTrigger();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CoreConfig::OnSourceModAllInitialized()
|
||||
{
|
||||
rootmenu->AddRootConsoleCommand3("config", "Set core configuration options", this);
|
||||
g_pOnServerCfg = forwardsys->CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
|
||||
g_pOnConfigsExecuted = forwardsys->CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
|
||||
g_pOnAutoConfigsBuffered = forwardsys->CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
|
||||
g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
|
||||
g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
|
||||
g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
|
||||
g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
|
||||
}
|
||||
|
||||
CoreConfig::CoreConfig()
|
||||
CoreConfig::CoreConfig() : m_Strings(512)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -127,15 +129,15 @@ CoreConfig::~CoreConfig()
|
||||
|
||||
void CoreConfig::OnSourceModShutdown()
|
||||
{
|
||||
rootmenu->RemoveRootConsoleCommand("config", this);
|
||||
forwardsys->ReleaseForward(g_pOnServerCfg);
|
||||
forwardsys->ReleaseForward(g_pOnConfigsExecuted);
|
||||
forwardsys->ReleaseForward(g_pOnAutoConfigsBuffered);
|
||||
g_RootMenu.RemoveRootConsoleCommand("config", this);
|
||||
g_Forwards.ReleaseForward(g_pOnServerCfg);
|
||||
g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
|
||||
g_Forwards.ReleaseForward(g_pOnAutoConfigsBuffered);
|
||||
|
||||
if (g_pExecPtr != NULL)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
|
||||
g_pExecPtr = NULL;
|
||||
}
|
||||
}
|
||||
@@ -160,8 +162,8 @@ void CoreConfig::OnSourceModLevelChange(const char *mapName)
|
||||
g_pExecPtr = FindCommand("exec");
|
||||
if (g_pExecPtr != NULL)
|
||||
{
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -177,45 +179,31 @@ void CoreConfig::OnSourceModLevelChange(const char *mapName)
|
||||
g_bGotTrigger = false;
|
||||
}
|
||||
|
||||
void CoreConfig::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command)
|
||||
void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||
{
|
||||
int argcount = command->ArgC();
|
||||
int argcount = command.ArgC();
|
||||
if (argcount >= 4)
|
||||
{
|
||||
const char *option = command->Arg(2);
|
||||
const char *value = command->Arg(3);
|
||||
const char *option = command.Arg(2);
|
||||
const char *value = command.Arg(3);
|
||||
|
||||
char error[255];
|
||||
|
||||
ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
|
||||
|
||||
if (res == ConfigResult_Reject)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\". (%s)", option, value, error);
|
||||
g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
|
||||
} else if (res == ConfigResult_Ignore) {
|
||||
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||
} else {
|
||||
if (res == ConfigResult_Ignore) {
|
||||
UTIL_ConsolePrint("[SM] WARNING: Config option \"%s\" is not registered.", option);
|
||||
}
|
||||
|
||||
UTIL_ConsolePrint("[SM] Config option \"%s\" set to \"%s\".", option, value);
|
||||
g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (argcount >= 3) {
|
||||
const char *option = command->Arg(2);
|
||||
|
||||
const char *value = GetCoreConfigValue(option);
|
||||
|
||||
if (value == NULL)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||
} else {
|
||||
UTIL_ConsolePrint("[SM] Config option \"%s\" is set to \"%s\".", option, value);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UTIL_ConsolePrint("[SM] Usage: sm config <option> [value]");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
|
||||
}
|
||||
|
||||
void CoreConfig::Initialize()
|
||||
@@ -226,38 +214,25 @@ void CoreConfig::Initialize()
|
||||
/* Try to get command line value of core config convar */
|
||||
const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
|
||||
|
||||
/* If sm_corecfgfile is on the command line, use that
|
||||
* If sm_corecfgfile isn't there, check sm_basepath on the command line and build the path off that
|
||||
* If sm_basepath isn't there, just use the default path for the cfg
|
||||
*/
|
||||
if (corecfg)
|
||||
/* If sm_corecfgfile not specified on command line, use default value */
|
||||
if (!corecfg)
|
||||
{
|
||||
ke::path::Format(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||
corecfg = sm_corecfgfile.GetDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *basepath = icvar->GetCommandLineValue("sm_basepath");
|
||||
|
||||
/* Format path to config file */
|
||||
if (basepath)
|
||||
{
|
||||
ke::path::Format(filePath, sizeof(filePath), "%s/%s/%s", g_SourceMod.GetGamePath(), basepath, "configs/core.cfg");
|
||||
}
|
||||
else
|
||||
{
|
||||
ke::path::Format(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), sm_corecfgfile.GetDefault());
|
||||
}
|
||||
}
|
||||
/* Format path to config file */
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||
|
||||
/* Reset cached key values */
|
||||
m_KeyValues.clear();
|
||||
m_Strings.Reset();
|
||||
|
||||
/* Parse config file */
|
||||
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
|
||||
{
|
||||
/* :TODO: This won't actually log or print anything :( - So fix that somehow */
|
||||
const char *error = textparsers->GetSMCErrorString(err);
|
||||
logger->LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
|
||||
g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +244,7 @@ SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
||||
if (err == ConfigResult_Reject)
|
||||
{
|
||||
/* This is a fatal error */
|
||||
logger->LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
|
||||
g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
@@ -277,7 +252,7 @@ SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
||||
|
||||
ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
|
||||
{
|
||||
ConfigResult result = ConfigResult_Ignore;
|
||||
ConfigResult result;
|
||||
|
||||
/* Notify! */
|
||||
SMGlobalClass *pBase = SMGlobalClass::head;
|
||||
@@ -285,23 +260,24 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
|
||||
{
|
||||
if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
|
||||
{
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
pBase = pBase->m_pGlobalClassNext;
|
||||
}
|
||||
|
||||
std::string vstr(value);
|
||||
m_KeyValues.replace(option, std::move(vstr));
|
||||
m_KeyValues.replace(option, m_Strings.AddString(value));
|
||||
|
||||
return result;
|
||||
return ConfigResult_Ignore;
|
||||
}
|
||||
|
||||
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
||||
{
|
||||
StringHashMap<std::string>::Result r = m_KeyValues.find(key);
|
||||
if (!r.found())
|
||||
int *pKey = m_KeyValues.retrieve(key);
|
||||
if (pKey == NULL)
|
||||
{
|
||||
return NULL;
|
||||
return r->value.c_str();
|
||||
}
|
||||
return m_Strings.GetString(*pKey);
|
||||
}
|
||||
|
||||
bool SM_AreConfigsExecuted()
|
||||
@@ -318,7 +294,7 @@ inline bool IsPathSepChar(char c)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
{
|
||||
bool will_create = false;
|
||||
|
||||
@@ -336,12 +312,12 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
|
||||
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
|
||||
|
||||
if (!ke::file::IsDirectory(path))
|
||||
if (!g_LibSys.IsPathDirectory(path))
|
||||
{
|
||||
char *cur_ptr = path;
|
||||
size_t len;
|
||||
|
||||
ke::path::Format(path, sizeof(path), "%s", folder);
|
||||
g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
|
||||
len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
|
||||
|
||||
do
|
||||
@@ -362,12 +338,14 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
{
|
||||
next_ptr = NULL;
|
||||
}
|
||||
len += ke::path::Format(&build[len],
|
||||
len += g_LibSys.PathFormat(&build[len],
|
||||
sizeof(build)-len,
|
||||
"/%s",
|
||||
cur_ptr);
|
||||
if (!ke::file::CreateDirectory(build))
|
||||
if (!g_LibSys.CreateFolder(build))
|
||||
{
|
||||
break;
|
||||
}
|
||||
cur_ptr = next_ptr;
|
||||
} while (cur_ptr);
|
||||
}
|
||||
@@ -379,13 +357,13 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
|
||||
if (cfg->folder.size())
|
||||
{
|
||||
ke::path::Format(local,
|
||||
sizeof(local),
|
||||
g_LibSys.PathFormat(local,
|
||||
sizeof(local),
|
||||
"%s/%s.cfg",
|
||||
cfg->folder.c_str(),
|
||||
cfg->autocfg.c_str());
|
||||
} else {
|
||||
ke::path::Format(local,
|
||||
g_LibSys.PathFormat(local,
|
||||
sizeof(local),
|
||||
"%s.cfg",
|
||||
cfg->autocfg.c_str());
|
||||
@@ -393,7 +371,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
|
||||
g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
|
||||
|
||||
bool file_exists = ke::file::IsFile(file);
|
||||
bool file_exists = g_LibSys.IsPathFile(file);
|
||||
if (!file_exists && will_create)
|
||||
{
|
||||
List<const ConVar *> *convars = NULL;
|
||||
@@ -403,7 +381,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
FILE *fp = fopen(file, "wt");
|
||||
if (fp)
|
||||
{
|
||||
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SOURCEMOD_VERSION);
|
||||
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SM_FULL_VERSION);
|
||||
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
|
||||
fprintf(fp, "\n\n");
|
||||
|
||||
@@ -412,11 +390,8 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
for (iter = convars->begin(); iter != convars->end(); iter++)
|
||||
{
|
||||
const ConVar *cvar = (*iter);
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
if (cvar->IsFlagSet(FCVAR_DONTRECORD))
|
||||
#else
|
||||
if (cvar->IsBitSet(FCVAR_DONTRECORD))
|
||||
#endif
|
||||
|
||||
if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -425,7 +400,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
char *dptr = descr;
|
||||
|
||||
/* Print comments until there is no more */
|
||||
ke::SafeStrcpy(descr, sizeof(descr), cvar->GetHelpText());
|
||||
strncopy(descr, cvar->GetHelpText(), sizeof(descr));
|
||||
while (*dptr != '\0')
|
||||
{
|
||||
/* Find the next line */
|
||||
@@ -463,18 +438,13 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
can_create = false;
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger->LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
|
||||
return can_create;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists)
|
||||
{
|
||||
char cmd[255];
|
||||
ke::SafeSprintf(cmd, sizeof(cmd), "exec %s\n", local);
|
||||
UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
|
||||
engine->ServerCommand(cmd);
|
||||
}
|
||||
|
||||
@@ -498,10 +468,10 @@ void SM_DoSingleExecFwds(IPluginContext *ctx)
|
||||
|
||||
void SM_ConfigsExecuted_Plugin(unsigned int serial)
|
||||
{
|
||||
IPluginIterator *iter = scripts->GetPluginIterator();
|
||||
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
|
||||
while (iter->MorePlugins())
|
||||
{
|
||||
IPlugin *plugin = iter->GetPlugin();
|
||||
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
|
||||
if (plugin->GetSerial() == serial)
|
||||
{
|
||||
SM_DoSingleExecFwds(plugin->GetBaseContext());
|
||||
@@ -514,7 +484,7 @@ void SM_ConfigsExecuted_Plugin(unsigned int serial)
|
||||
|
||||
void SM_ExecuteForPlugin(IPluginContext *ctx)
|
||||
{
|
||||
SMPlugin *plugin = scripts->FindPluginByContext(ctx->GetContext());
|
||||
CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
|
||||
|
||||
unsigned int num = plugin->GetConfigCount();
|
||||
if (!num)
|
||||
@@ -529,7 +499,7 @@ void SM_ExecuteForPlugin(IPluginContext *ctx)
|
||||
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
|
||||
}
|
||||
char cmd[255];
|
||||
ke::SafeSprintf(cmd, sizeof(cmd), "sm_internal 2 %d\n", plugin->GetSerial());
|
||||
UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
|
||||
engine->ServerCommand(cmd);
|
||||
}
|
||||
}
|
||||
@@ -543,17 +513,19 @@ void SM_ExecuteAllConfigs()
|
||||
|
||||
engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
|
||||
|
||||
AutoPluginList plugins(scripts);
|
||||
for (size_t i = 0; i < plugins->size(); i++)
|
||||
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
|
||||
while (iter->MorePlugins())
|
||||
{
|
||||
SMPlugin *plugin = plugins->at(i);
|
||||
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
|
||||
unsigned int num = plugin->GetConfigCount();
|
||||
bool can_create = true;
|
||||
for (unsigned int i=0; i<num; i++)
|
||||
{
|
||||
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
|
||||
}
|
||||
iter->NextPlugin();
|
||||
}
|
||||
iter->Release();
|
||||
|
||||
g_bGotServerStart = true;
|
||||
CheckAndFinalizeConfigs();
|
||||
@@ -576,24 +548,7 @@ void SM_InternalCmdTrigger()
|
||||
{
|
||||
/* Order is important here. We need to buffer things before we send the command out. */
|
||||
g_pOnAutoConfigsBuffered->Execute(NULL);
|
||||
engine->ServerCommand("sm_internal 1\n");
|
||||
engine->ServerCommand("sm internal 1\n");
|
||||
g_PendingInternalPush = false;
|
||||
}
|
||||
|
||||
CON_COMMAND(sm_internal, "")
|
||||
{
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
CCommand args;
|
||||
#endif
|
||||
|
||||
if (args.ArgC() < 1)
|
||||
return;
|
||||
|
||||
const char *arg = args.Arg(1);
|
||||
if (strcmp(arg, "1") == 0) {
|
||||
SM_ConfigsExecuted_Global();
|
||||
} else if (strcmp(arg, "2") == 0) {
|
||||
if (args.ArgC() >= 3)
|
||||
SM_ConfigsExecuted_Plugin(atoi(args.Arg(2)));
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -35,8 +35,8 @@
|
||||
#include "sm_globals.h"
|
||||
#include <ITextParsers.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <am-string.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_memtable.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
@@ -55,7 +55,7 @@ public: // SMGlobalClass
|
||||
public: // ITextListener_SMC
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
public: // IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override;
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public:
|
||||
/**
|
||||
* Initializes CoreConfig by reading from core.cfg file
|
||||
@@ -68,7 +68,8 @@ private:
|
||||
*/
|
||||
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
||||
private:
|
||||
StringHashMap<std::string> m_KeyValues;
|
||||
BaseStringTable m_Strings;
|
||||
KTrie<int> m_KeyValues;
|
||||
};
|
||||
|
||||
extern bool SM_AreConfigsExecuted();
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "Tlhelp32.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "minidump.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
bool HookImportAddrTable(BYTE *base, const char *func, DWORD hookfunc, char *err, size_t maxlength)
|
||||
{
|
||||
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)base;
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "%s", "Could not detect valid DOS signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
|
||||
if (nt->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "%s", "Could not detect valid NT signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_IMPORT_DESCRIPTOR *desc =
|
||||
(IMAGE_IMPORT_DESCRIPTOR *)
|
||||
(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
if (base == (BYTE *)desc)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "%s", "Could not find IAT");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool entryFound = false;
|
||||
while (desc->Name)
|
||||
{
|
||||
if (desc->FirstThunk != 0)
|
||||
{
|
||||
IMAGE_THUNK_DATA *data = (IMAGE_THUNK_DATA *)(base + desc->OriginalFirstThunk);
|
||||
DWORD *iat = (DWORD *)(base + desc->FirstThunk);
|
||||
while (data->u1.Function)
|
||||
{
|
||||
if ((data->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != IMAGE_ORDINAL_FLAG32)
|
||||
{
|
||||
IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME *)(base + data->u1.AddressOfData);
|
||||
if (strcmp((char *)import->Name, func) == 0)
|
||||
{
|
||||
DWORD oldprot, oldprot2;
|
||||
VirtualProtect(iat, 4, PAGE_READWRITE, &oldprot);
|
||||
*iat = hookfunc;
|
||||
VirtualProtect(iat, 4, oldprot, &oldprot2);
|
||||
entryFound = true;
|
||||
}
|
||||
}
|
||||
data++;
|
||||
iat++;
|
||||
}
|
||||
}
|
||||
desc++;
|
||||
}
|
||||
|
||||
if (!entryFound)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "Could not find IAT entry for %s", func);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
MiniDumpWriteDump2(
|
||||
IN HANDLE hProcess,
|
||||
IN DWORD ProcessId,
|
||||
IN HANDLE hFile,
|
||||
IN MINIDUMP_TYPE DumpType,
|
||||
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
|
||||
IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
|
||||
IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
|
||||
)
|
||||
{
|
||||
DumpType = (MINIDUMP_TYPE)((int)DumpType|MiniDumpWithFullMemory|MiniDumpWithHandleData);
|
||||
return MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType, ExceptionParam, UserStreamParam, CallbackParam);
|
||||
}
|
||||
|
||||
FARPROC WINAPI GetProcAddress2(HMODULE hModule, LPCSTR lpProcName)
|
||||
{
|
||||
if (strcmp(lpProcName, "MiniDumpWriteDump") == 0)
|
||||
{
|
||||
return (FARPROC)MiniDumpWriteDump2;
|
||||
}
|
||||
|
||||
return GetProcAddress(hModule, lpProcName);
|
||||
}
|
||||
|
||||
HMODULE WINAPI LoadLibraryEx2(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags)
|
||||
{
|
||||
HMODULE lib = LoadLibraryEx(lpFileName, hFile, dwFlags);
|
||||
|
||||
/* Steam.dll seems to get loaded using an abs path, thus the use of stristr() */
|
||||
if (stristr(lpFileName, "steam.dll"))
|
||||
{
|
||||
char err[64];
|
||||
if (!HookImportAddrTable((BYTE *)lib, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
|
||||
{
|
||||
Error("[SM] %s in steam.dll\n", err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
class CrazyWindowsDebugger : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
void OnSourceModAllInitialized()
|
||||
{
|
||||
HANDLE hModuleList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
|
||||
MODULEENTRY32 me32;
|
||||
BYTE *engine = NULL;
|
||||
BYTE *steam = NULL;
|
||||
char err[64];
|
||||
|
||||
me32.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
if (!Module32First(hModuleList, &me32))
|
||||
{
|
||||
Error("Could not initialize crazy debugger!");
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (strcasecmp(me32.szModule, "engine.dll") == 0)
|
||||
{
|
||||
engine = me32.modBaseAddr;
|
||||
}
|
||||
else if (strcasecmp(me32.szModule, "steam.dll") == 0)
|
||||
{
|
||||
steam = me32.modBaseAddr;
|
||||
}
|
||||
} while (Module32Next(hModuleList, &me32));
|
||||
|
||||
CloseHandle(hModuleList);
|
||||
|
||||
/* This really should not happen, but ... */
|
||||
if (!engine)
|
||||
{
|
||||
Error("[SM] Could not find engine.dll\n");
|
||||
}
|
||||
|
||||
/* Steam.dll isn't loaded yet */
|
||||
if (!steam)
|
||||
{
|
||||
if (!HookImportAddrTable(engine, "LoadLibraryExA", (DWORD)LoadLibraryEx2, err, sizeof(err)))
|
||||
{
|
||||
Error("[SM] %s in engine.dll)\n", err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!HookImportAddrTable(steam, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
|
||||
{
|
||||
Error("[SM] %s in steam.dll)\n", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} s_CrazyDebugger;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -30,36 +30,27 @@
|
||||
*/
|
||||
|
||||
#include "Database.h"
|
||||
#include "ISourceMod.h"
|
||||
#include "HandleSys.h"
|
||||
#include "ShareSys.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "Logger.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include <chrono>
|
||||
#include <amtl/am-thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <IThreader.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
#include "ThreadSupport.h"
|
||||
|
||||
#define DBPARSE_LEVEL_NONE 0
|
||||
#define DBPARSE_LEVEL_MAIN 1
|
||||
#define DBPARSE_LEVEL_DATABASE 2
|
||||
|
||||
DBManager g_DBMan;
|
||||
static bool s_OneTimeThreaderErrorMsg = false;
|
||||
|
||||
DBManager::DBManager()
|
||||
: m_Terminate(false),
|
||||
m_pDefault(NULL)
|
||||
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static void FrameHook(bool simulating)
|
||||
{
|
||||
g_DBMan.RunFrame();
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModAllInitialized()
|
||||
{
|
||||
HandleAccess sec;
|
||||
@@ -67,36 +58,50 @@ void DBManager::OnSourceModAllInitialized()
|
||||
g_HandleSys.InitAccessDefaults(NULL, &sec);
|
||||
sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY;
|
||||
sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
|
||||
|
||||
|
||||
m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||
m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
|
||||
g_pSM->BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
|
||||
m_Builder.SetPath(m_Filename);
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
|
||||
|
||||
m_pConfigLock = g_pThreader->MakeMutex();
|
||||
m_pThinkLock = g_pThreader->MakeMutex();
|
||||
m_pQueueLock = g_pThreader->MakeMutex();
|
||||
|
||||
g_PluginSys.AddPluginsListener(this);
|
||||
|
||||
g_pSM->AddGameFrameHook(&FrameHook);
|
||||
|
||||
auto sm_reload_databases = [this] (int client, const ICommandArgs *args) -> bool {
|
||||
m_Builder.StartParse();
|
||||
return true;
|
||||
};
|
||||
bridge->DefineCommand("sm_reload_databases", "Reparse database configurations file", sm_reload_databases);
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModLevelChange(const char *mapName)
|
||||
{
|
||||
m_Builder.StartParse();
|
||||
SMCError err;
|
||||
SMCStates states = {0, 0};
|
||||
|
||||
/* We lock and don't give up the lock until we're done.
|
||||
* This way the thread's search won't be searching through a
|
||||
* potentially empty/corrupt list, which would be very bad.
|
||||
*/
|
||||
m_pConfigLock->Lock();
|
||||
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
|
||||
{
|
||||
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
||||
if (err != SMCError_Custom)
|
||||
{
|
||||
const char *txt = textparsers->GetSMCErrorString(err);
|
||||
g_Logger.LogError("[SM] Line %d: %s", states.line, txt);
|
||||
}
|
||||
}
|
||||
m_pConfigLock->Unlock();
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModShutdown()
|
||||
{
|
||||
g_pSM->RemoveGameFrameHook(&FrameHook);
|
||||
KillWorkerThread();
|
||||
g_PluginSys.RemovePluginsListener(this);
|
||||
m_pConfigLock->DestroyThis();
|
||||
m_pThinkLock->DestroyThis();
|
||||
m_pQueueLock->DestroyThis();
|
||||
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
|
||||
}
|
||||
@@ -126,10 +131,128 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
}
|
||||
}
|
||||
|
||||
void DBManager::ReadSMC_ParseStart()
|
||||
{
|
||||
m_confs.clear();
|
||||
m_ParseLevel = 0;
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
m_StrTab.Reset();
|
||||
m_DefDriver.clear();
|
||||
}
|
||||
|
||||
ConfDbInfo s_CurInfo;
|
||||
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
m_ParseLevel++;
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_NONE)
|
||||
{
|
||||
if (strcmp(name, "Databases") == 0)
|
||||
{
|
||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||
} else {
|
||||
m_ParseLevel++;
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||
s_CurInfo = ConfDbInfo();
|
||||
s_CurInfo.name = m_StrTab.AddString(name);
|
||||
m_ParseState = DBPARSE_LEVEL_DATABASE;
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
m_ParseLevel++;
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_MAIN)
|
||||
{
|
||||
if (strcmp(key, "driver_default") == 0)
|
||||
{
|
||||
m_DefDriver.assign(value);
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
if (strcmp(key, "driver") == 0)
|
||||
{
|
||||
if (strcmp(value, "default") != 0)
|
||||
{
|
||||
s_CurInfo.driver = m_StrTab.AddString(value);
|
||||
}
|
||||
} else if (strcmp(key, "database") == 0) {
|
||||
s_CurInfo.database = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "host") == 0) {
|
||||
s_CurInfo.host = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "user") == 0) {
|
||||
s_CurInfo.user = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "pass") == 0) {
|
||||
s_CurInfo.pass = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "timeout") == 0) {
|
||||
s_CurInfo.info.maxTimeout = atoi(value);
|
||||
} else if (strcmp(key, "port") == 0) {
|
||||
s_CurInfo.info.port = atoi(value);
|
||||
}
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
#define ASSIGN_VAR(var) \
|
||||
if (s_CurInfo.var == -1) { \
|
||||
s_CurInfo.info.var = ""; \
|
||||
} else { \
|
||||
s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
|
||||
}
|
||||
|
||||
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
m_ParseLevel--;
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||
{
|
||||
/* Set all of the info members to either a blank string
|
||||
* or the string pointer from the string table.
|
||||
*/
|
||||
ASSIGN_VAR(driver);
|
||||
ASSIGN_VAR(database);
|
||||
ASSIGN_VAR(host);
|
||||
ASSIGN_VAR(user);
|
||||
ASSIGN_VAR(pass);
|
||||
|
||||
/* Save it.. */
|
||||
m_confs.push_back(s_CurInfo);
|
||||
|
||||
/* Go up one level */
|
||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
return SMCResult_Halt;
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
#undef ASSIGN_VAR
|
||||
|
||||
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||
{
|
||||
}
|
||||
|
||||
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
|
||||
{
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
ke::RefPtr<ConfDbInfo> pInfo = list.GetDatabaseConf(name);
|
||||
ConfDbInfo *pInfo = GetDatabaseConf(name);
|
||||
|
||||
if (!pInfo)
|
||||
{
|
||||
@@ -138,7 +261,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
||||
*pdr = NULL;
|
||||
}
|
||||
*pdb = NULL;
|
||||
g_pSM->Format(error, maxlength, "Configuration \"%s\" not found", name);
|
||||
UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -148,12 +271,11 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
||||
/* Try to assign a real driver pointer */
|
||||
if (pInfo->info.driver[0] == '\0')
|
||||
{
|
||||
std::string defaultDriver = list.GetDefaultDriver();
|
||||
if (!m_pDefault && defaultDriver.length() > 0)
|
||||
if (!m_pDefault && m_DefDriver.size() > 0)
|
||||
{
|
||||
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
|
||||
}
|
||||
dname = defaultDriver.length() ? defaultDriver.c_str() : "default";
|
||||
dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
|
||||
pInfo->realDriver = m_pDefault;
|
||||
} else {
|
||||
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
|
||||
@@ -176,7 +298,8 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
||||
}
|
||||
*pdb = NULL;
|
||||
|
||||
g_pSM->Format(error, maxlength, "Driver \"%s\" not found", dname);
|
||||
UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -189,7 +312,7 @@ void DBManager::AddDriver(IDBDriver *pDriver)
|
||||
*/
|
||||
KillWorkerThread();
|
||||
|
||||
m_drivers.push_back(pDriver);
|
||||
m_drivers.push_back(pDriver);
|
||||
}
|
||||
|
||||
void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
@@ -209,18 +332,15 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
}
|
||||
}
|
||||
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
for (auto conf : list) {
|
||||
if (conf->realDriver == pDriver)
|
||||
{
|
||||
conf->realDriver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Someone unloaded the default driver? Silly.. */
|
||||
if (pDriver == m_pDefault)
|
||||
/* Make sure NOTHING references this! */
|
||||
List<ConfDbInfo>::iterator iter;
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
m_pDefault = NULL;
|
||||
ConfDbInfo &db = (*iter);
|
||||
if (db.realDriver == pDriver)
|
||||
{
|
||||
db.realDriver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that the driver is gone, we have to test the think queue.
|
||||
@@ -252,11 +372,9 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
|
||||
IDBDriver *DBManager::GetDefaultDriver()
|
||||
{
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
std::string defaultDriver = list.GetDefaultDriver();
|
||||
if (!m_pDefault && defaultDriver.length() > 0)
|
||||
if (!m_pDefault && m_DefDriver.size() > 0)
|
||||
{
|
||||
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
|
||||
}
|
||||
|
||||
return m_pDefault;
|
||||
@@ -319,25 +437,29 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
|
||||
|
||||
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
||||
{
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
ke::RefPtr<ConfDbInfo> info = list.GetDatabaseConf(name);
|
||||
ConfDbInfo *info = GetDatabaseConf(name);
|
||||
if (!info)
|
||||
{
|
||||
// couldn't find requested conf, return default if exists
|
||||
info = list.GetDefaultConfiguration();
|
||||
if (!info)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &info->info;
|
||||
}
|
||||
|
||||
ke::RefPtr<ConfDbInfo> DBManager::GetDatabaseConf(const char *name)
|
||||
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
|
||||
{
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
return list.GetDatabaseConf(name);
|
||||
List<ConfDbInfo>::iterator iter;
|
||||
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
ConfDbInfo &conf = (*iter);
|
||||
if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
|
||||
{
|
||||
return &conf;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||
@@ -352,7 +474,7 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||
}
|
||||
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
g_pSM->Format(filename, sizeof(filename), "dbi.%s.ext", name);
|
||||
UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
|
||||
|
||||
IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
|
||||
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
|
||||
@@ -373,16 +495,12 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||
|
||||
void DBManager::KillWorkerThread()
|
||||
{
|
||||
if (m_Worker)
|
||||
if (m_pWorker)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Lock);
|
||||
m_Terminate = true;
|
||||
m_QueueEvent.notify_all();
|
||||
}
|
||||
m_Worker->join();
|
||||
m_Worker = nullptr;
|
||||
m_Terminate = false;
|
||||
m_pWorker->Stop(false);
|
||||
g_pThreader->DestroyWorker(m_pWorker);
|
||||
m_pWorker = NULL;
|
||||
s_OneTimeThreaderErrorMsg = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,95 +513,99 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_Worker)
|
||||
if (!m_pWorker)
|
||||
{
|
||||
m_Worker = ke::NewThread("SM Database Worker", [this]() -> void {
|
||||
Run();
|
||||
});
|
||||
m_pWorker = g_pThreader->MakeWorker(this, true);
|
||||
if (!m_pWorker)
|
||||
{
|
||||
if (!s_OneTimeThreaderErrorMsg)
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
|
||||
s_OneTimeThreaderErrorMsg = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!m_pWorker->Start())
|
||||
{
|
||||
if (!s_OneTimeThreaderErrorMsg)
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to start db threader (error unknown)");
|
||||
s_OneTimeThreaderErrorMsg = true;
|
||||
}
|
||||
g_pThreader->DestroyWorker(m_pWorker);
|
||||
m_pWorker = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add to the queue */
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Lock);
|
||||
m_pQueueLock->Lock();
|
||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
||||
queue.push(op);
|
||||
m_QueueEvent.notify_one();
|
||||
m_pQueueLock->Unlock();
|
||||
}
|
||||
|
||||
/* Make the thread */
|
||||
m_pWorker->MakeThread(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DBManager::Run()
|
||||
void DBManager::OnWorkerStart(IThreadWorker *pWorker)
|
||||
{
|
||||
// Initialize DB threadsafety.
|
||||
for (size_t i=0; i < m_drivers.size(); i++)
|
||||
m_drSafety.clear();
|
||||
for (size_t i=0; i<m_drivers.size(); i++)
|
||||
{
|
||||
if (m_drivers[i]->IsThreadSafe())
|
||||
{
|
||||
m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
|
||||
else
|
||||
} else {
|
||||
m_drSafety.push_back(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run actual worker thread logic.
|
||||
ThreadMain();
|
||||
|
||||
// Shutdown DB threadsafety.
|
||||
void DBManager::OnWorkerStop(IThreadWorker *pWorker)
|
||||
{
|
||||
for (size_t i=0; i<m_drivers.size(); i++)
|
||||
{
|
||||
if (m_drSafety[i])
|
||||
{
|
||||
m_drivers[i]->ShutdownThreadSafety();
|
||||
}
|
||||
}
|
||||
m_drSafety.clear();
|
||||
}
|
||||
|
||||
void DBManager::ThreadMain()
|
||||
void DBManager::RunThread(IThreadHandle *pThread)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_Lock);
|
||||
IDBThreadOperation *op = NULL;
|
||||
|
||||
while (true) {
|
||||
// The lock has been acquired. Grab everything we can out of the
|
||||
// queue. Since we want to flush the queue even if we're terminated,
|
||||
// we process all operations we can before checking to terminate.
|
||||
// There's no risk of starvation since the main thread blocks on us
|
||||
// terminating.
|
||||
auto queue = &m_OpQueue.GetLikelyQueue();
|
||||
if (queue->empty()) {
|
||||
// If the queue is empty and we've been asked to stop, leave now.
|
||||
if (m_Terminate)
|
||||
return;
|
||||
|
||||
// Otherwise, wait for something to happen.
|
||||
m_QueueEvent.wait(lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
IDBThreadOperation *op = queue->first();
|
||||
queue->pop();
|
||||
|
||||
// Unlock the queue when we run the query, so the main thread can
|
||||
// keep pumping events. We re-acquire the lock to check for more
|
||||
// items. It's okay if we terminate while unlocked; the main
|
||||
// thread would be blocked and we'd need to flush the queue
|
||||
// anyway, so after we've depleted the queue here, we'll just
|
||||
// reach the terminate at the top of the loop.
|
||||
lock.unlock();
|
||||
op->RunThreadPart();
|
||||
|
||||
// Re-acquire the lock and give the data back to the main thread
|
||||
// immediately. We use a separate lock to minimize game thread
|
||||
// contention.
|
||||
/* Get something from the queue */
|
||||
{
|
||||
m_pQueueLock->Lock();
|
||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
|
||||
if (!queue.empty())
|
||||
{
|
||||
std::lock_guard<std::mutex> think_lock(m_ThinkLock);
|
||||
m_ThinkQueue.push(op);
|
||||
op = queue.first();
|
||||
queue.pop();
|
||||
}
|
||||
|
||||
// Note that we add a 20ms delay after processing a query. This is
|
||||
// questionable but the intent is to avoid starving the game thread.
|
||||
if (!m_Terminate)
|
||||
std::this_thread::sleep_for(20ms);
|
||||
|
||||
lock.lock();
|
||||
m_pQueueLock->Unlock();
|
||||
}
|
||||
|
||||
/* whoa. hi. did we get something? we should have. */
|
||||
if (!op)
|
||||
{
|
||||
/* wtf? */
|
||||
return;
|
||||
}
|
||||
|
||||
op->RunThreadPart();
|
||||
|
||||
m_pThinkLock->Lock();
|
||||
m_ThinkQueue.push(op);
|
||||
m_pThinkLock->Unlock();
|
||||
}
|
||||
|
||||
void DBManager::RunFrame()
|
||||
@@ -495,16 +617,19 @@ void DBManager::RunFrame()
|
||||
}
|
||||
|
||||
/* Dump one thing per-frame so the server stays sane. */
|
||||
IDBThreadOperation *op;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ThinkLock);
|
||||
op = m_ThinkQueue.first();
|
||||
m_ThinkQueue.pop();
|
||||
}
|
||||
m_pThinkLock->Lock();
|
||||
IDBThreadOperation *op = m_ThinkQueue.first();
|
||||
m_ThinkQueue.pop();
|
||||
m_pThinkLock->Unlock();
|
||||
op->RunThinkPart();
|
||||
op->Destroy();
|
||||
}
|
||||
|
||||
void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
|
||||
{
|
||||
s_pAddBlock = pToken;
|
||||
@@ -542,7 +667,7 @@ void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
|
||||
s_pAddBlock = NULL;
|
||||
}
|
||||
|
||||
void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
||||
void DBManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
/* Kill the thread so we can flush everything into the think queue... */
|
||||
KillWorkerThread();
|
||||
@@ -568,7 +693,9 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
||||
}
|
||||
}
|
||||
|
||||
for (iter = templist.begin(); iter != templist.end(); iter++)
|
||||
for (iter = templist.begin();
|
||||
iter != templist.end();
|
||||
iter++)
|
||||
{
|
||||
IDBThreadOperation *op = (*iter);
|
||||
op->RunThinkPart();
|
||||
@@ -576,13 +703,23 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
||||
}
|
||||
}
|
||||
|
||||
std::string DBManager::GetDefaultDriverName()
|
||||
void DBManager::LockConfig()
|
||||
{
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
return list.GetDefaultDriver();
|
||||
m_pConfigLock->Lock();
|
||||
}
|
||||
|
||||
void DBManager::UnlockConfig()
|
||||
{
|
||||
m_pConfigLock->Unlock();
|
||||
}
|
||||
|
||||
const char *DBManager::GetDefaultDriverName()
|
||||
{
|
||||
return m_DefDriver.c_str();
|
||||
}
|
||||
|
||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||
{
|
||||
g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -32,27 +32,42 @@
|
||||
#ifndef _INCLUDE_DATABASE_MANAGER_H_
|
||||
#define _INCLUDE_DATABASE_MANAGER_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <IDBDriver.h>
|
||||
#include "sm_globals.h"
|
||||
#include <sh_vector.h>
|
||||
#include <am-string.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
#include <ITextParsers.h>
|
||||
#include "sm_memtable.h"
|
||||
#include <IThreader.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "sm_simple_prioqueue.h"
|
||||
#include <am-refcounting.h>
|
||||
#include "DatabaseConfBuilder.h"
|
||||
#include "PluginSys.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct ConfDbInfo
|
||||
{
|
||||
ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
|
||||
database(-1), realDriver(NULL)
|
||||
{
|
||||
}
|
||||
int name;
|
||||
int driver;
|
||||
int host;
|
||||
int user;
|
||||
int pass;
|
||||
int database;
|
||||
IDBDriver *realDriver;
|
||||
DatabaseInfo info;
|
||||
};
|
||||
|
||||
class DBManager :
|
||||
public IDBManager,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch,
|
||||
public ITextListener_SMC,
|
||||
public IThread,
|
||||
public IThreadWorkerCallbacks,
|
||||
public IPluginsListener
|
||||
{
|
||||
public:
|
||||
@@ -71,7 +86,6 @@ public: //IDBManager
|
||||
void AddDriver(IDBDriver *pDrivera);
|
||||
void RemoveDriver(IDBDriver *pDriver);
|
||||
const DatabaseInfo *FindDatabaseConf(const char *name);
|
||||
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name);
|
||||
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
|
||||
unsigned int GetDriverCount();
|
||||
IDBDriver *GetDriver(unsigned int index);
|
||||
@@ -79,23 +93,34 @@ public: //IDBManager
|
||||
HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
|
||||
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
|
||||
void AddDependency(IExtension *myself, IDBDriver *driver);
|
||||
public: //ke::IRunnable
|
||||
void Run();
|
||||
void ThreadMain();
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||
void ReadSMC_ParseEnd(bool halted, bool failed);
|
||||
public: //IThread
|
||||
void RunThread(IThreadHandle *pThread);
|
||||
void OnTerminate(IThreadHandle *pThread, bool cancel);
|
||||
public: //IThreadWorkerCallbacks
|
||||
void OnWorkerStart(IThreadWorker *pWorker);
|
||||
void OnWorkerStop(IThreadWorker *pWorker);
|
||||
public: //IPluginsListener
|
||||
void OnPluginWillUnload(IPlugin *plugin);
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public:
|
||||
ConfDbInfo *GetDatabaseConf(const char *name);
|
||||
IDBDriver *FindOrLoadDriver(const char *name);
|
||||
IDBDriver *GetDefaultDriver();
|
||||
std::string GetDefaultDriverName();
|
||||
const char *GetDefaultDriverName();
|
||||
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
|
||||
void LockConfig();
|
||||
void UnlockConfig();
|
||||
void RunFrame();
|
||||
inline HandleType_t GetDatabaseType()
|
||||
{
|
||||
return m_DatabaseType;
|
||||
}
|
||||
private:
|
||||
void ClearConfigs();
|
||||
void KillWorkerThread();
|
||||
private:
|
||||
CVector<IDBDriver *> m_drivers;
|
||||
@@ -104,16 +129,19 @@ private:
|
||||
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
||||
Queue<IDBThreadOperation *> m_ThinkQueue;
|
||||
CVector<bool> m_drSafety; /* which drivers are safe? */
|
||||
std::unique_ptr<std::thread> m_Worker;
|
||||
std::condition_variable m_QueueEvent;
|
||||
std::mutex m_ThinkLock;
|
||||
std::mutex m_Lock;
|
||||
bool m_Terminate;
|
||||
IThreadWorker *m_pWorker; /* Worker thread object */
|
||||
IMutex *m_pConfigLock; /* Configuration lock */
|
||||
IMutex *m_pQueueLock; /* Queue safety lock */
|
||||
IMutex *m_pThinkLock; /* Think-queue lock */
|
||||
|
||||
DatabaseConfBuilder m_Builder;
|
||||
List<ConfDbInfo> m_confs;
|
||||
HandleType_t m_DriverType;
|
||||
HandleType_t m_DatabaseType;
|
||||
String m_DefDriver;
|
||||
BaseStringTable m_StrTab;
|
||||
char m_Filename[PLATFORM_MAX_PATH];
|
||||
unsigned int m_ParseLevel;
|
||||
unsigned int m_ParseState;
|
||||
IDBDriver *m_pDefault;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -29,11 +29,10 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <ISourceMod.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <stdarg.h>
|
||||
#include "DebugReporter.h"
|
||||
#include "Logger.h"
|
||||
#include "PluginSys.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
DebugReport g_DbgReporter;
|
||||
|
||||
@@ -48,7 +47,7 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, msg);
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), msg, ap);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_Logger.LogMessage("[SM] %s", buffer);
|
||||
@@ -57,25 +56,20 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
|
||||
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, message);
|
||||
GenerateErrorVA(ctx, func_idx, err, message, ap);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap)
|
||||
{
|
||||
char buffer[512];
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
||||
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||
|
||||
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
|
||||
if (err >= 0) {
|
||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||
if (error)
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||
else
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||
if (error)
|
||||
{
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||
} else {
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
@@ -100,10 +94,10 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, message);
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||
va_end(ap);
|
||||
|
||||
const char *plname = pluginsys->FindPluginByContext(pContext->GetContext())->GetFilename();
|
||||
const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
|
||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||
|
||||
if (error)
|
||||
@@ -133,10 +127,55 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
}
|
||||
}
|
||||
|
||||
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
||||
{
|
||||
const char *lastname;
|
||||
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
int n_err = error->GetErrorCode();
|
||||
|
||||
if (n_err != SP_ERROR_NATIVE)
|
||||
{
|
||||
g_Logger.LogError("[SM] Plugin encountered error %d: %s",
|
||||
n_err,
|
||||
error->GetErrorString());
|
||||
}
|
||||
|
||||
if ((lastname=error->GetLastNative(NULL)) != NULL)
|
||||
{
|
||||
const char *custerr;
|
||||
if ((custerr=error->GetCustomErrorString()) != NULL)
|
||||
{
|
||||
g_Logger.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
|
||||
} else {
|
||||
g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!error->DebugInfoAvailable())
|
||||
{
|
||||
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
||||
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
||||
_GetPluginIndex(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
CallStackInfo stk_info;
|
||||
int i = 0;
|
||||
g_Logger.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
|
||||
while (error->GetTraceInfo(&stk_info))
|
||||
{
|
||||
g_Logger.LogError("[SM] [%d] Line %d, %s::%s()",
|
||||
i++,
|
||||
stk_info.line,
|
||||
stk_info.filename,
|
||||
stk_info.function);
|
||||
}
|
||||
}
|
||||
|
||||
int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
||||
{
|
||||
int id = 1;
|
||||
IPluginIterator *iter = pluginsys->GetPluginIterator();
|
||||
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
|
||||
|
||||
for (; iter->MorePlugins(); iter->NextPlugin(), id++)
|
||||
{
|
||||
@@ -152,95 +191,6 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
||||
|
||||
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
|
||||
|
||||
return pluginsys->GetPluginCount() + 1;
|
||||
return g_PluginSys.GetPluginCount() + 1;
|
||||
}
|
||||
|
||||
void DebugReport::ReportError(const IErrorReport &report, IFrameIterator &iter)
|
||||
{
|
||||
// Don't log an error if a function wasn't runnable.
|
||||
// This is necassary due to the way SM is handling and exposing
|
||||
// scripted functions. It's too late to change that now.
|
||||
if (report.Code() == SP_ERROR_NOT_RUNNABLE)
|
||||
return;
|
||||
|
||||
const char *blame = nullptr;
|
||||
if (report.Blame())
|
||||
{
|
||||
blame = report.Blame()->DebugName();
|
||||
} else {
|
||||
// Find the nearest plugin to blame.
|
||||
for (; !iter.Done(); iter.Next())
|
||||
{
|
||||
if (iter.IsScriptedFrame())
|
||||
{
|
||||
IPlugin *plugin = pluginsys->FindPluginByContext(iter.Context()->GetContext());
|
||||
if (plugin)
|
||||
{
|
||||
blame = plugin->GetFilename();
|
||||
} else {
|
||||
blame = iter.Context()->GetRuntime()->GetFilename();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iter.Reset();
|
||||
|
||||
g_Logger.LogError("[SM] Exception reported: %s", report.Message());
|
||||
|
||||
if (blame)
|
||||
{
|
||||
g_Logger.LogError("[SM] Blaming: %s", blame);
|
||||
}
|
||||
|
||||
std::vector<std::string> arr = GetStackTrace(&iter);
|
||||
for (size_t i = 0; i < arr.size(); i++)
|
||||
{
|
||||
g_Logger.LogError("%s", arr[i].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> DebugReport::GetStackTrace(IFrameIterator *iter)
|
||||
{
|
||||
char temp[3072];
|
||||
std::vector<std::string> trace;
|
||||
iter->Reset();
|
||||
|
||||
if (!iter->Done())
|
||||
{
|
||||
trace.push_back("[SM] Call stack trace:");
|
||||
|
||||
for (int index = 0; !iter->Done(); iter->Next(), index++)
|
||||
{
|
||||
const char *fn = iter->FunctionName();
|
||||
if (!fn)
|
||||
{
|
||||
fn = "<unknown function>";
|
||||
}
|
||||
if (iter->IsNativeFrame())
|
||||
{
|
||||
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] %s", index, fn);
|
||||
trace.push_back(temp);
|
||||
continue;
|
||||
}
|
||||
if (iter->IsScriptedFrame())
|
||||
{
|
||||
const char *file = iter->FilePath();
|
||||
if (!file)
|
||||
{
|
||||
file = "<unknown>";
|
||||
}
|
||||
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] Line %d, %s::%s",
|
||||
index,
|
||||
iter->LineNumber(),
|
||||
file,
|
||||
fn);
|
||||
|
||||
trace.push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trace;
|
||||
}
|
||||
@@ -33,9 +33,7 @@
|
||||
#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_
|
||||
|
||||
#include "sp_vm_api.h"
|
||||
#include "common_logic.h"
|
||||
#include <am-vector.h>
|
||||
#include <am-string.h>
|
||||
#include "sm_globals.h"
|
||||
|
||||
class DebugReport :
|
||||
public SMGlobalClass,
|
||||
@@ -44,15 +42,11 @@ class DebugReport :
|
||||
public: // SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
public: // IDebugListener
|
||||
void ReportError(const IErrorReport &report, IFrameIterator &iter);
|
||||
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
||||
void OnDebugSpew(const char *msg, ...);
|
||||
public:
|
||||
// If err is -1, caller assumes the automatic reporting by SourcePawn is
|
||||
// good enough, and only wants the supplemental logging provided here.
|
||||
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
||||
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
|
||||
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
||||
std::vector<std::string> GetStackTrace(IFrameIterator *iter);
|
||||
private:
|
||||
int _GetPluginIndex(IPluginContext *ctx);
|
||||
};
|
||||
+42
-75
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -30,11 +30,10 @@
|
||||
*/
|
||||
|
||||
#include "EventManager.h"
|
||||
#include "ForwardSys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "PlayerManager.h"
|
||||
|
||||
#include "logic_bridge.h"
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
|
||||
EventManager g_EventManager;
|
||||
|
||||
@@ -43,26 +42,16 @@ SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *,
|
||||
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
|
||||
typedef List<EventHook *> EventHookList;
|
||||
|
||||
class EventForwardFilter : public IForwardFilter
|
||||
{
|
||||
EventInfo *pEventInfo;
|
||||
public:
|
||||
EventForwardFilter(EventInfo *pEventInfo) : pEventInfo(pEventInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
|
||||
{
|
||||
params[2].val = pEventInfo->bDontBroadcast ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
EventManager::EventManager() : m_EventType(0)
|
||||
{
|
||||
/* Create an event lookup trie */
|
||||
m_EventHooks = sm_trie_create();
|
||||
}
|
||||
|
||||
EventManager::~EventManager()
|
||||
{
|
||||
sm_trie_destroy(m_EventHooks);
|
||||
|
||||
/* Free memory used by EventInfo structs if any */
|
||||
CStack<EventInfo *>::iterator iter;
|
||||
for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
|
||||
@@ -76,8 +65,8 @@ EventManager::~EventManager()
|
||||
void EventManager::OnSourceModAllInitialized()
|
||||
{
|
||||
/* Add a hook for IGameEventManager2::FireEvent() */
|
||||
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
|
||||
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
|
||||
SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
|
||||
SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
|
||||
|
||||
HandleAccess sec;
|
||||
|
||||
@@ -87,17 +76,17 @@ void EventManager::OnSourceModAllInitialized()
|
||||
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
||||
|
||||
/* Create the 'GameEvent' handle type */
|
||||
m_EventType = handlesys->CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||
m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
void EventManager::OnSourceModShutdown()
|
||||
{
|
||||
/* Remove hook for IGameEventManager2::FireEvent() */
|
||||
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
|
||||
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
|
||||
|
||||
/* Remove the 'GameEvent' handle type */
|
||||
handlesys->RemoveType(m_EventType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
|
||||
|
||||
/* Remove ourselves as listener for events */
|
||||
gameevents->RemoveListener(this);
|
||||
@@ -135,12 +124,12 @@ void EventManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
if (pHook->pPreHook)
|
||||
{
|
||||
forwardsys->ReleaseForward(pHook->pPreHook);
|
||||
g_Forwards.ReleaseForward(pHook->pPreHook);
|
||||
}
|
||||
|
||||
if (pHook->pPostHook)
|
||||
{
|
||||
forwardsys->ReleaseForward(pHook->pPostHook);
|
||||
g_Forwards.ReleaseForward(pHook->pPostHook);
|
||||
}
|
||||
|
||||
delete pHook;
|
||||
@@ -158,13 +147,6 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
|
||||
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
int EventManager::GetEventDebugID()
|
||||
{
|
||||
return EVENT_DEBUG_ID_INIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
|
||||
{
|
||||
EventHook *pHook;
|
||||
@@ -181,10 +163,10 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
||||
}
|
||||
|
||||
/* If a hook structure does not exist... */
|
||||
if (!m_EventHooks.retrieve(name, &pHook))
|
||||
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
|
||||
{
|
||||
EventHookList *pHookList;
|
||||
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
|
||||
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
|
||||
|
||||
/* Check plugin for an existing EventHook list */
|
||||
if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
|
||||
@@ -199,12 +181,12 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
||||
if (mode == EventHookMode_Pre)
|
||||
{
|
||||
/* Create forward for a pre hook */
|
||||
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
|
||||
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
|
||||
/* Add to forward list */
|
||||
pHook->pPreHook->AddFunction(pFunction);
|
||||
} else {
|
||||
/* Create forward for a post hook */
|
||||
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
||||
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
||||
/* Should we copy data from a pre hook to the post hook? */
|
||||
pHook->postCopy = (mode == EventHookMode_Post);
|
||||
/* Add to forward list */
|
||||
@@ -212,14 +194,14 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
||||
}
|
||||
|
||||
/* Cache the name for post hooks */
|
||||
pHook->name = name;
|
||||
pHook->name = sm_strdup(name);
|
||||
|
||||
/* Increase reference count */
|
||||
pHook->refCount++;
|
||||
|
||||
/* Add hook structure to hook lists */
|
||||
pHookList->push_back(pHook);
|
||||
m_EventHooks.insert(name, pHook);
|
||||
sm_trie_insert(m_EventHooks, name, pHook);
|
||||
|
||||
return EventHookErr_Okay;
|
||||
}
|
||||
@@ -231,7 +213,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
||||
/* Create pre hook forward if necessary */
|
||||
if (!pHook->pPreHook)
|
||||
{
|
||||
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
|
||||
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
|
||||
}
|
||||
|
||||
/* Add plugin function to forward list */
|
||||
@@ -240,7 +222,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
||||
/* Create post hook forward if necessary */
|
||||
if (!pHook->pPostHook)
|
||||
{
|
||||
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
||||
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
||||
}
|
||||
|
||||
/* If postCopy is false, then we may want to set it to true */
|
||||
@@ -265,7 +247,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
||||
IChangeableForward **pEventForward;
|
||||
|
||||
/* If hook does not exist at all */
|
||||
if (!m_EventHooks.retrieve(name, &pHook))
|
||||
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
|
||||
{
|
||||
return EventHookErr_NotActive;
|
||||
}
|
||||
@@ -287,7 +269,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
||||
/* If forward's list contains 0 functions now, free it */
|
||||
if ((*pEventForward)->GetFunctionCount() == 0)
|
||||
{
|
||||
forwardsys->ReleaseForward(*pEventForward);
|
||||
g_Forwards.ReleaseForward(*pEventForward);
|
||||
*pEventForward = NULL;
|
||||
}
|
||||
|
||||
@@ -297,7 +279,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
||||
/* If reference count is now 0, free hook structure */
|
||||
|
||||
EventHookList *pHookList;
|
||||
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
|
||||
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
|
||||
|
||||
/* Get plugin's event hook list */
|
||||
if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
|
||||
@@ -315,7 +297,10 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
||||
pHookList->remove(pHook);
|
||||
|
||||
/* Delete entry in trie */
|
||||
m_EventHooks.remove(name);
|
||||
sm_trie_delete(m_EventHooks, name);
|
||||
|
||||
/* Free the cached name */
|
||||
delete pHook->name;
|
||||
|
||||
/* And finally free structure memory */
|
||||
delete pHook;
|
||||
@@ -342,7 +327,6 @@ EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name,
|
||||
|
||||
pInfo->pEvent = pEvent;
|
||||
pInfo->pOwner = pContext->GetIdentity();
|
||||
pInfo->bDontBroadcast = false;
|
||||
|
||||
return pInfo;
|
||||
}
|
||||
@@ -362,13 +346,6 @@ void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
|
||||
m_FreeEvents.push(pInfo);
|
||||
}
|
||||
|
||||
void EventManager::FireEventToClient(EventInfo *pInfo, IClient *pClient)
|
||||
{
|
||||
// The IClient vtable is +sizeof(void *) from the IGameEventListener2 (CBaseClient) vtable due to multiple inheritance.
|
||||
IGameEventListener2 *pGameClient = (IGameEventListener2 *)((intptr_t)pClient - sizeof(void *));
|
||||
pGameClient->FireGameEvent(pInfo->pEvent);
|
||||
}
|
||||
|
||||
void EventManager::CancelCreatedEvent(EventInfo *pInfo)
|
||||
{
|
||||
/* Free event from IGameEventManager2 */
|
||||
@@ -388,7 +365,6 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
IChangeableForward *pForward;
|
||||
const char *name;
|
||||
cell_t res = Pl_Continue;
|
||||
bool broadcast = bDontBroadcast;
|
||||
|
||||
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
|
||||
if (!pEvent)
|
||||
@@ -398,7 +374,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
|
||||
name = pEvent->GetName();
|
||||
|
||||
if (m_EventHooks.retrieve(name, &pHook))
|
||||
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
|
||||
{
|
||||
/* Push the event onto the event stack. The reference count is increased to make sure
|
||||
* the structure is not garbage collected in between now and the post hook.
|
||||
@@ -412,20 +388,14 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
{
|
||||
EventInfo info(pEvent, NULL);
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
Handle_t hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
info.bDontBroadcast = bDontBroadcast;
|
||||
|
||||
EventForwardFilter filter(&info);
|
||||
Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
pForward->PushCell(hndl);
|
||||
pForward->PushString(name);
|
||||
pForward->PushCell(bDontBroadcast);
|
||||
pForward->Execute(&res, &filter);
|
||||
pForward->Execute(&res, NULL);
|
||||
|
||||
broadcast = info.bDontBroadcast;
|
||||
|
||||
handlesys->FreeHandle(hndl, &sec);
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
}
|
||||
|
||||
if (pHook->postCopy)
|
||||
@@ -433,7 +403,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
m_EventCopies.push(gameevents->DuplicateEvent(pEvent));
|
||||
}
|
||||
|
||||
if (res >= Pl_Handled)
|
||||
if (res)
|
||||
{
|
||||
gameevents->FreeEvent(pEvent);
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
@@ -444,9 +414,6 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
m_EventStack.push(NULL);
|
||||
}
|
||||
|
||||
if (broadcast != bDontBroadcast)
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &IGameEventManager2::FireEvent, (pEvent, broadcast));
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
@@ -474,17 +441,16 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
{
|
||||
if (pHook->postCopy)
|
||||
{
|
||||
info.bDontBroadcast = bDontBroadcast;
|
||||
info.pEvent = m_EventCopies.front();
|
||||
info.pOwner = NULL;
|
||||
hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||
hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
pForward->PushCell(hndl);
|
||||
} else {
|
||||
pForward->PushCell(BAD_HANDLE);
|
||||
}
|
||||
|
||||
pForward->PushString(pHook->name.c_str());
|
||||
pForward->PushString(pHook->name);
|
||||
pForward->PushCell(bDontBroadcast);
|
||||
pForward->Execute(NULL);
|
||||
|
||||
@@ -492,7 +458,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
{
|
||||
/* Free handle */
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
handlesys->FreeHandle(hndl, &sec);
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
|
||||
/* Free event structure */
|
||||
gameevents->FreeEvent(info.pEvent);
|
||||
@@ -505,7 +471,8 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
{
|
||||
assert(pHook->pPostHook == NULL);
|
||||
assert(pHook->pPreHook == NULL);
|
||||
m_EventHooks.remove(pHook->name.c_str());
|
||||
sm_trie_delete(m_EventHooks, pHook->name);
|
||||
delete pHook->name;
|
||||
delete pHook;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-21
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -34,15 +34,13 @@
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <sm_namehashset.h>
|
||||
#include "sm_trie.h"
|
||||
#include <sh_list.h>
|
||||
#include <sh_stack.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <IPluginSys.h>
|
||||
|
||||
class IClient;
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct EventInfo
|
||||
@@ -55,7 +53,6 @@ struct EventInfo
|
||||
}
|
||||
IGameEvent *pEvent;
|
||||
IdentityToken_t *pOwner;
|
||||
bool bDontBroadcast;
|
||||
};
|
||||
|
||||
struct EventHook
|
||||
@@ -71,16 +68,7 @@ struct EventHook
|
||||
IChangeableForward *pPostHook;
|
||||
bool postCopy;
|
||||
unsigned int refCount;
|
||||
std::string name;
|
||||
|
||||
static inline bool matches(const char *name, const EventHook *hook)
|
||||
{
|
||||
return strcmp(name, hook->name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum EventHookMode
|
||||
@@ -116,9 +104,6 @@ public: // IPluginsListener
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public: // IGameEventListener2
|
||||
void FireGameEvent(IGameEvent *pEvent);
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
int GetEventDebugID();
|
||||
#endif
|
||||
public:
|
||||
/**
|
||||
* Get the 'GameEvent' handle type ID.
|
||||
@@ -132,14 +117,13 @@ public:
|
||||
EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post);
|
||||
EventInfo *CreateEvent(IPluginContext *pContext, const char *name, bool force=false);
|
||||
void FireEvent(EventInfo *pInfo, bool bDontBroadcast=false);
|
||||
void FireEventToClient(EventInfo *pInfo, IClient *pClient);
|
||||
void CancelCreatedEvent(EventInfo *pInfo);
|
||||
private: // IGameEventManager2 hooks
|
||||
bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast);
|
||||
bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast);
|
||||
private:
|
||||
HandleType_t m_EventType;
|
||||
NameHashSet<EventHook *> m_EventHooks;
|
||||
Trie *m_EventHooks;
|
||||
CStack<EventInfo *> m_FreeEvents;
|
||||
CStack<EventHook *> m_EventStack;
|
||||
CStack<IGameEvent *> m_EventCopies;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,14 +36,14 @@
|
||||
#include <ILibrarySys.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include "common_logic.h"
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_globals.h"
|
||||
#include "ShareSys.h"
|
||||
#include <ISmmAPI.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include "PluginSys.h"
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
#include <bridge/include/IExtensionBridge.h>
|
||||
|
||||
class CPlayer;
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
@@ -66,7 +66,6 @@ public:
|
||||
public: //IExtension
|
||||
IExtensionInterface *GetAPI();
|
||||
const char *GetFilename();
|
||||
const char *GetPath() const;
|
||||
IdentityToken_t *GetIdentity();
|
||||
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||
@@ -80,7 +79,6 @@ public:
|
||||
void AddPlugin(CPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddLibrary(const char *library);
|
||||
bool IsRequired();
|
||||
public:
|
||||
virtual bool Load(char *error, size_t maxlength);
|
||||
virtual bool IsLoaded() =0;
|
||||
@@ -88,7 +86,7 @@ public:
|
||||
virtual bool Reload(char *error, size_t maxlength) =0;
|
||||
virtual bool IsSameFile(const char* file) =0;
|
||||
protected:
|
||||
void Initialize(const char *filename, const char *path, bool bRequired = true);
|
||||
void Initialize(const char *filename, const char *path);
|
||||
bool PerformAPICheck(char *error, size_t maxlength);
|
||||
void CreateIdentity();
|
||||
void DestroyIdentity();
|
||||
@@ -105,13 +103,12 @@ protected:
|
||||
List<String> m_Libraries;
|
||||
unsigned int unload_code;
|
||||
bool m_bFullyLoaded;
|
||||
bool m_bRequired;
|
||||
};
|
||||
|
||||
class CLocalExtension : public CExtension
|
||||
{
|
||||
public:
|
||||
CLocalExtension(const char *filename, bool bRequired = true);
|
||||
CLocalExtension(const char *filename);
|
||||
public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
@@ -120,7 +117,7 @@ public:
|
||||
bool IsExternal();
|
||||
bool IsSameFile(const char *file);
|
||||
private:
|
||||
int m_PlId;
|
||||
PluginId m_PlId;
|
||||
ILibrary *m_pLib;
|
||||
};
|
||||
|
||||
@@ -138,7 +135,7 @@ public:
|
||||
};
|
||||
|
||||
class CExtensionManager :
|
||||
public IExtensionSys,
|
||||
public IExtensionManager,
|
||||
public SMGlobalClass,
|
||||
public IPluginsListener,
|
||||
public IRootConsoleCommand
|
||||
@@ -164,22 +161,19 @@ public: //IExtensionManager
|
||||
public: //IPluginsListener
|
||||
void OnPluginDestroyed(IPlugin *plugin);
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command) override;
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public:
|
||||
IExtension *LoadAutoExtension(const char *path, bool bErrorOnMissing=true);
|
||||
IExtension *LoadAutoExtension(const char *path);
|
||||
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
||||
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
|
||||
void BindChildPlugin(IExtension *pParent, SMPlugin *pPlugin);
|
||||
void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
|
||||
void TryAutoload();
|
||||
void AddLibrary(IExtension *pSource, const char *library);
|
||||
bool LibraryExists(const char *library);
|
||||
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
void CallOnCoreMapEnd();
|
||||
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
|
||||
const CVector<IExtension *> *ListExtensions();
|
||||
void FreeExtensionList(const CVector<IExtension *> *list);
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
void Shutdown();
|
||||
@@ -1,65 +1,85 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet :
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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>.
|
||||
/**
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "ForwardSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ShareSys.h"
|
||||
#include "DebugReporter.h"
|
||||
#include "common_logic.h"
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <amtl/am-string.h>
|
||||
#include <ReentrantList.h>
|
||||
|
||||
using namespace ke;
|
||||
|
||||
CForwardManager g_Forwards;
|
||||
|
||||
// Genesis turns to its source, reduction occurs stepwise although the essence
|
||||
// is all one. End of line. FTL system check.
|
||||
/**
|
||||
* Genesis turns to its source, reduction occurs stepwise although the essence is all one.
|
||||
* End of line. FTL system check.
|
||||
*
|
||||
* :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
|
||||
* VARARG FUNCTIONS:
|
||||
* - Pushing no varargs
|
||||
*/
|
||||
|
||||
// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
|
||||
// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
|
||||
|
||||
CForwardManager::~CForwardManager()
|
||||
{
|
||||
CStack<CForward *>::iterator iter;
|
||||
for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
m_FreeForwards.popall();
|
||||
}
|
||||
|
||||
void CForwardManager::OnSourceModAllInitialized()
|
||||
{
|
||||
scripts->AddPluginsListener(this);
|
||||
sharesys->AddInterface(NULL, this);
|
||||
g_PluginSys.AddPluginsListener(this);
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
|
||||
{
|
||||
CForward *fwd;
|
||||
va_list ap;
|
||||
va_start(ap, types);
|
||||
|
||||
CForward *fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (fwd)
|
||||
{
|
||||
scripts->AddFunctionsToForward(name, fwd);
|
||||
g_PluginSys.AddFunctionsToForward(name, fwd);
|
||||
|
||||
m_managed.push_back(fwd);
|
||||
}
|
||||
@@ -69,10 +89,11 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned
|
||||
|
||||
IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
|
||||
{
|
||||
CForward *fwd;
|
||||
va_list ap;
|
||||
va_start(ap, types);
|
||||
|
||||
CForward *fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
@@ -87,103 +108,115 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType
|
||||
void CForwardManager::OnPluginLoaded(IPlugin *plugin)
|
||||
{
|
||||
/* Attach any globally managed forwards */
|
||||
for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
|
||||
CForward *fwd = (*iter);
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
|
||||
if (pFunc)
|
||||
fwd->AddFunction(pFunc);
|
||||
}
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
|
||||
CForward *fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
|
||||
for (ForwardIter iter(m_unmanaged); !iter.done(); iter.next()) {
|
||||
CForward *fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
|
||||
{
|
||||
for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
|
||||
CForward *fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0) {
|
||||
if (ifchng)
|
||||
*ifchng = NULL;
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
for (ForwardIter iter(m_unmanaged); !iter.done(); iter.next()) {
|
||||
CForward *fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0) {
|
||||
if (ifchng)
|
||||
*ifchng = fwd;
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifchng)
|
||||
*ifchng = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CForwardManager::ReleaseForward(IForward *aForward)
|
||||
{
|
||||
CForward *fwd = static_cast<CForward *>(aForward);
|
||||
m_managed.remove(fwd);
|
||||
m_unmanaged.remove(fwd);
|
||||
delete fwd;
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
|
||||
{
|
||||
if (paused)
|
||||
return;
|
||||
|
||||
/* Attach any globally managed forwards */
|
||||
for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
|
||||
CForward *fwd = (*iter);
|
||||
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
|
||||
// Only add functions, if they aren't registered yet!
|
||||
if (pFunc && !fwd->IsFunctionRegistered(pFunc))
|
||||
{
|
||||
fwd->AddFunction(pFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
|
||||
for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
|
||||
{
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0)
|
||||
{
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = NULL;
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0)
|
||||
{
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = fwd;
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CForwardManager::ReleaseForward(IForward *forward)
|
||||
{
|
||||
ForwardFree(static_cast<CForward *>(forward));
|
||||
}
|
||||
|
||||
void CForwardManager::ForwardFree(CForward *fwd)
|
||||
{
|
||||
if (fwd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_FreeForwards.push(fwd);
|
||||
m_managed.remove(fwd);
|
||||
}
|
||||
|
||||
CForward *CForwardManager::ForwardMake()
|
||||
{
|
||||
CForward *fwd;
|
||||
if (m_FreeForwards.empty())
|
||||
{
|
||||
fwd = new CForward;
|
||||
} else {
|
||||
fwd = m_FreeForwards.front();
|
||||
m_FreeForwards.pop();
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
|
||||
{
|
||||
/* No longer used */
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* ACTUAL FORWARD API IMPLEMENTATION *
|
||||
*************************************/
|
||||
|
||||
CForward::CForward(ExecType et, const char *name, const ParamType *types, unsigned num_params)
|
||||
: m_numparams(0),
|
||||
m_varargs(0),
|
||||
m_ExecType(et),
|
||||
m_curparam(0),
|
||||
m_errstate(SP_ERROR_NONE)
|
||||
{
|
||||
ke::SafeStrcpy(m_name, sizeof(m_name), name ? name : "");
|
||||
|
||||
for (unsigned i = 0; i < num_params; i++)
|
||||
m_types[i] = types[i];
|
||||
|
||||
if (num_params && types[num_params - 1] == Param_VarArgs) {
|
||||
m_varargs = num_params;
|
||||
m_numparams = num_params - 1;
|
||||
} else {
|
||||
m_varargs = 0;
|
||||
m_numparams = num_params;
|
||||
}
|
||||
}
|
||||
|
||||
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
|
||||
{
|
||||
ParamType _types[SP_MAX_EXEC_PARAMS];
|
||||
@@ -221,7 +254,29 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CForward(et, name, _types, num_params);
|
||||
CForward *pForward = g_Forwards.ForwardMake();
|
||||
pForward->m_curparam = 0;
|
||||
pForward->m_ExecType = et;
|
||||
snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
|
||||
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
pForward->m_types[i] = _types[i];
|
||||
}
|
||||
|
||||
if (num_params && _types[num_params-1] == Param_VarArgs)
|
||||
{
|
||||
pForward->m_varargs = num_params--;
|
||||
} else {
|
||||
pForward->m_varargs = false;
|
||||
}
|
||||
|
||||
pForward->m_numparams = num_params;
|
||||
pForward->m_errstate = SP_ERROR_NONE;
|
||||
|
||||
pForward->m_functions.clear();
|
||||
|
||||
return pForward;
|
||||
}
|
||||
|
||||
int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
@@ -233,45 +288,58 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
return err;
|
||||
}
|
||||
|
||||
FuncIter iter = m_functions.begin();
|
||||
IPluginFunction *func;
|
||||
cell_t cur_result = 0;
|
||||
cell_t high_result = 0;
|
||||
cell_t low_result = 0;
|
||||
int err;
|
||||
unsigned int success=0;
|
||||
unsigned int failed=0, success=0;
|
||||
unsigned int num_params = m_curparam;
|
||||
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
FwdParamInfo *param;
|
||||
ParamType type;
|
||||
|
||||
/* Save local, reset */
|
||||
memcpy(temp_info, m_params, sizeof(m_params));
|
||||
m_curparam = 0;
|
||||
|
||||
for (FuncIter iter(m_functions); !iter.done(); iter.next())
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||
{
|
||||
IPluginFunction *func = (*iter);
|
||||
|
||||
if (filter)
|
||||
filter->Preprocess(func, temp_info);
|
||||
|
||||
if (func->GetParentRuntime()->IsPaused())
|
||||
continue;
|
||||
func = (*iter);
|
||||
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
int err = SP_ERROR_PARAM;
|
||||
FwdParamInfo *param = &temp_info[i];
|
||||
param = &temp_info[i];
|
||||
|
||||
ParamType type;
|
||||
if (i >= m_numparams || m_types[i] == Param_Any)
|
||||
{
|
||||
type = param->pushedas;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = m_types[i];
|
||||
}
|
||||
|
||||
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
err = _ExecutePushRef(func, type, param);
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
if (type == Param_String)
|
||||
{
|
||||
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
|
||||
}
|
||||
else if (type == Param_Float || type == Param_Cell)
|
||||
{
|
||||
err = func->PushCellByRef(¶m->val);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -291,7 +359,11 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
}
|
||||
|
||||
/* Call the function and deal with the return value. */
|
||||
if ((err=func->Execute(&cur_result)) == SP_ERROR_NONE)
|
||||
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
||||
{
|
||||
failed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
success++;
|
||||
switch (m_ExecType)
|
||||
@@ -370,58 +442,6 @@ done:
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::_ExecutePushRef(IPluginFunction *func, ParamType type, FwdParamInfo *param)
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
int err;
|
||||
IPluginRuntime *runtime = func->GetParentRuntime();
|
||||
switch (type)
|
||||
{
|
||||
case Param_String:
|
||||
// Normal string was pushed.
|
||||
if (!param->isnull)
|
||||
return func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
|
||||
|
||||
// If NULL_STRING was pushed, push the reference to the pubvar of the callee instead.
|
||||
uint32_t null_string_idx;
|
||||
err = runtime->FindPubvarByName("NULL_STRING", &null_string_idx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cell_t null_string;
|
||||
err = runtime->GetPubvarAddrs(null_string_idx, &null_string, nullptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return func->PushCell(null_string);
|
||||
|
||||
case Param_Float:
|
||||
case Param_Cell:
|
||||
return func->PushCellByRef(¶m->val);
|
||||
|
||||
default:
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
// No NULL_VECTOR was pushed.
|
||||
if (type != Param_Array || !param->isnull)
|
||||
return func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
|
||||
// If NULL_VECTOR was pushed, push the reference to the pubvar of the callee instead.
|
||||
uint32_t null_vector_idx;
|
||||
err = runtime->FindPubvarByName("NULL_VECTOR", &null_vector_idx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cell_t null_vector;
|
||||
err = runtime->GetPubvarAddrs(null_vector_idx, &null_vector, nullptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return func->PushCell(null_vector);
|
||||
}
|
||||
}
|
||||
|
||||
int CForward::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
@@ -440,7 +460,6 @@ int CForward::PushCell(cell_t cell)
|
||||
m_params[m_curparam].pushedas = Param_Cell;
|
||||
}
|
||||
|
||||
m_params[m_curparam].isnull = false;
|
||||
m_params[m_curparam++].val = cell;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
@@ -464,7 +483,6 @@ int CForward::PushFloat(float number)
|
||||
m_params[m_curparam].pushedas = Param_Float;
|
||||
}
|
||||
|
||||
m_params[m_curparam].isnull = false;
|
||||
m_params[m_curparam++].val = *(cell_t *)&number;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
@@ -523,22 +541,14 @@ void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||
m_params[m_curparam].byref.cells = cells;
|
||||
m_params[m_curparam].byref.flags = flags;
|
||||
m_params[m_curparam].byref.orig_addr = inarray;
|
||||
m_params[m_curparam].isnull = false;
|
||||
}
|
||||
|
||||
int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||
{
|
||||
/* Push a reference to the NULL_VECTOR pubvar if NULL was passed. */
|
||||
/* We don't allow this here */
|
||||
if (!inarray)
|
||||
{
|
||||
/* Make sure this was intentional. */
|
||||
if (cells == 3)
|
||||
{
|
||||
return PushNullVector();
|
||||
} else {
|
||||
/* We don't allow this here */
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
|
||||
if (m_curparam < m_numparams)
|
||||
@@ -570,17 +580,10 @@ void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags
|
||||
m_params[m_curparam].byref.flags = cp_flags;
|
||||
m_params[m_curparam].byref.orig_addr = inarray;
|
||||
m_params[m_curparam].byref.sz_flags = sz_flags;
|
||||
m_params[m_curparam].isnull = false;
|
||||
}
|
||||
|
||||
int CForward::PushString(const char *string)
|
||||
{
|
||||
/* Push a reference to the NULL_STRING pubvar if NULL was passed. */
|
||||
if (!string)
|
||||
{
|
||||
return PushNullString();
|
||||
}
|
||||
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
@@ -627,52 +630,6 @@ int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_fla
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushNullString()
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
} else if (m_types[m_curparam] != Param_String) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].isnull = true;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushNullVector()
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
} else if (m_types[m_curparam] != Param_Array) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].isnull = true;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::Cancel()
|
||||
{
|
||||
if (!m_curparam)
|
||||
@@ -710,69 +667,74 @@ bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
|
||||
|
||||
bool CForward::RemoveFunction(IPluginFunction *func)
|
||||
{
|
||||
ReentrantList<IPluginFunction *> *lst;
|
||||
if (func->IsRunnable())
|
||||
lst = &m_functions;
|
||||
else
|
||||
lst = &m_paused;
|
||||
|
||||
bool found = false;
|
||||
for (FuncIter iter(lst); !iter.done(); iter.next()) {
|
||||
if (*iter == func) {
|
||||
iter.remove();
|
||||
FuncIter iter;
|
||||
List<IPluginFunction *> *lst;
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
lst = &m_functions;
|
||||
} else {
|
||||
lst = &m_paused;
|
||||
}
|
||||
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||
{
|
||||
if ((*iter) == func)
|
||||
{
|
||||
found = true;
|
||||
lst->erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel a call, if any */
|
||||
if (found || m_curparam)
|
||||
{
|
||||
func->Cancel();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
|
||||
{
|
||||
FuncIter iter;
|
||||
IPluginFunction *func;
|
||||
unsigned int removed = 0;
|
||||
for (FuncIter iter(m_functions); !iter.done(); iter.next()) {
|
||||
IPluginFunction *func = *iter;
|
||||
if (func->GetParentContext() == plugin->GetBaseContext()) {
|
||||
iter.remove();
|
||||
IPluginContext *pContext = plugin->GetBaseContext();
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end();)
|
||||
{
|
||||
func = (*iter);
|
||||
if (func->GetParentContext() == pContext)
|
||||
{
|
||||
iter = m_functions.erase(iter);
|
||||
removed++;
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool CForward::AddFunction(IPluginFunction *func)
|
||||
{
|
||||
if (m_curparam)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
m_functions.push_back(func);
|
||||
else
|
||||
} else {
|
||||
m_paused.push_back(func);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CForward::IsFunctionRegistered(IPluginFunction *func)
|
||||
{
|
||||
ReentrantList<IPluginFunction *> *lst;
|
||||
if (func->IsRunnable())
|
||||
lst = &m_functions;
|
||||
else
|
||||
lst = &m_paused;
|
||||
|
||||
for (FuncIter iter(lst); !iter.done(); iter.next()) {
|
||||
if ((*iter) == func)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *CForward::GetForwardName()
|
||||
{
|
||||
return m_name;
|
||||
@@ -1,44 +1,66 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet :
|
||||
// =============================================================================
|
||||
// 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>.
|
||||
/**
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
|
||||
#include <IForwardSys.h>
|
||||
#include <IPluginSys.h>
|
||||
#include "common_logic.h"
|
||||
#include "ISourceMod.h"
|
||||
#include "ReentrantList.h"
|
||||
#include "sm_globals.h"
|
||||
#include <sh_list.h>
|
||||
#include <sh_stack.h>
|
||||
#include "sourcemod.h"
|
||||
|
||||
typedef ReentrantList<IPluginFunction *>::iterator FuncIter;
|
||||
using namespace SourceHook;
|
||||
|
||||
typedef List<IPluginFunction *>::iterator FuncIter;
|
||||
|
||||
/* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
|
||||
#define FORWARDS_NAME_MAX 64
|
||||
|
||||
struct ByrefInfo
|
||||
{
|
||||
unsigned int cells;
|
||||
cell_t *orig_addr;
|
||||
int flags;
|
||||
int sz_flags;
|
||||
};
|
||||
|
||||
struct FwdParamInfo
|
||||
{
|
||||
cell_t val;
|
||||
ByrefInfo byref;
|
||||
ParamType pushedas;
|
||||
};
|
||||
|
||||
class CForward : public IChangeableForward
|
||||
{
|
||||
public: //ICallable
|
||||
@@ -67,14 +89,7 @@ public:
|
||||
unsigned int num_params,
|
||||
const ParamType *types,
|
||||
va_list ap);
|
||||
bool IsFunctionRegistered(IPluginFunction *func);
|
||||
private:
|
||||
CForward(ExecType et, const char *name,
|
||||
const ParamType *types, unsigned num_params);
|
||||
|
||||
int PushNullString();
|
||||
int PushNullVector();
|
||||
int _ExecutePushRef(IPluginFunction *func, ParamType type, FwdParamInfo *param);
|
||||
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
|
||||
inline int SetError(int err)
|
||||
@@ -83,8 +98,11 @@ private:
|
||||
return err;
|
||||
}
|
||||
protected:
|
||||
mutable ReentrantList<IPluginFunction *> m_functions;
|
||||
mutable ReentrantList<IPluginFunction *> m_paused;
|
||||
/* :TODO: I want a caching list type here.
|
||||
* Destroying these things and using new/delete for their members feels bad.
|
||||
*/
|
||||
mutable List<IPluginFunction *> m_functions;
|
||||
mutable List<IPluginFunction *> m_paused;
|
||||
|
||||
/* Type and name information */
|
||||
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
|
||||
@@ -105,6 +123,8 @@ class CForwardManager :
|
||||
public SMGlobalClass
|
||||
{
|
||||
friend class CForward;
|
||||
public:
|
||||
~CForwardManager();
|
||||
public: //IForwardManager
|
||||
IForward *CreateForward(const char *name,
|
||||
ExecType et,
|
||||
@@ -124,11 +144,13 @@ public: //IPluginsListener
|
||||
void OnPluginPauseChange(IPlugin *plugin, bool paused);
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
protected:
|
||||
CForward *ForwardMake();
|
||||
void ForwardFree(CForward *fwd);
|
||||
private:
|
||||
ReentrantList<CForward *> m_managed;
|
||||
ReentrantList<CForward *> m_unmanaged;
|
||||
|
||||
typedef ReentrantList<CForward *>::iterator ForwardIter;
|
||||
CStack<CForward *> m_FreeForwards;
|
||||
List<CForward *> m_managed;
|
||||
List<CForward *> m_unmanaged;
|
||||
};
|
||||
|
||||
extern CForwardManager g_Forwards;
|
||||
@@ -32,20 +32,26 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "GameConfigs.h"
|
||||
//#include "sm_stringutil.h"
|
||||
//#include "sourcemod.h"
|
||||
//#include "sourcemm_api.h"
|
||||
//#include "HalfLife2.h"
|
||||
//#include "Logger.h"
|
||||
//#include "ShareSys.h"
|
||||
//#include "MemoryUtils.h"
|
||||
//#include "LibrarySys.h"
|
||||
//#include "HandleSys.h"
|
||||
//#include "sm_crc32.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "Logger.h"
|
||||
#include "ShareSys.h"
|
||||
#include "MemoryUtils.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "sm_crc32.h"
|
||||
|
||||
//#if defined PLATFORM_LINUX
|
||||
//#include <dlfcn.h>
|
||||
//#endif
|
||||
#if defined PLATFORM_LINUX
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
GameConfigManager g_GameConfigs;
|
||||
IGameConfig *g_pGameConf = NULL;
|
||||
static char g_Game[256];
|
||||
static char g_GameDesc[256] = {'!', '\0'};
|
||||
static char g_GameName[256] = {'$', '\0'};
|
||||
|
||||
#define PSTATE_NONE 0
|
||||
#define PSTATE_GAMES 1
|
||||
@@ -60,42 +66,70 @@
|
||||
#define PSTATE_GAMEDEFS_CRC_BINARY 10
|
||||
#define PSTATE_GAMEDEFS_CUSTOM 11
|
||||
|
||||
#define WIN 0
|
||||
#define LIN 1
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
#define PLATFORM_NAME "windows"
|
||||
#define PLATFORM_SERVER_BINARY "server.dll"
|
||||
#elif defined PLATFORM_LINUX
|
||||
#define PLATFORM_NAME "linux"
|
||||
#define PLATFORM_SERVER_BINARY "server_i486.so"
|
||||
#elif defined PLATFORM_APPLE
|
||||
#define PLATFORM_NAME "undef"
|
||||
#define PLATFORM_SERVER_BINARY "undef.dylib"
|
||||
#endif
|
||||
|
||||
Offset *tempOffset;
|
||||
Sig *tempSig;
|
||||
|
||||
struct TempSigInfo
|
||||
{
|
||||
void Reset()
|
||||
{
|
||||
library[0] = '\0';
|
||||
sig[0] = '\0';
|
||||
}
|
||||
char sig[512];
|
||||
char library[64];
|
||||
} s_TempSig;
|
||||
unsigned int s_ServerBinCRC;
|
||||
bool s_ServerBinCRC_Ok = false;
|
||||
|
||||
bool /*CGameConfig::*/DoesGameMatch(const char *value)
|
||||
static bool DoesGameMatch(const char *value)
|
||||
{
|
||||
if (strcmp(value, /*m_gdcG*/game) == 0)
|
||||
if (strcmp(value, g_Game) == 0 ||
|
||||
strcmp(value, g_GameDesc) == 0 ||
|
||||
strcmp(value, g_GameName) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool /*CGameConfig::*/DoesEngineMatch(const char *value)
|
||||
static bool DoesEngineMatch(const char *value)
|
||||
{
|
||||
if (strcmp(value, /*m_gdcE*/engine) == 0)
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (strcmp(value, "original") == 0)
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
if (strcmp(value, "darkmessiah") == 0)
|
||||
#elif SOURCE_ENGINE == SE_ORANGEBOX
|
||||
if (strcmp(value, "orangebox") == 0)
|
||||
#elif SOURCE_ENGINE == SE_ORANGEBOXVALVE
|
||||
if (strcmp(value, "orangebox_valve") == 0)
|
||||
#elif SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
if (strcmp(value, "left4dead") == 0)
|
||||
#else
|
||||
#error "Unknown engine type"
|
||||
#endif
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CGameConfig::CGameConfig()//const char *file)//, const char *game, const char *engine)
|
||||
CGameConfig::CGameConfig(const char *file)
|
||||
{
|
||||
// strncopy(m_File, file, sizeof(m_File));
|
||||
// strncopy(m_gdcGame, game, sizeof(m_gdcGame));
|
||||
// strncopy(m_gdcEngine, engine, sizeof(m_gdcEngine));
|
||||
//m_pStrings = new BaseStringTable(512);
|
||||
strncopy(m_File, file, sizeof(m_File));
|
||||
m_pOffsets = sm_trie_create();
|
||||
m_pProps = sm_trie_create();
|
||||
m_pKeys = sm_trie_create();
|
||||
m_pSigs = sm_trie_create();
|
||||
m_pStrings = new BaseStringTable(512);
|
||||
m_RefCount = 0;
|
||||
|
||||
m_CustomLevel = 0;
|
||||
@@ -104,7 +138,11 @@ CGameConfig::CGameConfig()//const char *file)//, const char *game, const char *e
|
||||
|
||||
CGameConfig::~CGameConfig()
|
||||
{
|
||||
// delete m_pStrings;
|
||||
sm_trie_destroy(m_pOffsets);
|
||||
sm_trie_destroy(m_pProps);
|
||||
sm_trie_destroy(m_pKeys);
|
||||
sm_trie_destroy(m_pSigs);
|
||||
delete m_pStrings;
|
||||
}
|
||||
|
||||
SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
@@ -167,14 +205,11 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
}
|
||||
else if (strcmp(name, "CRC") == 0)
|
||||
{
|
||||
#if 0
|
||||
m_ParseState = PSTATE_GAMEDEFS_CRC;
|
||||
bShouldBeReadingDefault = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
ITextListener_SMC **pListen = g_GameConfigs.m_customHandlers.retrieve(name);
|
||||
|
||||
if (pListen != NULL)
|
||||
@@ -185,7 +220,8 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
m_CustomHandler->ReadSMC_ParseStart();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_IgnoreLevel++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -193,19 +229,17 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
{
|
||||
m_Prop[0] = '\0';
|
||||
m_Class[0] = '\0';
|
||||
tempOffset = new Offset();
|
||||
tempOffset->setName(name);
|
||||
strncopy(m_offset, name, sizeof(m_offset));
|
||||
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
|
||||
break;
|
||||
}
|
||||
case PSTATE_GAMEDEFS_SIGNATURES:
|
||||
{
|
||||
tempSig = new Sig();
|
||||
tempSig->setName(name);
|
||||
strncopy(m_offset, name, sizeof(m_offset));
|
||||
s_TempSig.Reset();
|
||||
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
case PSTATE_GAMEDEFS_CRC:
|
||||
{
|
||||
char error[255];
|
||||
@@ -255,7 +289,6 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
return m_CustomHandler->ReadSMC_NewSection(states, name);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* No sub-sections allowed:
|
||||
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
||||
case PSTATE_GAMEDEFS_KEYS:
|
||||
@@ -288,17 +321,13 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
||||
strncopy(m_Class, value, sizeof(m_Class));
|
||||
} else if (strcmp(key, "prop") == 0) {
|
||||
strncopy(m_Prop, value, sizeof(m_Prop));
|
||||
} else /*if (strcmp(key, PLATFORM_NAME) == 0) */ {
|
||||
} else if (strcmp(key, PLATFORM_NAME) == 0) {
|
||||
int val = atoi(value);
|
||||
// sm_trie_replace(m_pOffsets, m_offset, (void *)val);
|
||||
if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
|
||||
else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
|
||||
sm_trie_replace(m_pOffsets, m_offset, (void *)val);
|
||||
}
|
||||
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
|
||||
m_Keys[key] = value;
|
||||
// printf("Inserting %s - %s\n", key, value);
|
||||
// int id = m_pStrings->AddString(value);
|
||||
// sm_trie_replace(m_pKeys, key, (void *)id);
|
||||
int id = m_pStrings->AddString(value);
|
||||
sm_trie_replace(m_pKeys, key, (void *)id);
|
||||
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
|
||||
if (strcmp(key, "game") == 0)
|
||||
{
|
||||
@@ -325,9 +354,12 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
||||
}
|
||||
}
|
||||
} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
|
||||
if (strcmp(key, "windows") == 0) tempSig->setWin(value);
|
||||
else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
|
||||
else if (strcmp(key, "library") == 0) tempSig->setLib(value);
|
||||
if (strcmp(key, PLATFORM_NAME) == 0)
|
||||
{
|
||||
strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
|
||||
} else if (strcmp(key, "library") == 0) {
|
||||
strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
|
||||
}
|
||||
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
|
||||
if (strcmp(key, PLATFORM_NAME) == 0
|
||||
&& s_ServerBinCRC_Ok
|
||||
@@ -388,8 +420,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
}
|
||||
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
||||
{
|
||||
m_Offsets.push_back(*tempOffset);
|
||||
#if 0
|
||||
/* Parse the offset... */
|
||||
if (m_Class[0] != '\0'
|
||||
&& m_Prop[0] != '\0')
|
||||
@@ -413,7 +443,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
|
||||
break;
|
||||
}
|
||||
@@ -442,8 +471,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
}
|
||||
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
|
||||
{
|
||||
m_Sigs.push_back(*tempSig);
|
||||
#if 0
|
||||
if (s_TempSig.library[0] == '\0')
|
||||
{
|
||||
/* assume server */
|
||||
@@ -538,7 +565,6 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
skip_find:
|
||||
#endif
|
||||
sm_trie_replace(m_pSigs, m_offset, final_addr);
|
||||
#endif
|
||||
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
|
||||
|
||||
break;
|
||||
@@ -663,7 +689,7 @@ public:
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
public:
|
||||
list<char*> *fileList;
|
||||
List<String> *fileList;
|
||||
unsigned int state;
|
||||
unsigned int ignoreLevel;
|
||||
char cur_file[PLATFORM_MAX_PATH];
|
||||
@@ -678,21 +704,26 @@ static MasterReader master_reader;
|
||||
bool CGameConfig::Reparse(char *error, size_t maxlength)
|
||||
{
|
||||
/* Reset cached data */
|
||||
// m_pStrings->Reset();
|
||||
m_Offsets.clear();
|
||||
m_Sigs.clear();
|
||||
|
||||
m_pStrings->Reset();
|
||||
sm_trie_clear(m_pOffsets);
|
||||
sm_trie_clear(m_pProps);
|
||||
sm_trie_clear(m_pKeys);
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
|
||||
/* See if we can use the extended gamedata format. */
|
||||
//TODO pass in path to gamedata somehow
|
||||
// g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/master.games.txt", m_File);
|
||||
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/master.games.txt", m_File);
|
||||
if (!g_LibSys.PathExists(path))
|
||||
{
|
||||
/* Nope, use the old mechanism. */
|
||||
UTIL_Format(path, sizeof(path), "%s.txt", m_File);
|
||||
return EnterFile(path, error, maxlength);
|
||||
}
|
||||
|
||||
/* Otherwise, it's time to parse the master. */
|
||||
SMCError err;
|
||||
SMCStates state = {0, 0};
|
||||
list<char*> fileList;
|
||||
List<String> fileList;
|
||||
master_reader.fileList = &fileList;
|
||||
|
||||
err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
|
||||
@@ -700,26 +731,64 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
|
||||
{
|
||||
const char *msg = textparsers->GetSMCErrorString(err);
|
||||
|
||||
printf("[SM] Error parsing master gameconf file \"%s\":", path);
|
||||
printf("[SM] Error %d on line %d, col %d: %s",
|
||||
g_Logger.LogError("[SM] Error parsing master gameconf file \"%s\":", path);
|
||||
g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
|
||||
err,
|
||||
state.line,
|
||||
state.col,
|
||||
msg ? msg : "Unknown error");
|
||||
exit(PARSE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Go through each file we found and parse it. */
|
||||
list<char*>::iterator iter;
|
||||
List<String>::iterator iter;
|
||||
for (iter = fileList.begin(); iter != fileList.end(); iter++)
|
||||
{
|
||||
UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
|
||||
UTIL_Format(path, sizeof(path), "%s/%s", m_File, (*iter).c_str());
|
||||
if (!EnterFile(path, error, maxlength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the contents of the 'custom' directory */
|
||||
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/custom", m_File);
|
||||
IDirectory *customDir = g_LibSys.OpenDirectory(path);
|
||||
|
||||
if (!customDir)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
while (customDir->MoreFiles())
|
||||
{
|
||||
if (!customDir->IsEntryFile())
|
||||
{
|
||||
customDir->NextEntry();
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *curFile = customDir->GetEntryName();
|
||||
|
||||
/* Only allow .txt files */
|
||||
int len = strlen(curFile);
|
||||
if (len > 4 && strcmp(&curFile[len-4], ".txt") != 0)
|
||||
{
|
||||
customDir->NextEntry();
|
||||
continue;
|
||||
}
|
||||
|
||||
UTIL_Format(path, sizeof(path), "%s/custom/%s", m_File, curFile);
|
||||
if (!EnterFile(path, error, maxlength))
|
||||
{
|
||||
g_LibSys.CloseDirectory(customDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
customDir->NextEntry();
|
||||
}
|
||||
|
||||
g_LibSys.CloseDirectory(customDir);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -728,20 +797,22 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
|
||||
SMCError err;
|
||||
SMCStates state = {0, 0};
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM, m_CurFile, sizeof(m_CurFile), "gamedata/%s", file);
|
||||
|
||||
/* Initialize parse states */
|
||||
m_IgnoreLevel = 0;
|
||||
bShouldBeReadingDefault = true;
|
||||
m_ParseState = PSTATE_NONE;
|
||||
|
||||
if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
|
||||
if ((err=textparsers->ParseSMCFile(m_CurFile, this, &state, error, maxlength))
|
||||
!= SMCError_Okay)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
msg = textparsers->GetSMCErrorString(err);
|
||||
|
||||
printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
|
||||
printf("[SM] Error %d on line %d, col %d: %s\n",
|
||||
g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile);
|
||||
g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
|
||||
err,
|
||||
state.line,
|
||||
state.col,
|
||||
@@ -755,13 +826,12 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
|
||||
m_CustomLevel = 0;
|
||||
}
|
||||
|
||||
exit(PARSE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool CGameConfig::GetOffset(const char *key, int *value)
|
||||
{
|
||||
void *obj;
|
||||
@@ -813,16 +883,149 @@ unsigned int CGameConfig::DecRefCount()
|
||||
m_RefCount--;
|
||||
return m_RefCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *CGameConfig::GetKeyValue(const char *key)
|
||||
GameConfigManager::GameConfigManager()
|
||||
{
|
||||
map<const char*,const char*,cmp_str>::iterator it = m_Keys.find(key);
|
||||
if (it == m_Keys.end()) return NULL;
|
||||
|
||||
return it->second;
|
||||
m_pLookup = sm_trie_create();
|
||||
}
|
||||
|
||||
list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
|
||||
list<Sig> CGameConfig::GetSigs() { return m_Sigs; }
|
||||
GameConfigManager::~GameConfigManager()
|
||||
{
|
||||
sm_trie_destroy(m_pLookup);
|
||||
}
|
||||
|
||||
void GameConfigManager::OnSourceModStartup(bool late)
|
||||
{
|
||||
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
|
||||
|
||||
strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
|
||||
strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1);
|
||||
|
||||
KeyValues *pGameInfo = new KeyValues("GameInfo");
|
||||
if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
|
||||
{
|
||||
const char *str;
|
||||
if ((str = pGameInfo->GetString("game", NULL)) != NULL)
|
||||
{
|
||||
strncopy(g_GameName + 1, str, sizeof(g_GameName) - 1);
|
||||
}
|
||||
}
|
||||
pGameInfo->deleteThis();
|
||||
}
|
||||
|
||||
void GameConfigManager::OnSourceModAllInitialized()
|
||||
{
|
||||
/* NOW initialize the game file */
|
||||
CGameConfig *pGameConf = (CGameConfig *)g_pGameConf;
|
||||
|
||||
char error[255];
|
||||
if (!pGameConf->Reparse(error, sizeof(error)))
|
||||
{
|
||||
/* :TODO: log */
|
||||
}
|
||||
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
void GameConfigManager::OnSourceModAllShutdown()
|
||||
{
|
||||
CloseGameConfigFile(g_pGameConf);
|
||||
}
|
||||
|
||||
bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
|
||||
{
|
||||
#if 0
|
||||
/* A crash was detected during last load - We block the gamedata loading so it hopefully won't happen again */
|
||||
if (g_blockGameDataLoad)
|
||||
{
|
||||
UTIL_Format(error, maxlength, "GameData loaded blocked due to detected crash");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
CGameConfig *pConfig;
|
||||
|
||||
if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
|
||||
{
|
||||
pConfig->IncRefCount();
|
||||
*_pConfig = pConfig;
|
||||
return true;
|
||||
}
|
||||
|
||||
pConfig = new CGameConfig(file);
|
||||
|
||||
/* :HACKHACK: Don't parse the main config file */
|
||||
bool retval = true;
|
||||
if (_pConfig != &g_pGameConf)
|
||||
{
|
||||
retval = pConfig->Reparse(error, maxlength);
|
||||
}
|
||||
|
||||
m_cfgs.push_back(pConfig);
|
||||
sm_trie_insert(m_pLookup, file, pConfig);
|
||||
|
||||
pConfig->IncRefCount();
|
||||
|
||||
*_pConfig = pConfig;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg)
|
||||
{
|
||||
CGameConfig *pConfig = (CGameConfig *)cfg;
|
||||
|
||||
if (pConfig->DecRefCount() == 0)
|
||||
{
|
||||
sm_trie_delete(m_pLookup, pConfig->m_File);
|
||||
delete pConfig;
|
||||
}
|
||||
}
|
||||
|
||||
extern HandleType_t g_GameConfigsType;
|
||||
|
||||
IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err)
|
||||
{
|
||||
HandleSecurity sec(ident, g_pCoreIdent);
|
||||
IGameConfig *conf = NULL;
|
||||
HandleError _err = g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&conf);
|
||||
|
||||
if (err)
|
||||
{
|
||||
*err = _err;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
void GameConfigManager::AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener)
|
||||
{
|
||||
m_customHandlers.insert(sectionname, listener);
|
||||
}
|
||||
|
||||
void GameConfigManager::RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener)
|
||||
{
|
||||
ITextListener_SMC **pListener = m_customHandlers.retrieve(sectionname);
|
||||
|
||||
if (pListener == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (*pListener != listener)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_customHandlers.remove(sectionname);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void GameConfigManager::AcquireLock()
|
||||
{
|
||||
}
|
||||
|
||||
void GameConfigManager::ReleaseLock()
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet:
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -32,32 +32,31 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
|
||||
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include <ITextParsers.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include <unordered_set>
|
||||
#include <sh_list.h>
|
||||
#include "sm_trie.h"
|
||||
#include "sm_globals.h"
|
||||
#include "sm_memtable.h"
|
||||
#include "sm_trie_tpl.h"
|
||||
#include "ThreadSupport.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
|
||||
class SendProp;
|
||||
|
||||
class CGameConfig :
|
||||
public ITextListener_SMC,
|
||||
public IGameConfig,
|
||||
public ke::Refcounted<CGameConfig>
|
||||
public IGameConfig
|
||||
{
|
||||
friend class GameConfigManager;
|
||||
public:
|
||||
CGameConfig(const char *file, const char *engine = NULL);
|
||||
CGameConfig(const char *file);
|
||||
~CGameConfig();
|
||||
public:
|
||||
bool Reparse(char *error, size_t maxlength);
|
||||
bool EnterFile(const char *file, char *error, size_t maxlength);
|
||||
void SetBaseEngine(const char *engine);
|
||||
void SetParseEngine(const char *engine);
|
||||
public: //ITextListener_SMC
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
@@ -67,90 +66,34 @@ public: //IGameConfig
|
||||
bool GetOffset(const char *key, int *value);
|
||||
SendProp *GetSendProp(const char *key);
|
||||
bool GetMemSig(const char *key, void **addr);
|
||||
bool GetAddress(const char *key, void **addr);
|
||||
public: //NameHashSet
|
||||
static inline bool matches(const char *key, const CGameConfig *value)
|
||||
{
|
||||
return strcmp(key, value->m_File) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
public:
|
||||
void IncRefCount();
|
||||
unsigned int DecRefCount();
|
||||
private:
|
||||
BaseStringTable *m_pStrings;
|
||||
char m_File[PLATFORM_MAX_PATH];
|
||||
char m_CurFile[PLATFORM_MAX_PATH];
|
||||
StringHashMap<int> m_Offsets;
|
||||
StringHashMap<SendProp *> m_Props;
|
||||
StringHashMap<std::string> m_Keys;
|
||||
StringHashMap<void *> m_Sigs;
|
||||
Trie *m_pOffsets;
|
||||
Trie *m_pProps;
|
||||
Trie *m_pKeys;
|
||||
Trie *m_pSigs;
|
||||
unsigned int m_RefCount;
|
||||
/* Parse states */
|
||||
int m_ParseState;
|
||||
unsigned int m_IgnoreLevel;
|
||||
std::string m_Class;
|
||||
std::string m_Prop;
|
||||
std::string m_offset;
|
||||
std::string m_Game;
|
||||
std::string m_Key;
|
||||
unsigned int bCurrentBinCRC;
|
||||
bool bCurrentBinCRC_Ok = false;
|
||||
char m_Class[64];
|
||||
char m_Prop[64];
|
||||
char m_offset[64];
|
||||
char m_Game[256];
|
||||
bool bShouldBeReadingDefault;
|
||||
bool had_game;
|
||||
bool matched_game;
|
||||
bool had_engine;
|
||||
bool matched_engine;
|
||||
bool matched_platform;
|
||||
|
||||
/* Custom Sections */
|
||||
unsigned int m_CustomLevel;
|
||||
ITextListener_SMC *m_CustomHandler;
|
||||
|
||||
/* Support for reading Addresses */
|
||||
struct AddressConf
|
||||
{
|
||||
std::string signatureName;
|
||||
int readCount;
|
||||
int read[8];
|
||||
bool lastIsOffset;
|
||||
|
||||
AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset);
|
||||
|
||||
AddressConf() {}
|
||||
};
|
||||
|
||||
std::string m_Address;
|
||||
std::string m_AddressSignature;
|
||||
int m_AddressReadCount;
|
||||
int m_AddressRead[8];
|
||||
bool m_AddressLastIsOffset;
|
||||
StringHashMap<AddressConf> m_Addresses;
|
||||
const char *m_pEngine;
|
||||
const char *m_pBaseEngine;
|
||||
time_t m_ModTime;
|
||||
};
|
||||
|
||||
struct GameBinaryInfo
|
||||
{
|
||||
void *m_pAddr = nullptr;
|
||||
uint32_t m_crc = 0;
|
||||
bool m_crcOK = false;
|
||||
};
|
||||
|
||||
class GameBinPathManager
|
||||
{
|
||||
public:
|
||||
GameBinPathManager() {}
|
||||
~GameBinPathManager() {}
|
||||
public:
|
||||
void Init();
|
||||
|
||||
inline const std::vector<std::string>& Paths() const
|
||||
{
|
||||
return m_ordered;
|
||||
}
|
||||
private:
|
||||
std::unordered_set<std::string> m_lookup;
|
||||
std::vector<std::string> m_ordered;
|
||||
};
|
||||
|
||||
class GameConfigManager :
|
||||
@@ -174,17 +117,11 @@ public: //SMGlobalClass
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModAllShutdown();
|
||||
public:
|
||||
bool TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest);
|
||||
void RemoveCachedConfig(CGameConfig *config);
|
||||
private:
|
||||
void CacheGameBinaryInfo(const char* pszName);
|
||||
private:
|
||||
NameHashSet<CGameConfig *> m_Lookup;
|
||||
StringHashMap<GameBinaryInfo> m_gameBinInfos;
|
||||
List<CGameConfig *> m_cfgs;
|
||||
Trie *m_pLookup;
|
||||
public:
|
||||
StringHashMap<ITextListener_SMC *> m_customHandlers;
|
||||
GameBinPathManager m_gameBinPathManager;
|
||||
KTrie<ITextListener_SMC *> m_customHandlers;
|
||||
};
|
||||
|
||||
extern GameConfigManager g_GameConfigs;
|
||||
@@ -1,171 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet :
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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>.
|
||||
#include "GameHooks.h"
|
||||
#include "sourcemod.h"
|
||||
#include "ConVarManager.h"
|
||||
#include "command_args.h"
|
||||
#include "provider.h"
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
|
||||
#else
|
||||
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
#endif
|
||||
|
||||
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int);
|
||||
|
||||
GameHooks::GameHooks()
|
||||
: client_cvar_query_mode_(ClientCvarQueryMode::Unavailable),
|
||||
last_command_client_(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void GameHooks::Start()
|
||||
{
|
||||
// Hook ICvar::CallGlobalChangeCallbacks.
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
hooks_ += SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
|
||||
#else
|
||||
hooks_ += SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
|
||||
#endif
|
||||
|
||||
// Episode 2 has this function by default, but the older versions do not.
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (g_SMAPI->GetGameDLLVersion() >= 6) {
|
||||
hooks_ += SH_ADD_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &GameHooks::OnQueryCvarValueFinished), false);
|
||||
client_cvar_query_mode_ = ClientCvarQueryMode::DLL;
|
||||
}
|
||||
#endif
|
||||
|
||||
hooks_ += SH_ADD_HOOK(IServerGameClients, SetCommandClient, serverClients, SH_MEMBER(this, &GameHooks::SetCommandClient), false);
|
||||
}
|
||||
|
||||
void GameHooks::OnVSPReceived()
|
||||
{
|
||||
if (client_cvar_query_mode_ != ClientCvarQueryMode::Unavailable)
|
||||
return;
|
||||
|
||||
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
|
||||
return;
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
hooks_ += SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &GameHooks::OnQueryCvarValueFinished), false);
|
||||
client_cvar_query_mode_ = ClientCvarQueryMode::VSP;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GameHooks::Shutdown()
|
||||
{
|
||||
for (size_t i = 0; i < hooks_.size(); i++)
|
||||
SH_REMOVE_HOOK_ID(hooks_[i]);
|
||||
hooks_.clear();
|
||||
|
||||
client_cvar_query_mode_ = ClientCvarQueryMode::Unavailable;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
|
||||
#else
|
||||
void GameHooks::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
||||
#endif
|
||||
{
|
||||
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||
float flOldValue = atof(oldValue);
|
||||
#endif
|
||||
g_ConVarManager.OnConVarChanged(pConVar, oldValue, flOldValue);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
|
||||
const char *cvarName, const char *cvarValue){
|
||||
int client = IndexOfEdict(pPlayer);
|
||||
|
||||
# if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
|
||||
return;
|
||||
# endif
|
||||
g_ConVarManager.OnClientQueryFinished(cookie, client, result, cvarName, cvarValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
ke::RefPtr<CommandHook>
|
||||
GameHooks::AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
|
||||
{
|
||||
return new CommandHook(cmd, callback, false);
|
||||
}
|
||||
|
||||
ke::RefPtr<CommandHook>
|
||||
GameHooks::AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback)
|
||||
{
|
||||
return new CommandHook(cmd, callback, true);
|
||||
}
|
||||
|
||||
void GameHooks::SetCommandClient(int client)
|
||||
{
|
||||
last_command_client_ = client + 1;
|
||||
}
|
||||
|
||||
CommandHook::CommandHook(ConCommand *cmd, const Callback &callback, bool post)
|
||||
: hook_id_(0),
|
||||
callback_(callback)
|
||||
{
|
||||
hook_id_ = SH_ADD_HOOK(ConCommand, Dispatch, cmd, SH_MEMBER(this, &CommandHook::Dispatch), post);
|
||||
}
|
||||
|
||||
CommandHook::~CommandHook()
|
||||
{
|
||||
if (hook_id_)
|
||||
SH_REMOVE_HOOK_ID(hook_id_);
|
||||
}
|
||||
|
||||
void CommandHook::Dispatch(DISPATCH_ARGS)
|
||||
{
|
||||
DISPATCH_PROLOGUE;
|
||||
EngineArgs args(command);
|
||||
|
||||
AddRef();
|
||||
bool rval = callback_(sCoreProviderImpl.CommandClient(), &args);
|
||||
Release();
|
||||
if (rval)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void CommandHook::Zap()
|
||||
{
|
||||
hook_id_ = 0;
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet :
|
||||
// =============================================================================
|
||||
// SourceMod
|
||||
// Copyright (C) 2004-2015 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_PROVIDER_GAME_HOOKS_H_
|
||||
#define _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_
|
||||
|
||||
// Needed for CEntityIndex, edict_t, etc.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <eiface.h>
|
||||
#include <iserverplugin.h>
|
||||
#include <amtl/am-refcounting.h>
|
||||
#include <amtl/am-vector.h>
|
||||
#include <amtl/am-function.h>
|
||||
|
||||
class ConVar;
|
||||
class CCommand;
|
||||
struct CCommandContext;
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
# define DISPATCH_ARGS const CCommand &command
|
||||
# define DISPATCH_PROLOGUE
|
||||
#else
|
||||
# define DISPATCH_ARGS
|
||||
# define DISPATCH_PROLOGUE CCommand command
|
||||
#endif
|
||||
|
||||
namespace SourceMod {
|
||||
|
||||
// Describes the mechanism in which client cvar queries are implemented.
|
||||
enum class ClientCvarQueryMode {
|
||||
Unavailable,
|
||||
DLL,
|
||||
VSP
|
||||
};
|
||||
|
||||
class ICommandArgs;
|
||||
|
||||
class CommandHook : public ke::Refcounted<CommandHook>
|
||||
{
|
||||
public:
|
||||
// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
|
||||
typedef ke::Function<bool(int, const ICommandArgs *)> Callback;
|
||||
|
||||
public:
|
||||
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
|
||||
~CommandHook();
|
||||
void Dispatch(DISPATCH_ARGS);
|
||||
void Zap();
|
||||
|
||||
private:
|
||||
int hook_id_;
|
||||
Callback callback_;
|
||||
};
|
||||
|
||||
class GameHooks
|
||||
{
|
||||
public:
|
||||
GameHooks();
|
||||
|
||||
void Start();
|
||||
void Shutdown();
|
||||
void OnVSPReceived();
|
||||
|
||||
ClientCvarQueryMode GetClientCvarQueryMode() const {
|
||||
return client_cvar_query_mode_;
|
||||
}
|
||||
|
||||
public:
|
||||
ke::RefPtr<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
|
||||
ke::RefPtr<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
|
||||
|
||||
int CommandClient() const {
|
||||
return last_command_client_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Static callback that Valve's ConVar object executes when the convar's value changes.
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
static void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||
#else
|
||||
static void OnConVarChanged(ConVar *pConVar, const char *oldValue);
|
||||
#endif
|
||||
|
||||
// Callback for when StartQueryCvarValue() has finished.
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
|
||||
const char *cvarName, const char *cvarValue);
|
||||
#endif
|
||||
|
||||
void SetCommandClient(int client);
|
||||
|
||||
private:
|
||||
class HookList : public std::vector<int>
|
||||
{
|
||||
public:
|
||||
HookList &operator += (int hook_id) {
|
||||
this->push_back(hook_id);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
HookList hooks_;
|
||||
|
||||
ClientCvarQueryMode client_cvar_query_mode_;
|
||||
int last_command_client_;
|
||||
};
|
||||
|
||||
} // namespace SourceMod
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_PROVIDER_GAME_HOOKS_H_
|
||||
+118
-1077
File diff suppressed because it is too large
Load Diff
+20
-187
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2016 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -35,24 +35,16 @@
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_tinyhash.h>
|
||||
#include <am-utility.h>
|
||||
#include <am-hashset.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_trie.h"
|
||||
#include "sm_globals.h"
|
||||
#include "sm_queue.h"
|
||||
#include <IGameHelpers.h>
|
||||
#include <KeyValues.h>
|
||||
#include <server_class.h>
|
||||
#include <datamap.h>
|
||||
#include <ihandleentity.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#include <string_t.h>
|
||||
|
||||
namespace SourceMod {
|
||||
class ICommandArgs;
|
||||
} // namespace SourceMod
|
||||
class CCommand;
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
@@ -60,95 +52,18 @@ using namespace SourceMod;
|
||||
#define HUD_PRINTTALK 3
|
||||
#define HUD_PRINTCENTER 4
|
||||
|
||||
#if defined _WIN32
|
||||
#define SOURCE_BIN_PREFIX ""
|
||||
#define SOURCE_BIN_SUFFIX ""
|
||||
#define SOURCE_BIN_EXT ".dll"
|
||||
#elif defined __APPLE__
|
||||
#define SOURCE_BIN_PREFIX ""
|
||||
#define SOURCE_BIN_SUFFIX ""
|
||||
#define SOURCE_BIN_EXT ".dylib"
|
||||
#elif defined __linux__
|
||||
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
|
||||
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_LEFT4DEAD2 || SOURCE_ENGINE == SE_NUCLEARDAWN \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI
|
||||
#define SOURCE_BIN_PREFIX "lib"
|
||||
#define SOURCE_BIN_SUFFIX "_srv"
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD || SOURCE_ENGINE == SE_PVKII
|
||||
#define SOURCE_BIN_PREFIX "lib"
|
||||
#define SOURCE_BIN_SUFFIX ""
|
||||
#else
|
||||
#define SOURCE_BIN_PREFIX ""
|
||||
#define SOURCE_BIN_SUFFIX "_i486"
|
||||
#endif
|
||||
#define SOURCE_BIN_EXT ".so"
|
||||
#endif
|
||||
|
||||
#define FORMAT_SOURCE_BIN_NAME(basename) \
|
||||
(SOURCE_BIN_PREFIX basename SOURCE_BIN_SUFFIX SOURCE_BIN_EXT)
|
||||
|
||||
struct DataTableInfo
|
||||
{
|
||||
struct SendPropInfo
|
||||
{
|
||||
static inline bool matches(const char *name, const SendPropInfo &info)
|
||||
{
|
||||
return strcmp(name, info.name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
|
||||
SendPropInfo()
|
||||
: name(), info{nullptr, 0}
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
sm_sendprop_info_t info;
|
||||
};
|
||||
|
||||
static inline bool matches(const char *name, const DataTableInfo *info)
|
||||
{
|
||||
return strcmp(name, info->sc->GetName()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
|
||||
DataTableInfo(ServerClass *sc)
|
||||
: sc(sc)
|
||||
{
|
||||
}
|
||||
|
||||
ServerClass *sc;
|
||||
NameHashSet<SendPropInfo> lookup;
|
||||
KTrie<sm_sendprop_info_t> lookup;
|
||||
};
|
||||
|
||||
struct DataMapCacheInfo
|
||||
struct DataMapTrie
|
||||
{
|
||||
static inline bool matches(const char *name, const DataMapCacheInfo &info)
|
||||
{
|
||||
return strcmp(name, info.name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
|
||||
DataMapCacheInfo()
|
||||
: name(), info{nullptr, 0}
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
sm_datatable_info_t info;
|
||||
DataMapTrie() : trie(NULL) {}
|
||||
Trie *trie;
|
||||
};
|
||||
|
||||
typedef NameHashSet<DataMapCacheInfo> DataMapCache;
|
||||
|
||||
struct DelayedFakeCliCmd
|
||||
{
|
||||
String cmd;
|
||||
@@ -158,7 +73,7 @@ struct DelayedFakeCliCmd
|
||||
|
||||
struct CachedCommandInfo
|
||||
{
|
||||
const ICommandArgs *args;
|
||||
const CCommand *args;
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
char cmd[300];
|
||||
#endif
|
||||
@@ -171,63 +86,26 @@ struct DelayedKickInfo
|
||||
char buffer[384];
|
||||
};
|
||||
|
||||
// copy from game/shared/entitylist_base.h
|
||||
class CEntInfo
|
||||
{
|
||||
public:
|
||||
IHandleEntity *m_pEntity;
|
||||
int m_SerialNumber;
|
||||
CEntInfo *m_pPrev;
|
||||
CEntInfo *m_pNext;
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
string_t m_iName;
|
||||
string_t m_iClassName;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Corresponds to TF2's eFindMapResult in eiface.h
|
||||
// Not yet in other games, but eventually in others on same branch.
|
||||
enum class SMFindMapResult : cell_t {
|
||||
Found,
|
||||
NotFound,
|
||||
FuzzyMatch,
|
||||
NonCanonical,
|
||||
PossiblyAvailable
|
||||
};
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS
|
||||
template< class T, class I = int >
|
||||
class CUtlMemoryGlobalMalloc;
|
||||
class CUtlString;
|
||||
#endif
|
||||
|
||||
class CHalfLife2 :
|
||||
public SMGlobalClass,
|
||||
public IGameHelpers
|
||||
{
|
||||
friend class AutoEnterCommand;
|
||||
public:
|
||||
CHalfLife2();
|
||||
~CHalfLife2();
|
||||
public:
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModAllInitialized_Post();
|
||||
/*void OnSourceModAllShutdown();*/
|
||||
ConfigResult OnSourceModConfigChanged(const char *key, const char *value,
|
||||
ConfigSource source, char *error, size_t maxlength) override;
|
||||
public: //IGameHelpers
|
||||
SendProp *FindInSendTable(const char *classname, const char *offset);
|
||||
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
|
||||
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
||||
ServerClass *FindServerClass(const char *classname);
|
||||
ServerClass *FindEntityServerClass(CBaseEntity *pEntity);
|
||||
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
|
||||
bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
|
||||
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
|
||||
bool TextMsg(int client, int dest, const char *msg);
|
||||
bool HintTextMsg(int client, const char *msg);
|
||||
bool HintTextMsg(cell_t *players, int count, const char *msg);
|
||||
bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show);
|
||||
bool IsLANServer();
|
||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
||||
@@ -237,48 +115,25 @@ public: //IGameHelpers
|
||||
void SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt);
|
||||
const char *GetCurrentMap();
|
||||
void ServerCommand(const char *buffer);
|
||||
CBaseEntity *ReferenceToEntity(cell_t entRef);
|
||||
cell_t EntityToReference(CBaseEntity *pEntity);
|
||||
cell_t IndexToReference(int entIndex);
|
||||
int ReferenceToIndex(cell_t entRef);
|
||||
cell_t ReferenceToBCompatRef(cell_t entRef);
|
||||
CEntInfo *LookupEntity(int entIndex);
|
||||
cell_t EntityToBCompatRef(CBaseEntity *pEntity);
|
||||
void *GetGlobalEntityList();
|
||||
int GetSendPropOffset(SendProp *prop);
|
||||
ICommandLine *GetValveCommandLine();
|
||||
const char *GetEntityClassname(edict_t *pEdict);
|
||||
const char *GetEntityClassname(CBaseEntity *pEntity);
|
||||
bool IsMapValid(const char *map);
|
||||
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
|
||||
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
|
||||
void FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec);
|
||||
#endif
|
||||
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
|
||||
string_t AllocPooledString(const char *pszValue);
|
||||
bool GetServerSteam3Id(char *pszOut, size_t len) const override;
|
||||
uint64_t GetServerSteamId64() const override;
|
||||
public:
|
||||
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
||||
void ProcessFakeCliCmdQueue();
|
||||
public:
|
||||
const ICommandArgs *PeekCommandStack();
|
||||
void PushCommandStack(const CCommand *cmd);
|
||||
void PopCommandStack();
|
||||
const CCommand *PeekCommandStack();
|
||||
const char *CurrentCommandName();
|
||||
void AddDelayedKick(int client, int userid, const char *msg);
|
||||
void ProcessDelayedKicks();
|
||||
#if !defined METAMOD_PLAPI_VERSION
|
||||
bool IsOriginalEngine();
|
||||
#endif
|
||||
private:
|
||||
void PushCommandStack(const ICommandArgs *cmd);
|
||||
void PopCommandStack();
|
||||
DataTableInfo *_FindServerClass(const char *classname);
|
||||
private:
|
||||
void InitLogicalEntData();
|
||||
void InitCommandLine();
|
||||
private:
|
||||
typedef ke::HashMap<datamap_t *, DataMapCache *, ke::PointerPolicy<datamap_t> > DataTableMap;
|
||||
|
||||
NameHashSet<DataTableInfo *> m_Classes;
|
||||
DataTableMap m_Maps;
|
||||
Trie *m_pClasses;
|
||||
List<DataTableInfo *> m_Tables;
|
||||
THash<datamap_t *, DataMapTrie> m_Maps;
|
||||
int m_MsgTextMsg;
|
||||
int m_HinTextMsg;
|
||||
int m_SayTextMsg;
|
||||
@@ -287,32 +142,10 @@ private:
|
||||
CStack<DelayedFakeCliCmd *> m_FreeCmds;
|
||||
CStack<CachedCommandInfo> m_CommandStack;
|
||||
Queue<DelayedKickInfo> m_DelayedKicks;
|
||||
void *m_pGetCommandLine;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
public:
|
||||
bool CanSetCSGOEntProp(const char *pszPropName)
|
||||
{
|
||||
return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName);
|
||||
}
|
||||
private:
|
||||
ke::HashSet<std::string, detail::StringHashMapPolicy> m_CSGOBadList;
|
||||
bool m_bFollowCSGOServerGuidelines = true;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern CHalfLife2 g_HL2;
|
||||
|
||||
bool IndexToAThings(cell_t, CBaseEntity **pEntData, edict_t **pEdictData);
|
||||
|
||||
class AutoEnterCommand
|
||||
{
|
||||
public:
|
||||
AutoEnterCommand(const ICommandArgs *args) {
|
||||
g_HL2.PushCommandStack(args);
|
||||
}
|
||||
~AutoEnterCommand() {
|
||||
g_HL2.PopCommandStack();
|
||||
}
|
||||
};
|
||||
edict_t *GetEntity(cell_t num, CBaseEntity **pData);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -30,29 +30,17 @@
|
||||
*/
|
||||
|
||||
#include "HandleSys.h"
|
||||
#include <time.h>
|
||||
#include "ShareSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "Logger.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "common_logic.h"
|
||||
#include "ShareSys.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include <am-string.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <ISourceMod.h>
|
||||
|
||||
#include "sm_platform.h"
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include "sm_invalidparamhandler.h"
|
||||
#endif
|
||||
|
||||
using namespace std::string_literals;
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
HandleSystem g_HandleSys;
|
||||
|
||||
QHandle *ignore_handle;
|
||||
extern ConVar *g_datetime_format;
|
||||
|
||||
inline HandleType_t TypeParent(HandleType_t type)
|
||||
{
|
||||
@@ -72,6 +60,9 @@ HandleSystem::HandleSystem()
|
||||
m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
|
||||
memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
|
||||
|
||||
m_TypeLookup = sm_trie_create();
|
||||
m_strtab = new BaseStringTable(512);
|
||||
|
||||
m_TypeTail = 0;
|
||||
}
|
||||
|
||||
@@ -79,6 +70,8 @@ HandleSystem::~HandleSystem()
|
||||
{
|
||||
delete [] m_Handles;
|
||||
delete [] m_Types;
|
||||
sm_trie_destroy(m_TypeLookup);
|
||||
delete m_strtab;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,10 +145,12 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
||||
|
||||
if (name && name[0] != '\0')
|
||||
{
|
||||
if (m_TypeLookup.contains(name))
|
||||
if (sm_trie_retrieve(m_TypeLookup, name, NULL))
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
*err = HandleError_Parameter;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -217,8 +212,10 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
||||
pType->dispatch = dispatch;
|
||||
if (name && name[0] != '\0')
|
||||
{
|
||||
pType->name = std::make_unique<std::string>(name);
|
||||
m_TypeLookup.insert(name, pType);
|
||||
pType->nameIdx = m_strtab->AddString(name);
|
||||
sm_trie_insert(m_TypeLookup, name, (void *)pType);
|
||||
} else {
|
||||
pType->nameIdx = -1;
|
||||
}
|
||||
|
||||
pType->opened = 0;
|
||||
@@ -246,14 +243,21 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
||||
return index;
|
||||
}
|
||||
|
||||
bool HandleSystem::FindHandleType(const char *name, HandleType_t *aResult)
|
||||
bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
|
||||
{
|
||||
QHandleType *type;
|
||||
if (!m_TypeLookup.retrieve(name, &type))
|
||||
return false;
|
||||
QHandleType *_type;
|
||||
|
||||
if (aResult)
|
||||
*aResult = type - m_Types;
|
||||
if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int offset = _type - m_Types;
|
||||
|
||||
if (type)
|
||||
{
|
||||
*type = offset;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -301,28 +305,6 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
||||
}
|
||||
}
|
||||
|
||||
if (owner)
|
||||
{
|
||||
owner->num_handles++;
|
||||
if (!owner->warned_handle_usage && owner->num_handles >= HANDLESYS_WARN_USAGE)
|
||||
{
|
||||
owner->warned_handle_usage = true;
|
||||
|
||||
std::string path = "<unknown>";
|
||||
if (auto plugin = scripts->FindPluginByIdentity(owner))
|
||||
{
|
||||
path = "plugin "s + plugin->GetFilename();
|
||||
}
|
||||
else if (auto ext = g_Extensions.GetExtensionFromIdent(owner))
|
||||
{
|
||||
path = "extension "s + ext->GetFilename();
|
||||
}
|
||||
|
||||
logger->LogError("[SM] Warning: %s is using more than %d handles!",
|
||||
path.c_str(), HANDLESYS_WARN_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
QHandle *pHandle = &m_Handles[handle];
|
||||
|
||||
assert(pHandle->set == false);
|
||||
@@ -344,7 +326,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
||||
|
||||
/* Create the hash value */
|
||||
Handle_t hash = pHandle->serial;
|
||||
hash <<= HANDLESYS_HANDLE_BITS;
|
||||
hash <<= 16;
|
||||
hash |= handle;
|
||||
|
||||
/* Add a reference count to the type */
|
||||
@@ -463,7 +445,7 @@ Handle_t HandleSystem::CreateHandleInt(HandleType_t type,
|
||||
|
||||
pHandle->object = object;
|
||||
pHandle->clone = 0;
|
||||
pHandle->timestamp = g_pSM->GetAdjustedTime();
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -508,7 +490,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
||||
unsigned int *in_index,
|
||||
bool ignoreFree)
|
||||
{
|
||||
unsigned int serial = (handle >> HANDLESYS_HANDLE_BITS);
|
||||
unsigned int serial = (handle >> 16);
|
||||
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
||||
|
||||
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
||||
@@ -597,7 +579,6 @@ HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Hand
|
||||
}
|
||||
|
||||
pNewHandle->clone = index;
|
||||
pNewHandle->object = NULL;
|
||||
pHandle->refcount++;
|
||||
|
||||
*newhandle = new_handle;
|
||||
@@ -639,58 +620,10 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, Iden
|
||||
return CloneHandle(pHandle, index, newhandle, newOwner);
|
||||
}
|
||||
|
||||
Handle_t HandleSystem::FastCloneHandle(QHandle *pHandle, unsigned int index)
|
||||
{
|
||||
if (pHandle->clone)
|
||||
return FastCloneHandle(&m_Handles[pHandle->clone], pHandle->clone);
|
||||
|
||||
Handle_t hndl;
|
||||
if (CloneHandle(pHandle, index, &hndl, g_pCoreIdent) != HandleError_None)
|
||||
return BAD_HANDLE;
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
|
||||
{
|
||||
QHandle *pHandle;
|
||||
unsigned int index;
|
||||
|
||||
GetHandleUnchecked(hndl, pHandle, index);
|
||||
|
||||
return FastCloneHandle(pHandle, index);
|
||||
}
|
||||
|
||||
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
unsigned int serial = (hndl >> HANDLESYS_HANDLE_BITS);
|
||||
#endif
|
||||
index = (hndl & HANDLESYS_HANDLE_MASK);
|
||||
|
||||
assert(index != 0 && index <= m_HandleTail && index < HANDLESYS_MAX_HANDLES);
|
||||
|
||||
pHandle = &m_Handles[index];
|
||||
|
||||
assert(pHandle->set && pHandle->set != HandleSet_Freed);
|
||||
assert(pHandle->serial == serial);
|
||||
}
|
||||
|
||||
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
{
|
||||
if (pHandle->is_destroying)
|
||||
{
|
||||
/* Someone tried to free this recursively.
|
||||
* We'll just ignore this safely.
|
||||
*/
|
||||
return HandleError_None;
|
||||
}
|
||||
|
||||
QHandleType *pType = &m_Types[pHandle->type];
|
||||
|
||||
if (pHandle->owner && pHandle->owner->num_handles > 0)
|
||||
pHandle->owner->num_handles--;
|
||||
|
||||
if (pHandle->clone)
|
||||
{
|
||||
/* If we're a clone, decrease the parent reference count */
|
||||
@@ -703,7 +636,6 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
pMaster = &m_Handles[master];
|
||||
|
||||
/* Release the clone now */
|
||||
pHandle->is_destroying = true;
|
||||
ReleasePrimHandle(index);
|
||||
|
||||
/* Decrement the master's reference count */
|
||||
@@ -712,27 +644,20 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
/* Type should be the same but do this anyway... */
|
||||
pType = &m_Types[pMaster->type];
|
||||
pMaster->is_destroying = true;
|
||||
if (pMaster->object)
|
||||
{
|
||||
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
|
||||
}
|
||||
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
|
||||
ReleasePrimHandle(master);
|
||||
}
|
||||
} else if (pHandle->set == HandleSet_Identity) {
|
||||
/* If we're an identity, skip all this stuff!
|
||||
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
|
||||
*/
|
||||
pHandle->is_destroying = true;
|
||||
ReleasePrimHandle(index);
|
||||
} else {
|
||||
/* Decrement, free if necessary */
|
||||
if (--pHandle->refcount == 0)
|
||||
{
|
||||
pHandle->is_destroying = true;
|
||||
if (pHandle->object)
|
||||
{
|
||||
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
||||
}
|
||||
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
||||
ReleasePrimHandle(index);
|
||||
} else {
|
||||
/* We must be cloned, so mark ourselves as freed */
|
||||
@@ -765,6 +690,14 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec
|
||||
return HandleError_Access;
|
||||
}
|
||||
|
||||
if (pHandle->is_destroying)
|
||||
{
|
||||
/* Someone tried to free this recursively.
|
||||
* We'll just ignore this safely.
|
||||
*/
|
||||
return HandleError_None;
|
||||
}
|
||||
|
||||
return FreeHandle(pHandle, index);
|
||||
}
|
||||
|
||||
@@ -823,9 +756,6 @@ void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
|
||||
assert(pHandle->owner == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pHandle->owner = NULL;
|
||||
|
||||
/* Note that since 0 is an invalid handle, if any of these links are 0,
|
||||
* the data can still be set.
|
||||
*/
|
||||
@@ -935,6 +865,10 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
||||
m_Types[++m_FreeTypes].freeID = type;
|
||||
}
|
||||
|
||||
/* Invalidate the type now */
|
||||
IHandleTypeDispatch *dispatch = pType->dispatch;
|
||||
pType->dispatch = NULL;
|
||||
|
||||
/* Make sure nothing is using this type. */
|
||||
if (pType->opened)
|
||||
{
|
||||
@@ -946,9 +880,29 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FreeHandle(pHandle, i);
|
||||
|
||||
if (pHandle->clone)
|
||||
{
|
||||
/* Get parent */
|
||||
QHandle *pOther = &m_Handles[pHandle->clone];
|
||||
if (--pOther->refcount == 0)
|
||||
{
|
||||
/* Free! */
|
||||
dispatch->OnHandleDestroy(type, pOther->object);
|
||||
ReleasePrimHandle(pHandle->clone);
|
||||
}
|
||||
/* Unlink ourselves since we don't have a reference count */
|
||||
ReleasePrimHandle(i);
|
||||
} else {
|
||||
/* If it's not a clone, we still have to check the reference count.
|
||||
* Either way, we'll be destroyed eventually because the handle types do not change.
|
||||
*/
|
||||
if (--pHandle->refcount == 0)
|
||||
{
|
||||
/* Free! */
|
||||
dispatch->OnHandleDestroy(type, pHandle->object);
|
||||
ReleasePrimHandle(i);
|
||||
}
|
||||
}
|
||||
if (pType->opened == 0)
|
||||
{
|
||||
break;
|
||||
@@ -956,12 +910,14 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate the type now */
|
||||
pType->dispatch = NULL;
|
||||
|
||||
/* Remove it from the type cache. */
|
||||
if (pType->name)
|
||||
m_TypeLookup.remove(pType->name->c_str());
|
||||
if (pType->nameIdx != -1)
|
||||
{
|
||||
const char *typeName;
|
||||
|
||||
typeName = m_strtab->GetString(pType->nameIdx);
|
||||
sm_trie_delete(m_TypeLookup, typeName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -994,17 +950,14 @@ bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHa
|
||||
return true;
|
||||
}
|
||||
|
||||
#define HANDLE_LOG_VERY_BAD(message, ...) \
|
||||
logger->LogFatal(message, ##__VA_ARGS__); \
|
||||
logger->LogError(message, ##__VA_ARGS__);
|
||||
|
||||
bool HandleSystem::TryAndFreeSomeHandles()
|
||||
{
|
||||
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
|
||||
IPlugin *highest_owner = NULL;
|
||||
unsigned int highest_handle_count = 0;
|
||||
|
||||
/* Search all plugins */
|
||||
for (IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator(); pl_iter->MorePlugins(); pl_iter->NextPlugin())
|
||||
while (pl_iter->MorePlugins())
|
||||
{
|
||||
IPlugin *plugin = pl_iter->GetPlugin();
|
||||
IdentityToken_t *identity = plugin->GetIdentity();
|
||||
@@ -1033,6 +986,8 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
highest_owner = plugin;
|
||||
highest_handle_count = handle_count;
|
||||
}
|
||||
|
||||
pl_iter->NextPlugin();
|
||||
}
|
||||
|
||||
if (highest_owner == NULL || highest_handle_count == 0)
|
||||
@@ -1040,124 +995,20 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE_LOG_VERY_BAD("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
|
||||
HANDLE_LOG_VERY_BAD("[SM] Unloading plugin to free %d handles.", highest_handle_count);
|
||||
HANDLE_LOG_VERY_BAD("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
|
||||
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
|
||||
|
||||
const IdentityToken_t *pIdentity = highest_owner->GetIdentity();
|
||||
unsigned int total = 0, highest_index = 0, total_size = 0, size;
|
||||
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
|
||||
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
|
||||
|
||||
const QHandle *oldest = nullptr;
|
||||
const QHandle *newest = nullptr;
|
||||
for (unsigned int i = 1; i <= m_HandleTail; ++i)
|
||||
{
|
||||
const QHandle &Handle = m_Handles[i];
|
||||
if (Handle.set != HandleSet_Used || Handle.owner != pIdentity)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
++pCount[Handle.type];
|
||||
++total;
|
||||
|
||||
if (Handle.type >= highest_index)
|
||||
{
|
||||
highest_index = ((Handle.type) + 1);
|
||||
}
|
||||
|
||||
if (!oldest || oldest->timestamp > Handle.timestamp)
|
||||
{
|
||||
oldest = &Handle;
|
||||
}
|
||||
if (!newest || newest->timestamp < Handle.timestamp)
|
||||
{
|
||||
newest = &Handle;
|
||||
}
|
||||
|
||||
if (Handle.clone != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Types[Handle.type].dispatch->GetHandleApproxSize(Handle.type, Handle.object, &size))
|
||||
{
|
||||
total_size += size;
|
||||
}
|
||||
}
|
||||
|
||||
const char * pTypeName = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < highest_index; ++i)
|
||||
{
|
||||
if (pCount[i] == 0)
|
||||
{
|
||||
continue; /* We may have gaps, it's fine. */
|
||||
}
|
||||
|
||||
if (m_Types[i].name)
|
||||
pTypeName = m_Types[i].name->c_str();
|
||||
else
|
||||
pTypeName = "ANON";
|
||||
|
||||
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
|
||||
}
|
||||
|
||||
const char *fmt = bridge->GetCvarString(g_datetime_format);
|
||||
|
||||
char oldstamp[256], newstamp[256]; // 256 should be more than enough
|
||||
|
||||
// scope for InvalidParameterHandler
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
InvalidParameterHandler p;
|
||||
#endif
|
||||
size_t written = strftime(oldstamp, sizeof(oldstamp), fmt, localtime(&oldest->timestamp));
|
||||
if (!written)
|
||||
{
|
||||
ke::SafeStrcpy(oldstamp, sizeof(oldstamp), "INVALID");
|
||||
}
|
||||
|
||||
written = strftime(newstamp, sizeof(newstamp), fmt, localtime(&newest->timestamp));
|
||||
if (!written)
|
||||
{
|
||||
ke::SafeStrcpy(newstamp, sizeof(newstamp), "INVALID");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
|
||||
HANDLE_LOG_VERY_BAD("Oldest Living Handle: %s created at %s", m_Types[oldest->type].name->c_str(), oldstamp);
|
||||
HANDLE_LOG_VERY_BAD("Newest Living Handle: %s created at %s", m_Types[newest->type].name->c_str(), newstamp);
|
||||
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
|
||||
delete [] pCount;
|
||||
g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
|
||||
g_Logger.LogFatal("[SM] Unloading plugin to free %d handles.", highest_handle_count);
|
||||
g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
|
||||
|
||||
highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
|
||||
|
||||
return scripts->UnloadPlugin(highest_owner);
|
||||
return g_PluginSys.UnloadPlugin(highest_owner);
|
||||
}
|
||||
|
||||
static void rep(const HandleReporter &fn, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fn(buffer);
|
||||
}
|
||||
|
||||
void HandleSystem::Dump(const HandleReporter &fn)
|
||||
void HandleSystem::Dump(HANDLE_REPORTER rep)
|
||||
{
|
||||
unsigned int total_size = 0;
|
||||
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", "Handle", "Owner", "Type", "Memory", "Time Created");
|
||||
rep(fn, "---------------------------------------------------------------------------------------------");
|
||||
|
||||
const char *fmt = bridge->GetCvarString(g_datetime_format);
|
||||
rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
|
||||
rep("--------------------------------------------------------------------------");
|
||||
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
||||
{
|
||||
if (m_Handles[i].set != HandleSet_Used)
|
||||
@@ -1165,30 +1016,30 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
||||
continue;
|
||||
}
|
||||
/* Get the index */
|
||||
unsigned int index = (m_Handles[i].serial << HANDLESYS_HANDLE_BITS) | i;
|
||||
unsigned int index = (m_Handles[i].serial << 16) | i;
|
||||
/* Determine the owner */
|
||||
const char *owner = "UNKNOWN";
|
||||
if (m_Handles[i].owner)
|
||||
{
|
||||
IdentityToken_t *pOwner = m_Handles[i].owner;
|
||||
IdentityToken_t *pOwner = m_Handles[i].owner;
|
||||
if (pOwner == g_pCoreIdent)
|
||||
{
|
||||
owner = "CORE";
|
||||
}
|
||||
else if (pOwner == scripts->GetIdentity())
|
||||
else if (pOwner == g_PluginSys.GetIdentity())
|
||||
{
|
||||
owner = "PLUGINSYS";
|
||||
}
|
||||
else
|
||||
{
|
||||
IExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
|
||||
CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
|
||||
if (ext)
|
||||
{
|
||||
owner = ext->GetFilename();
|
||||
}
|
||||
else
|
||||
{
|
||||
SMPlugin *pPlugin = scripts->FindPluginByIdentity(pOwner);
|
||||
CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
|
||||
if (pPlugin)
|
||||
{
|
||||
owner = pPlugin->GetFilename();
|
||||
@@ -1203,55 +1054,23 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
||||
const char *type = "ANON";
|
||||
QHandleType *pType = &m_Types[m_Handles[i].type];
|
||||
unsigned int size = 0;
|
||||
unsigned int parentIdx;
|
||||
bool bresult;
|
||||
if (pType->name)
|
||||
type = pType->name->c_str();
|
||||
|
||||
if ((parentIdx = m_Handles[i].clone) != 0)
|
||||
if (pType->nameIdx != -1)
|
||||
{
|
||||
if (m_Handles[parentIdx].refcount > 0)
|
||||
{
|
||||
size = 0;
|
||||
bresult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[parentIdx].type, m_Handles[parentIdx].object, &size);
|
||||
}
|
||||
type = m_strtab->GetString(pType->nameIdx);
|
||||
}
|
||||
else
|
||||
{
|
||||
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
|
||||
}
|
||||
|
||||
char date[256]; // 256 should be more than enough
|
||||
size_t written = 0;
|
||||
// scope for InvalidParameterHandler
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
InvalidParameterHandler p;
|
||||
#endif
|
||||
written = strftime(date, sizeof(date), fmt, localtime(&m_Handles[i].timestamp));
|
||||
}
|
||||
|
||||
if (!written)
|
||||
{
|
||||
ke::SafeStrcpy(date, sizeof(date), "INVALID");
|
||||
}
|
||||
|
||||
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|
||||
|| !bresult)
|
||||
|| !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
|
||||
{
|
||||
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, "-1", date);
|
||||
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[32];
|
||||
ke::SafeSprintf(buffer, sizeof(buffer), "%d", size);
|
||||
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, buffer, date);
|
||||
UTIL_Format(buffer, sizeof(buffer), "%d", size);
|
||||
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
|
||||
total_size += size;
|
||||
}
|
||||
}
|
||||
rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
|
||||
rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -32,27 +32,21 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <amtl/am-string.h>
|
||||
#include <amtl/am-function.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "common_logic.h"
|
||||
#include <stdio.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sm_trie.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sm_memtable.h"
|
||||
|
||||
#define HANDLESYS_HANDLE_BITS 20
|
||||
#define HANDLESYS_MAX_HANDLES ((1 << HANDLESYS_HANDLE_BITS) - 1)
|
||||
#define HANDLESYS_MAX_HANDLES (1<<14)
|
||||
#define HANDLESYS_MAX_TYPES (1<<9)
|
||||
#define HANDLESYS_MAX_SUBTYPES 0xF
|
||||
#define HANDLESYS_SUBTYPE_MASK 0xF
|
||||
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
||||
#define HANDLESYS_SERIAL_BITS (32 - HANDLESYS_HANDLE_BITS)
|
||||
#define HANDLESYS_MAX_SERIALS (1 << HANDLESYS_SERIAL_BITS)
|
||||
#define HANDLESYS_SERIAL_MASK (((1 << HANDLESYS_SERIAL_BITS) - 1) << HANDLESYS_HANDLE_BITS)
|
||||
#define HANDLESYS_HANDLE_MASK ((1 << HANDLESYS_HANDLE_BITS) - 1)
|
||||
#define HANDLESYS_WARN_USAGE 100000
|
||||
#define HANDLESYS_MAX_SERIALS 0xFFFF
|
||||
#define HANDLESYS_SERIAL_MASK 0xFFFF0000
|
||||
#define HANDLESYS_HANDLE_MASK 0x0000FFFF
|
||||
|
||||
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
|
||||
|
||||
@@ -93,7 +87,6 @@ struct QHandle
|
||||
bool access_special; /* Whether or not access rules are special or type-derived */
|
||||
bool is_destroying; /* Whether or not the handle is being destroyed */
|
||||
HandleAccess sec; /* Security rules */
|
||||
time_t timestamp; /* Creation timestamp */
|
||||
/* The following variables are unrelated to the Handle array, and used
|
||||
* as an inlined chain of information */
|
||||
unsigned int freeID; /* ID of a free handle in the free handle chain */
|
||||
@@ -111,19 +104,10 @@ struct QHandleType
|
||||
TypeAccess typeSec;
|
||||
HandleAccess hndlSec;
|
||||
unsigned int opened;
|
||||
std::unique_ptr<std::string> name;
|
||||
|
||||
static inline bool matches(const char *key, const QHandleType *type)
|
||||
{
|
||||
return type->name && type->name->compare(key) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
int nameIdx;
|
||||
};
|
||||
|
||||
typedef ke::Function<void(const char *)> HandleReporter;
|
||||
typedef void (HANDLE_REPORTER)(const char *str, ...);
|
||||
|
||||
class HandleSystem :
|
||||
public IHandleSys
|
||||
@@ -175,10 +159,7 @@ public: //IHandleSystem
|
||||
const HandleAccess *pAccess,
|
||||
HandleError *err);
|
||||
|
||||
void Dump(const HandleReporter &reporter);
|
||||
|
||||
/* Bypasses security checks. */
|
||||
Handle_t FastCloneHandle(Handle_t hndl);
|
||||
void Dump(HANDLE_REPORTER rep);
|
||||
protected:
|
||||
/**
|
||||
* Decodes a handle with sanity and security checking.
|
||||
@@ -189,9 +170,6 @@ protected:
|
||||
unsigned int *index,
|
||||
bool ignoreFree=false);
|
||||
|
||||
Handle_t FastCloneHandle(QHandle *pHandle, unsigned int index);
|
||||
void GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index);
|
||||
|
||||
/**
|
||||
* Creates a basic handle and sets its reference count to 1.
|
||||
* Does not do any type or security checking.
|
||||
@@ -233,37 +211,15 @@ protected:
|
||||
private:
|
||||
QHandle *m_Handles;
|
||||
QHandleType *m_Types;
|
||||
NameHashSet<QHandleType *> m_TypeLookup;
|
||||
Trie *m_TypeLookup;
|
||||
unsigned int m_TypeTail;
|
||||
unsigned int m_FreeTypes;
|
||||
unsigned int m_HandleTail;
|
||||
unsigned int m_FreeHandles;
|
||||
unsigned int m_HSerial;
|
||||
BaseStringTable *m_strtab;
|
||||
};
|
||||
|
||||
extern HandleSystem g_HandleSys;
|
||||
|
||||
struct AutoHandleRooter
|
||||
{
|
||||
public:
|
||||
AutoHandleRooter(Handle_t hndl)
|
||||
{
|
||||
if (hndl != BAD_HANDLE)
|
||||
this->hndl = g_HandleSys.FastCloneHandle(hndl);
|
||||
else
|
||||
this->hndl = BAD_HANDLE;
|
||||
}
|
||||
|
||||
~AutoHandleRooter()
|
||||
{
|
||||
if (hndl != BAD_HANDLE)
|
||||
{
|
||||
HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
}
|
||||
}
|
||||
private:
|
||||
Handle_t hndl;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -34,16 +34,27 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sm_platform.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "LibrarySys.h"
|
||||
#include <amtl/am-string.h>
|
||||
#include <amtl/os/am-path.h>
|
||||
#include <amtl/os/am-fsutil.h>
|
||||
|
||||
LibrarySystem g_LibSys;
|
||||
|
||||
CLibrary::CLibrary(ke::RefPtr<ke::SharedLib> lib)
|
||||
: lib_(lib)
|
||||
CLibrary::~CLibrary()
|
||||
{
|
||||
if (m_lib)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
FreeLibrary(m_lib);
|
||||
#elif defined PLATFORM_POSIX
|
||||
dlclose(m_lib);
|
||||
#endif
|
||||
m_lib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CLibrary::CLibrary(LibraryHandle me)
|
||||
{
|
||||
m_lib = me;
|
||||
}
|
||||
|
||||
void CLibrary::CloseLibrary()
|
||||
@@ -53,7 +64,11 @@ void CLibrary::CloseLibrary()
|
||||
|
||||
void *CLibrary::GetSymbolAddress(const char *symname)
|
||||
{
|
||||
return lib_->lookup(symname);
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return GetProcAddress(m_lib, symname);
|
||||
#elif defined PLATFORM_POSIX
|
||||
return dlsym(m_lib, symname);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +81,7 @@ CDirectory::CDirectory(const char *path)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
char newpath[PLATFORM_MAX_PATH];
|
||||
ke::SafeSprintf(newpath, sizeof(newpath), "%s\\*.*", path);
|
||||
snprintf(newpath, sizeof(newpath), "%s\\*.*", path);
|
||||
m_dir = FindFirstFileA(newpath, &m_fd);
|
||||
if (!IsValid())
|
||||
{
|
||||
@@ -78,7 +93,7 @@ CDirectory::CDirectory(const char *path)
|
||||
{
|
||||
/* :TODO: we need to read past "." and ".."! */
|
||||
ep = readdir(m_dir);
|
||||
ke::SafeStrcpy(m_origpath, PLATFORM_MAX_PATH, path);
|
||||
snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path);
|
||||
} else {
|
||||
ep = NULL;
|
||||
}
|
||||
@@ -125,10 +140,8 @@ bool CDirectory::IsEntryDirectory()
|
||||
return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
|
||||
#elif defined PLATFORM_POSIX
|
||||
char temppath[PLATFORM_MAX_PATH];
|
||||
int ret = ke::SafeSprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
if (static_cast<size_t>(ret) >= sizeof(temppath))
|
||||
return false;
|
||||
return ke::file::IsDirectory(temppath);
|
||||
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
return g_LibSys.IsPathDirectory(temppath);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -138,10 +151,8 @@ bool CDirectory::IsEntryFile()
|
||||
return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE));
|
||||
#elif defined PLATFORM_POSIX
|
||||
char temppath[PLATFORM_MAX_PATH];
|
||||
int ret = ke::SafeSprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
if (static_cast<size_t>(ret) >= sizeof(temppath))
|
||||
return false;
|
||||
return ke::file::IsFile(temppath);
|
||||
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
return g_LibSys.IsPathFile(temppath);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -176,17 +187,75 @@ bool CDirectory::IsValid()
|
||||
|
||||
bool LibrarySystem::PathExists(const char *path)
|
||||
{
|
||||
return ke::file::PathExists(path);
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD attr = GetFileAttributesA(path);
|
||||
|
||||
return (attr != INVALID_FILE_ATTRIBUTES);
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
|
||||
return (stat(path, &s) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LibrarySystem::IsPathFile(const char *path)
|
||||
{
|
||||
return ke::file::IsFile(path);
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD attr = GetFileAttributes(path);
|
||||
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
|
||||
if (stat(path, &s) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return S_ISREG(s.st_mode) ? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LibrarySystem::IsPathDirectory(const char *path)
|
||||
{
|
||||
return ke::file::IsDirectory(path);
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD attr = GetFileAttributes(path);
|
||||
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
struct stat s;
|
||||
|
||||
if (stat(path, &s) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (S_ISDIR(s.st_mode))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IDirectory *LibrarySystem::OpenDirectory(const char *path)
|
||||
@@ -224,13 +293,13 @@ void LibrarySystem::GetPlatformErrorEx(int code, char *error, size_t maxlength)
|
||||
maxlength,
|
||||
NULL) == 0)
|
||||
{
|
||||
ke::SafeSprintf(error, maxlength, "error code %08x", code);
|
||||
UTIL_Format(error, maxlength, "error code %08x", code);
|
||||
}
|
||||
#elif defined PLATFORM_LINUX
|
||||
const char *ae = strerror_r(code, error, maxlength);
|
||||
if (ae != error)
|
||||
{
|
||||
ke::SafeStrcpy(error, maxlength, ae);
|
||||
UTIL_Format(error, maxlength, "%s", ae);
|
||||
}
|
||||
#elif defined PLATFORM_POSIX
|
||||
strerror_r(code, error, maxlength);
|
||||
@@ -238,6 +307,18 @@ void LibrarySystem::GetPlatformErrorEx(int code, char *error, size_t maxlength)
|
||||
}
|
||||
}
|
||||
|
||||
void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
GetPlatformError(buffer, maxlength);
|
||||
#elif defined PLATFORM_POSIX
|
||||
if (buffer != NULL && maxlength)
|
||||
{
|
||||
strncopy(buffer, dlerror(), maxlength);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LibrarySystem::CloseDirectory(IDirectory *dir)
|
||||
{
|
||||
delete dir;
|
||||
@@ -245,9 +326,19 @@ void LibrarySystem::CloseDirectory(IDirectory *dir)
|
||||
|
||||
ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength)
|
||||
{
|
||||
ke::RefPtr<ke::SharedLib> lib = ke::SharedLib::Open(path, error, maxlength);
|
||||
if (!lib)
|
||||
return nullptr;
|
||||
LibraryHandle lib;
|
||||
#if defined PLATFORM_WINDOWS
|
||||
lib = LoadLibraryA(path);
|
||||
#elif defined PLATFORM_POSIX
|
||||
lib = dlopen(path, RTLD_NOW);
|
||||
#endif
|
||||
|
||||
if (lib == NULL)
|
||||
{
|
||||
GetLoaderError(error, maxlength);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CLibrary(lib);
|
||||
}
|
||||
|
||||
@@ -255,8 +346,23 @@ size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
size_t mylen = ke::path::FormatVa(buffer, len, fmt, ap);
|
||||
size_t mylen = vsnprintf(buffer, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (mylen >= len)
|
||||
{
|
||||
mylen = len - 1;
|
||||
buffer[mylen] = '\0';
|
||||
}
|
||||
|
||||
for (size_t i=0; i<mylen; i++)
|
||||
{
|
||||
if (buffer[i] == PLATFORM_SEP_ALTCHAR)
|
||||
{
|
||||
buffer[i] = PLATFORM_SEP_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
return mylen;
|
||||
}
|
||||
|
||||
@@ -292,7 +398,11 @@ const char *LibrarySystem::GetFileExtension(const char *filename)
|
||||
|
||||
bool LibrarySystem::CreateFolder(const char *path)
|
||||
{
|
||||
return ke::file::CreateDirectory(path, 0775);
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return (mkdir(path) != -1);
|
||||
#elif defined PLATFORM_POSIX
|
||||
return (mkdir(path, 0775) != -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char *path)
|
||||
@@ -300,7 +410,7 @@ size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char
|
||||
size_t length = strlen(path);
|
||||
|
||||
for (size_t i = length - 1;
|
||||
i <= length - 1;
|
||||
i >= 0 && i <= length - 1;
|
||||
i--)
|
||||
{
|
||||
if (path[i] == '/'
|
||||
@@ -309,12 +419,12 @@ size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return ke::SafeStrcpy(buffer, maxlength, &path[i+1]);
|
||||
return UTIL_Format(buffer, maxlength, "%s", &path[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* We scanned and found no path separator */
|
||||
return ke::SafeStrcpy(buffer, maxlength, path);
|
||||
return UTIL_Format(buffer, maxlength, "%s", path);
|
||||
}
|
||||
|
||||
bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime)
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -33,11 +33,16 @@
|
||||
#define _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
|
||||
|
||||
#include <ILibrarySys.h>
|
||||
#include <amtl/os/am-shared-library.h>
|
||||
#include "sm_platform.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
typedef HMODULE LibraryHandle;
|
||||
#elif defined PLATFORM_POSIX
|
||||
typedef void * LibraryHandle;
|
||||
#endif
|
||||
|
||||
class CDirectory : public IDirectory
|
||||
{
|
||||
public:
|
||||
@@ -66,12 +71,13 @@ private:
|
||||
class CLibrary : public ILibrary
|
||||
{
|
||||
public:
|
||||
CLibrary(ke::RefPtr<ke::SharedLib> lib);
|
||||
CLibrary(LibraryHandle me);
|
||||
~CLibrary();
|
||||
public:
|
||||
void CloseLibrary() override;
|
||||
void *GetSymbolAddress(const char *symname) override;
|
||||
void CloseLibrary();
|
||||
void *GetSymbolAddress(const char *symname);
|
||||
private:
|
||||
ke::RefPtr<ke::SharedLib> lib_;
|
||||
LibraryHandle m_lib;
|
||||
};
|
||||
|
||||
class LibrarySystem : public ILibrarySys
|
||||
@@ -90,6 +96,7 @@ public:
|
||||
bool CreateFolder(const char *path);
|
||||
size_t GetFileFromPath(char *buffer, size_t maxlength, const char *path);
|
||||
bool FileTime(const char *path, FileTimeType type, time_t *pTime);
|
||||
void GetLoaderError(char *buffer, size_t maxlength);
|
||||
};
|
||||
|
||||
extern LibrarySystem g_LibSys;
|
||||
+503
-28
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -34,37 +34,512 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "Logger.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "TimerSys.h"
|
||||
#include "logic_bridge.h"
|
||||
#include <sourcemod_version.h>
|
||||
#include <bridge/include/IProviderCallbacks.h>
|
||||
|
||||
Logger g_Logger;
|
||||
|
||||
/**
|
||||
* :TODO: This should be creating the log folder if it doesn't exist
|
||||
*/
|
||||
|
||||
ConfigResult Logger::OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
size_t maxlength)
|
||||
{
|
||||
if (strcasecmp(key, "Logging") == 0)
|
||||
{
|
||||
bool state;
|
||||
|
||||
if (strcasecmp(value, "on") == 0)
|
||||
{
|
||||
state = true;
|
||||
} else if (strcasecmp(value, "off") == 0) {
|
||||
state = false;
|
||||
} else {
|
||||
UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
|
||||
return ConfigResult_Reject;
|
||||
}
|
||||
|
||||
if (source == ConfigSource_Console)
|
||||
{
|
||||
state ? EnableLogging() : DisableLogging();
|
||||
} else {
|
||||
m_InitialState = state;
|
||||
}
|
||||
|
||||
return ConfigResult_Accept;
|
||||
} else if (strcasecmp(key, "LogMode") == 0) {
|
||||
if (strcasecmp(value, "daily") == 0)
|
||||
{
|
||||
m_Mode = LoggingMode_Daily;
|
||||
} else if (strcasecmp(value, "map") == 0) {
|
||||
m_Mode = LoggingMode_PerMap;
|
||||
} else if (strcasecmp(value, "game") == 0) {
|
||||
m_Mode = LoggingMode_Game;
|
||||
} else {
|
||||
UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]");
|
||||
return ConfigResult_Reject;
|
||||
}
|
||||
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
return ConfigResult_Ignore;
|
||||
}
|
||||
|
||||
void Logger::OnSourceModStartup(bool late)
|
||||
{
|
||||
InitLogger(m_Mode);
|
||||
}
|
||||
|
||||
void Logger::OnSourceModAllShutdown()
|
||||
{
|
||||
CloseLogger();
|
||||
}
|
||||
|
||||
void Logger::OnSourceModLevelChange(const char *mapName)
|
||||
{
|
||||
MapChange(mapName);
|
||||
}
|
||||
|
||||
void Logger::_NewMapFile()
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Append "Log file closed" to previous log file */
|
||||
_CloseFile();
|
||||
|
||||
char _filename[256];
|
||||
int i = 0;
|
||||
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
while (true)
|
||||
{
|
||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
|
||||
FILE *fp = fopen(_filename, "r");
|
||||
if (!fp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
i++;
|
||||
}
|
||||
m_NrmFileName.assign(_filename);
|
||||
|
||||
FILE *fp = fopen(m_NrmFileName.c_str(), "w");
|
||||
if (!fp)
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformError(error, sizeof(error));
|
||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
|
||||
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
||||
LogFatal("[SM] Logging has been disabled.");
|
||||
m_Active = false;
|
||||
return;
|
||||
} else {
|
||||
char date[32];
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SM_FULL_VERSION);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::_CloseFile()
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *fp = NULL;
|
||||
if (!m_NrmFileName.empty())
|
||||
{
|
||||
fp = fopen(m_NrmFileName.c_str(), "r+");
|
||||
if (fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_END);
|
||||
LogMessage("Log file closed.");
|
||||
fclose(fp);
|
||||
}
|
||||
m_NrmFileName.clear();
|
||||
}
|
||||
|
||||
if (!m_ErrMapStart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
fp = fopen(m_ErrFileName.c_str(), "r+");
|
||||
if (fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_END);
|
||||
LogError("Error log file session closed.");
|
||||
fclose(fp);
|
||||
}
|
||||
m_ErrFileName.clear();
|
||||
}
|
||||
|
||||
void Logger::InitLogger(LoggingMode mode)
|
||||
{
|
||||
m_Mode = mode;
|
||||
m_Active = m_InitialState;
|
||||
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
m_CurDay = curtime->tm_mday;
|
||||
|
||||
char _filename[256];
|
||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||
m_ErrFileName.assign(_filename);
|
||||
|
||||
switch (m_Mode)
|
||||
{
|
||||
case LoggingMode_PerMap:
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
m_DelayedStart = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LoggingMode_Daily:
|
||||
{
|
||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||
m_NrmFileName.assign(_filename);
|
||||
m_DailyPrintHdr = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* do nothing... */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::CloseLogger()
|
||||
{
|
||||
_CloseFile();
|
||||
}
|
||||
|
||||
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
LogToOpenFileEx(fp, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
LogToFileOnlyEx(fp, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[3072];
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
char date[32];
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
|
||||
}
|
||||
|
||||
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[3072];
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
char date[32];
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void Logger::LogMessage(const char *vafmt, ...)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Mode == LoggingMode_Game)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
_PrintToGameLog(vafmt, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_DelayedStart)
|
||||
{
|
||||
m_DelayedStart = false;
|
||||
_NewMapFile();
|
||||
}
|
||||
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
FILE *fp = NULL;
|
||||
if (m_Mode == LoggingMode_PerMap)
|
||||
{
|
||||
fp = fopen(m_NrmFileName.c_str(), "a+");
|
||||
if (!fp)
|
||||
{
|
||||
_NewMapFile();
|
||||
fp = fopen(m_NrmFileName.c_str(), "a+");
|
||||
if (!fp)
|
||||
{
|
||||
goto print_error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m_CurDay != curtime->tm_mday)
|
||||
{
|
||||
char _filename[256];
|
||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||
m_NrmFileName.assign(_filename);
|
||||
m_CurDay = curtime->tm_mday;
|
||||
m_DailyPrintHdr = true;
|
||||
}
|
||||
fp = fopen(m_NrmFileName.c_str(), "a+");
|
||||
}
|
||||
|
||||
if (fp)
|
||||
{
|
||||
if (m_DailyPrintHdr)
|
||||
{
|
||||
char date[32];
|
||||
m_DailyPrintHdr = false;
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SM_FULL_VERSION);
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
LogToOpenFileEx(fp, vafmt, ap);
|
||||
va_end(ap);
|
||||
fclose(fp);
|
||||
} else {
|
||||
goto print_error;
|
||||
}
|
||||
|
||||
return;
|
||||
print_error:
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformError(error, sizeof(error));
|
||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
|
||||
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
||||
LogFatal("[SM] Logging has been disabled.");
|
||||
m_Active = false;
|
||||
}
|
||||
|
||||
void Logger::LogError(const char *vafmt, ...)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
if (curtime->tm_mday != m_CurDay)
|
||||
{
|
||||
char _filename[256];
|
||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||
m_ErrFileName.assign(_filename);
|
||||
m_CurDay = curtime->tm_mday;
|
||||
m_ErrMapStart = false;
|
||||
}
|
||||
|
||||
FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
|
||||
if (fp)
|
||||
{
|
||||
if (!m_ErrMapStart)
|
||||
{
|
||||
char date[32];
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
fprintf(fp, "L %s: SourceMod error session started\n", date);
|
||||
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||
m_ErrMapStart = true;
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
LogToOpenFileEx(fp, vafmt, ap);
|
||||
va_end(ap);
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformError(error, sizeof(error));
|
||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
|
||||
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
||||
LogFatal("[SM] Logging has been disabled.");
|
||||
m_Active = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::MapChange(const char *mapname)
|
||||
{
|
||||
m_CurMapName.assign(mapname);
|
||||
|
||||
switch (m_Mode)
|
||||
{
|
||||
case LoggingMode_Daily:
|
||||
{
|
||||
LogMessage("-------- Mapchange to %s --------", mapname);
|
||||
break;
|
||||
}
|
||||
case LoggingMode_PerMap:
|
||||
{
|
||||
_NewMapFile();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* Do nothing... */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ErrMapStart)
|
||||
{
|
||||
LogError("Error log file session closed.");
|
||||
}
|
||||
m_ErrMapStart = false;
|
||||
}
|
||||
|
||||
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
|
||||
{
|
||||
char msg[3072];
|
||||
size_t len;
|
||||
|
||||
len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
|
||||
len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
|
||||
|
||||
msg[len++] = '\n';
|
||||
msg[len] = '\0';
|
||||
|
||||
Engine_LogPrintWrapper(msg);
|
||||
}
|
||||
|
||||
const char *Logger::GetLogFileName(LogType type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LogType_Normal:
|
||||
{
|
||||
return m_NrmFileName.c_str();
|
||||
}
|
||||
case LogType_Error:
|
||||
{
|
||||
return m_ErrFileName.c_str();
|
||||
}
|
||||
default:
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoggingMode Logger::GetLoggingMode() const
|
||||
{
|
||||
return m_Mode;
|
||||
}
|
||||
|
||||
void Logger::EnableLogging()
|
||||
{
|
||||
if (m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_Active = true;
|
||||
LogMessage("[SM] Logging enabled manually by user.");
|
||||
}
|
||||
|
||||
void Logger::DisableLogging()
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LogMessage("[SM] Logging disabled manually by user.");
|
||||
m_Active = false;
|
||||
}
|
||||
|
||||
void Logger::LogFatal(const char *msg, ...)
|
||||
{
|
||||
/* :TODO: make this print all pretty-like
|
||||
* In fact, the pretty log printing function should be abstracted.
|
||||
* It's already implemented twice which is bad.
|
||||
*/
|
||||
|
||||
va_list ap;
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
|
||||
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
|
||||
|
||||
FILE *fp = fopen(path, "at");
|
||||
if (fp)
|
||||
{
|
||||
m_Active = true;
|
||||
va_start(ap, msg);
|
||||
LogToOpenFileEx(fp, msg, ap);
|
||||
va_end(ap);
|
||||
m_Active = false;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
bool g_in_game_log_hook = false;
|
||||
|
||||
static LoggerCore g_LoggerCore;
|
||||
|
||||
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
|
||||
|
||||
static void HookLogPrint(const char *message)
|
||||
{
|
||||
g_in_game_log_hook = true;
|
||||
bool stopped = logicore.callbacks->OnLogPrint(message);
|
||||
g_in_game_log_hook = false;
|
||||
|
||||
if (stopped)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void LoggerCore::OnSourceModStartup(bool late)
|
||||
{
|
||||
SH_ADD_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
|
||||
}
|
||||
|
||||
void LoggerCore::OnSourceModAllShutdown()
|
||||
{
|
||||
SH_REMOVE_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
|
||||
}
|
||||
|
||||
void Engine_LogPrintWrapper(const char *msg)
|
||||
{
|
||||
if (g_in_game_log_hook)
|
||||
|
||||
+60
-1
@@ -38,13 +38,72 @@
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
class LoggerCore : public SMGlobalClass
|
||||
enum LogType
|
||||
{
|
||||
LogType_Normal,
|
||||
LogType_Error
|
||||
};
|
||||
|
||||
enum LoggingMode
|
||||
{
|
||||
LoggingMode_Daily,
|
||||
LoggingMode_PerMap,
|
||||
LoggingMode_Game
|
||||
};
|
||||
|
||||
class Logger : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
|
||||
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
|
||||
m_InitialState(true)
|
||||
{
|
||||
}
|
||||
public: //SMGlobalClass
|
||||
ConfigResult OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllShutdown();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
public:
|
||||
void InitLogger(LoggingMode mode);
|
||||
void CloseLogger();
|
||||
void EnableLogging();
|
||||
void DisableLogging();
|
||||
void LogMessage(const char *msg, ...);
|
||||
void LogError(const char *msg, ...);
|
||||
void LogFatal(const char *msg, ...);
|
||||
void LogToOpenFile(FILE *fp, const char *msg, ...);
|
||||
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
|
||||
/* This version does not print to console, and is thus thread-safe */
|
||||
void LogToFileOnly(FILE *fp, const char *msg, ...);
|
||||
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
|
||||
void MapChange(const char *mapname);
|
||||
const char *GetLogFileName(LogType type) const;
|
||||
LoggingMode GetLoggingMode() const;
|
||||
private:
|
||||
void _CloseFile();
|
||||
void _NewMapFile();
|
||||
void _PrintToGameLog(const char *fmt, va_list ap);
|
||||
private:
|
||||
String m_NrmFileName;
|
||||
String m_ErrFileName;
|
||||
String m_CurMapName;
|
||||
LoggingMode m_Mode;
|
||||
int m_CurDay;
|
||||
bool m_ErrMapStart;
|
||||
bool m_Active;
|
||||
bool m_DelayedStart;
|
||||
bool m_DailyPrintHdr;
|
||||
bool m_InitialState;
|
||||
};
|
||||
|
||||
void Engine_LogPrintWrapper(const char *msg);
|
||||
|
||||
extern bool g_in_game_log_hook;
|
||||
extern Logger g_Logger;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
# (C)2004-2008 SourceMod Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
SMSDK = ..
|
||||
SRCDS_BASE = ~/srcds
|
||||
HL2SDK_ORIG = ../../hl2sdk
|
||||
HL2SDK_OB = ../../hl2sdk-ob
|
||||
HL2SDK_OB_VALVE = ../../hl2sdk-ob-valve
|
||||
HL2SDK_L4D = ../../hl2sdk-l4d
|
||||
MMSOURCE17 = ../../mmsource-1.7
|
||||
|
||||
#####################################
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
#####################################
|
||||
|
||||
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
|
||||
Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \
|
||||
MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \
|
||||
sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
|
||||
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
|
||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
|
||||
frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp PhraseCollection.cpp NextMap.cpp \
|
||||
NativeOwner.cpp
|
||||
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
|
||||
smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp \
|
||||
smn_handles.cpp smn_keyvalues.cpp smn_banning.cpp smn_maplists.cpp \
|
||||
smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \
|
||||
smn_usermsgs.cpp smn_menus.cpp smn_database.cpp smn_vector.cpp smn_adt_array.cpp \
|
||||
smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp
|
||||
OBJECTS += ExtensionSys.cpp \
|
||||
ForwardSys.cpp \
|
||||
HandleSys.cpp \
|
||||
LibrarySys.cpp \
|
||||
PluginInfoDatabase.cpp \
|
||||
PluginSys.cpp \
|
||||
ShareSys.cpp \
|
||||
NativeInvoker.cpp
|
||||
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
|
||||
|
||||
##############################################
|
||||
### 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
|
||||
|
||||
override ENGSET = false
|
||||
ifeq "$(ENGINE)" "original"
|
||||
HL2SDK = $(HL2SDK_ORIG)
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
CFLAGS += -DSOURCE_ENGINE=1
|
||||
METAMOD = $(MMSOURCE17)/core-legacy
|
||||
INCLUDE += -I$(HL2SDK)/public/dlls
|
||||
SRCDS = $(SRCDS_BASE)
|
||||
BINARY = sourcemod.1.ep1.so
|
||||
override ENGSET = true
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangebox"
|
||||
HL2SDK = $(HL2SDK_OB)
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=3
|
||||
METAMOD = $(MMSOURCE17)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
SRCDS = $(SRCDS_BASE)/orangebox
|
||||
BINARY = sourcemod.2.ep2.so
|
||||
override ENGSET = true
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangeboxvalve"
|
||||
HL2SDK = $(HL2SDK_OB_VALVE)
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=4
|
||||
METAMOD = $(MMSOURCE17)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
SRCDS = $(SRCDS_BASE)/orangebox
|
||||
BINARY = sourcemod.2.ep2v.so
|
||||
override ENGSET = true
|
||||
endif
|
||||
ifeq "$(ENGINE)" "left4dead"
|
||||
HL2SDK = $(HL2SDK_L4D)
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=5
|
||||
METAMOD = $(MMSOURCE17)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
SRCDS = $(SRCDS_BASE)/l4d
|
||||
BINARY = sourcemod.2.l4d.so
|
||||
override ENGSET = true
|
||||
endif
|
||||
|
||||
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_ORANGEBOXVALVE=4 -DSE_LEFT4DEAD=5
|
||||
|
||||
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
|
||||
tier0_i486.so -lpthread -static-libgcc
|
||||
|
||||
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/mathlib -I$(HL2PUB)/vstdlib \
|
||||
-I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook \
|
||||
-I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
||||
|
||||
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||
-Wno-uninitialized -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -m32
|
||||
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
||||
|
||||
################################################
|
||||
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||
################################################
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug.$(ENGINE)
|
||||
CFLAGS += $(C_DEBUG_FLAGS)
|
||||
else
|
||||
BIN_DIR = Release.$(ENGINE)
|
||||
CFLAGS += $(C_OPT_FLAGS)
|
||||
endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(C_GCC4_FLAGS)
|
||||
CPPFLAGS += $(CPP_GCC4_FLAGS)
|
||||
endif
|
||||
|
||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
||||
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
|
||||
|
||||
$(BIN_DIR)/%.o: %.cpp
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
||||
|
||||
$(BIN_DIR)/%.o: %.c
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
all: check
|
||||
mkdir -p $(BIN_DIR)/systems
|
||||
mkdir -p $(BIN_DIR)/thread
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
|
||||
$(MAKE) -f Makefile sourcemod
|
||||
|
||||
check:
|
||||
if [ "$(ENGSET)" = "false" ]; then \
|
||||
echo "You must supply ENGINE=left4dead or ENGINE=orangebox or ENGINE=original"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
sourcemod: check $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) -f Makefile all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean: check
|
||||
rm -rf $(BIN_DIR)/*.o
|
||||
rm -rf $(BIN_DIR)/systems/*.o
|
||||
rm -rf $(BIN_DIR)/thread/*.o
|
||||
rm -rf $(BIN_DIR)/$(BINARY)
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include "MemoryUtils.h"
|
||||
#include "ShareSys.h"
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
#endif
|
||||
|
||||
MemoryUtils g_MemUtils;
|
||||
|
||||
#if 0
|
||||
MemoryUtils::MemoryUtils()
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
|
||||
m_PageSize = info.dwPageSize;
|
||||
|
||||
#elif defined PLATFORM_POSIX
|
||||
|
||||
m_PageSize = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryUtils::OnSourceModAllInitialized()
|
||||
{
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||
{
|
||||
DynLibInfo lib;
|
||||
bool found;
|
||||
char *ptr, *end;
|
||||
|
||||
memset(&lib, 0, sizeof(DynLibInfo));
|
||||
|
||||
if (!GetLibraryInfo(libPtr, lib))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
||||
end = ptr + lib.memorySize;
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
found = true;
|
||||
for (register size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
|
||||
{
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return ptr;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
{
|
||||
unsigned long baseAddr;
|
||||
|
||||
if (libPtr == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
IMAGE_DOS_HEADER *dos;
|
||||
IMAGE_NT_HEADERS *pe;
|
||||
IMAGE_FILE_HEADER *file;
|
||||
IMAGE_OPTIONAL_HEADER *opt;
|
||||
|
||||
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
|
||||
|
||||
/* All this is for our insane sanity checks :o */
|
||||
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
|
||||
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
|
||||
file = &pe->FileHeader;
|
||||
opt = &pe->OptionalHeader;
|
||||
|
||||
/* Check PE magic and signature */
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check architecture, which is 32-bit/x86 right now
|
||||
* Should change this for 64-bit if Valve gets their act together
|
||||
*/
|
||||
if (file->Machine != IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library */
|
||||
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Finally, we can do this */
|
||||
lib.memorySize = opt->SizeOfImage;
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
|
||||
Dl_info info;
|
||||
Elf32_Ehdr *file;
|
||||
Elf32_Phdr *phdr;
|
||||
uint16_t phdrCount;
|
||||
|
||||
if (!dladdr(libPtr, &info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This is for our insane sanity checks :o */
|
||||
baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
|
||||
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
|
||||
|
||||
/* Check ELF magic */
|
||||
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ELF version */
|
||||
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ELF architecture, which is 32-bit/x86 right now
|
||||
* Should change this for 64-bit if Valve gets their act together
|
||||
*/
|
||||
if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library/shared object */
|
||||
if (file->e_type != ET_DYN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
phdrCount = file->e_phnum;
|
||||
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
|
||||
|
||||
/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
|
||||
for (uint16_t i = 0; i < phdrCount; i++)
|
||||
{
|
||||
Elf32_Phdr &hdr = phdr[i];
|
||||
|
||||
if (hdr.p_type == PT_LOAD)
|
||||
{
|
||||
lib.memorySize += hdr.p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Team Fortress 2 Extension
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
@@ -29,18 +29,32 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_GAMEPLAY_RULES_H_
|
||||
#define _INCLUDE_SOURCEMOD_GAMEPLAY_RULES_H_
|
||||
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||
|
||||
#include "extension.h"
|
||||
#include <jit/jit_helpers.h>
|
||||
#include <jit/x86/x86_macros.h>
|
||||
#include "CDetour/detours.h"
|
||||
#include <IMemoryUtils.h>
|
||||
#include "sm_globals.h"
|
||||
|
||||
bool InitialiseRulesDetours();
|
||||
void RemoveRulesDetours();
|
||||
using namespace SourceMod;
|
||||
|
||||
extern IForward *g_waitingPlayersStartForward;
|
||||
extern IForward *g_waitingPlayersEndForward;
|
||||
struct DynLibInfo
|
||||
{
|
||||
void *baseAddress;
|
||||
size_t memorySize;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_GAMEPLAY_RULES_H_
|
||||
class MemoryUtils :
|
||||
public IMemoryUtils,
|
||||
public SMGlobalClass
|
||||
{
|
||||
public: // SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
public: // IMemoryUtils
|
||||
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||
private:
|
||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||
};
|
||||
|
||||
extern MemoryUtils g_MemUtils;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||
+51
-72
@@ -38,9 +38,10 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "ShareSys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "Translator.h"
|
||||
|
||||
MenuManager g_Menus;
|
||||
VoteMenuHandler s_VoteHandler;
|
||||
@@ -55,47 +56,24 @@ MenuManager::MenuManager()
|
||||
|
||||
void MenuManager::OnSourceModAllInitialized()
|
||||
{
|
||||
sharesys->AddInterface(NULL, this);
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
|
||||
HandleAccess access;
|
||||
handlesys->InitAccessDefaults(NULL, &access);
|
||||
g_HandleSys.InitAccessDefaults(NULL, &access);
|
||||
|
||||
/* Deny cloning to menus */
|
||||
access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
||||
m_MenuType = handlesys->CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||
m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||
|
||||
/* Also deny deletion to styles */
|
||||
access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
||||
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
void MenuManager::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
const char* pTmp;
|
||||
|
||||
pTmp = g_pGameConf->GetKeyValue("MenuItemSound");
|
||||
if (nullptr != pTmp)
|
||||
{
|
||||
m_SelectSound = pTmp;
|
||||
}
|
||||
|
||||
pTmp = g_pGameConf->GetKeyValue("MenuExitSound");
|
||||
if (nullptr != pTmp)
|
||||
{
|
||||
m_ExitSound = pTmp;
|
||||
}
|
||||
|
||||
pTmp = g_pGameConf->GetKeyValue("MenuExitBackSound");
|
||||
if (nullptr != pTmp)
|
||||
{
|
||||
m_ExitBackSound = pTmp;
|
||||
}
|
||||
m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
void MenuManager::OnSourceModAllShutdown()
|
||||
{
|
||||
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
|
||||
handlesys->RemoveType(m_StyleType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
|
||||
}
|
||||
|
||||
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
@@ -134,7 +112,7 @@ Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return handlesys->CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
|
||||
return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
|
||||
@@ -144,7 +122,7 @@ Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return handlesys->CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
|
||||
return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
|
||||
@@ -154,7 +132,7 @@ HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
sec.pOwner = NULL;
|
||||
|
||||
return handlesys->ReadHandle(handle, m_MenuType, &sec, (void **)menu);
|
||||
return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
|
||||
}
|
||||
|
||||
HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
|
||||
@@ -164,7 +142,7 @@ HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
sec.pOwner = g_pCoreIdent;
|
||||
|
||||
return handlesys->ReadHandle(handle, m_StyleType, &sec, (void **)style);
|
||||
return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
|
||||
}
|
||||
|
||||
bool MenuManager::SetDefaultStyle(IMenuStyle *style)
|
||||
@@ -253,7 +231,6 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
unsigned int pgn = menu->GetPagination();
|
||||
unsigned int maxItems = style->GetMaxPageItems();
|
||||
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
|
||||
bool novoteButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_NOVOTE) == MENUFLAG_BUTTON_NOVOTE;
|
||||
|
||||
if (pgn != MENU_NO_PAGINATION)
|
||||
{
|
||||
@@ -264,11 +241,6 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
maxItems--;
|
||||
}
|
||||
|
||||
if (novoteButton)
|
||||
{
|
||||
maxItems--;
|
||||
}
|
||||
|
||||
/* This is very not allowed! */
|
||||
if (maxItems < 2)
|
||||
{
|
||||
@@ -332,7 +304,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
{
|
||||
ItemDrawInfo &dr = drawItems[foundItems].draw;
|
||||
/* Is the item valid? */
|
||||
if (menu->GetItemInfo(i, &dr, client) != NULL)
|
||||
if (menu->GetItemInfo(i, &dr) != NULL)
|
||||
{
|
||||
/* Ask the user to change the style, if necessary */
|
||||
mh->OnMenuDrawItem(menu, client, i, dr.style);
|
||||
@@ -422,7 +394,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
}
|
||||
while (++lastItem < totalItems)
|
||||
{
|
||||
if (menu->GetItemInfo(lastItem, &dr, client) != NULL)
|
||||
if (menu->GetItemInfo(lastItem, &dr) != NULL)
|
||||
{
|
||||
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
|
||||
if (IsSlotItem(panel, dr.style))
|
||||
@@ -444,7 +416,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
lastItem--;
|
||||
while (lastItem != 0)
|
||||
{
|
||||
if (menu->GetItemInfo(lastItem, &dr, client) != NULL)
|
||||
if (menu->GetItemInfo(lastItem, &dr) != NULL)
|
||||
{
|
||||
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
|
||||
if (IsSlotItem(panel, dr.style))
|
||||
@@ -464,20 +436,6 @@ skip_search:
|
||||
/* Draw the item according to the order */
|
||||
menu_slots_t *slots = md.slots;
|
||||
unsigned int position = 0; /* Keep track of the last position */
|
||||
|
||||
if (novoteButton)
|
||||
{
|
||||
char text[50];
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
|
||||
{
|
||||
ke::SafeStrcpy(text, sizeof(text), "No Vote");
|
||||
}
|
||||
ItemDrawInfo dr(text, 0);
|
||||
position = panel->DrawItem(dr);
|
||||
slots[position].type = ItemSel_Exit;
|
||||
position++;
|
||||
}
|
||||
|
||||
if (order == ItemOrder_Ascending)
|
||||
{
|
||||
md.item_on_page = drawItems[0].position;
|
||||
@@ -594,7 +552,7 @@ skip_search:
|
||||
/* If there are no control options,
|
||||
* Instead just pad with invisible slots.
|
||||
*/
|
||||
if (!displayNext && !displayPrev)
|
||||
if (!displayPrev && !displayPrev)
|
||||
{
|
||||
padItem.style = ITEMDRAW_NOTEXT;
|
||||
}
|
||||
@@ -628,9 +586,9 @@ skip_search:
|
||||
{
|
||||
if (exitBackButton)
|
||||
{
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
|
||||
{
|
||||
ke::SafeStrcpy(text, sizeof(text), "Back");
|
||||
UTIL_Format(text, sizeof(text), "Back");
|
||||
}
|
||||
dr.style = ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
@@ -638,9 +596,9 @@ skip_search:
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
|
||||
{
|
||||
ke::SafeStrcpy(text, sizeof(text), "Previous");
|
||||
UTIL_Format(text, sizeof(text), "Previous");
|
||||
}
|
||||
dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
@@ -659,9 +617,9 @@ skip_search:
|
||||
/* NEXT */
|
||||
if (displayNext || canDrawDisabled)
|
||||
{
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
|
||||
{
|
||||
ke::SafeStrcpy(text, sizeof(text), "Next");
|
||||
UTIL_Format(text, sizeof(text), "Next");
|
||||
}
|
||||
dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
@@ -690,9 +648,9 @@ skip_search:
|
||||
/* EXIT */
|
||||
if (exitButton)
|
||||
{
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
|
||||
{
|
||||
ke::SafeStrcpy(text, sizeof(text), "Exit");
|
||||
UTIL_Format(text, sizeof(text), "Exit");
|
||||
}
|
||||
dr.style = ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
@@ -723,9 +681,30 @@ bool MenuManager::MenuSoundsEnabled()
|
||||
return (sm_menu_sounds.GetInt() != 0);
|
||||
}
|
||||
|
||||
std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
size_t maxlength)
|
||||
{
|
||||
std::string *sound = nullptr;
|
||||
if (strcmp(key, "MenuItemSound") == 0)
|
||||
{
|
||||
m_SelectSound.assign(value);
|
||||
return ConfigResult_Accept;
|
||||
} else if (strcmp(key, "MenuExitBackSound") == 0) {
|
||||
m_ExitBackSound.assign(value);
|
||||
return ConfigResult_Accept;
|
||||
} else if (strcmp(key, "MenuExitSound") == 0) {
|
||||
m_ExitSound.assign(value);
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
return ConfigResult_Ignore;
|
||||
}
|
||||
|
||||
const char *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
const char *sound = NULL;
|
||||
|
||||
switch (sel)
|
||||
{
|
||||
@@ -735,7 +714,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_SelectSound.size() > 0)
|
||||
{
|
||||
sound = &m_SelectSound;
|
||||
sound = m_SelectSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -743,7 +722,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitBackSound.size() > 0)
|
||||
{
|
||||
sound = &m_ExitBackSound;
|
||||
sound = m_ExitBackSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -751,7 +730,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitSound.size() > 0)
|
||||
{
|
||||
sound = &m_ExitSound;
|
||||
sound = m_ExitSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+11
-6
@@ -36,8 +36,9 @@
|
||||
#include <sh_vector.h>
|
||||
#include <sh_stack.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include "sm_memtable.h"
|
||||
#include "sm_globals.h"
|
||||
#include <string>
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
@@ -55,8 +56,12 @@ public:
|
||||
MenuManager();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModAllInitialized_Post();
|
||||
void OnSourceModAllShutdown();
|
||||
ConfigResult OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
public: //IMenuManager
|
||||
virtual const char *GetInterfaceName()
|
||||
@@ -95,7 +100,7 @@ public:
|
||||
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
|
||||
public:
|
||||
bool MenuSoundsEnabled();
|
||||
std::string *GetMenuSound(ItemSelection sel);
|
||||
const char *GetMenuSound(ItemSelection sel);
|
||||
protected:
|
||||
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
|
||||
Handle_t CreateStyleHandle(IMenuStyle *style);
|
||||
@@ -105,9 +110,9 @@ private:
|
||||
CVector<IMenuStyle *> m_Styles;
|
||||
HandleType_t m_StyleType;
|
||||
HandleType_t m_MenuType;
|
||||
std::string m_SelectSound = "";
|
||||
std::string m_ExitBackSound = "";
|
||||
std::string m_ExitSound = "";
|
||||
String m_SelectSound;
|
||||
String m_ExitBackSound;
|
||||
String m_ExitSound;
|
||||
};
|
||||
|
||||
extern MenuManager g_Menus;
|
||||
|
||||
+81
-190
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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
|
||||
@@ -34,12 +34,11 @@
|
||||
#include "MenuStyle_Base.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "MenuManager.h"
|
||||
#include "HandleSys.h"
|
||||
#include "CellRecipientFilter.h"
|
||||
#if defined MENU_DEBUG
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include "Logger.h"
|
||||
#endif
|
||||
#include "logic_bridge.h"
|
||||
#include "AutoHandleRooter.h"
|
||||
|
||||
BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
|
||||
{
|
||||
@@ -59,7 +58,7 @@ Handle_t BaseMenuStyle::GetHandle()
|
||||
void BaseMenuStyle::AddClientToWatch(int client)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
|
||||
g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
|
||||
#endif
|
||||
m_WatchList.push_back(client);
|
||||
}
|
||||
@@ -67,7 +66,7 @@ void BaseMenuStyle::AddClientToWatch(int client)
|
||||
void BaseMenuStyle::RemoveClientFromWatch(int client)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
|
||||
g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
|
||||
#endif
|
||||
m_WatchList.remove(client);
|
||||
}
|
||||
@@ -75,7 +74,7 @@ void BaseMenuStyle::RemoveClientFromWatch(int client)
|
||||
void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
|
||||
g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
|
||||
#endif
|
||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||
menu_states_t &states = player->states;
|
||||
@@ -99,7 +98,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool
|
||||
|
||||
/* Fire callbacks */
|
||||
mh->OnMenuCancel(menu, client, reason);
|
||||
|
||||
|
||||
/* Only fire end if there's a valid menu */
|
||||
if (menu)
|
||||
{
|
||||
@@ -115,7 +114,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool
|
||||
void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
|
||||
g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
|
||||
#endif
|
||||
int maxClients = g_Players.GetMaxClients();
|
||||
for (int i=1; i<=maxClients; i++)
|
||||
@@ -135,7 +134,7 @@ void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
||||
bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
|
||||
g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
|
||||
#endif
|
||||
if (client < 1 || client > g_Players.MaxClients())
|
||||
{
|
||||
@@ -191,7 +190,7 @@ MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
|
||||
void BaseMenuStyle::OnClientDisconnected(int client)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
|
||||
g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
|
||||
#endif
|
||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||
if (!player->bInMenu)
|
||||
@@ -214,7 +213,7 @@ void BaseMenuStyle::ProcessWatchList()
|
||||
}
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
|
||||
g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
|
||||
m_WatchList.m_Size,
|
||||
m_WatchList.m_FirstLink,
|
||||
m_WatchList.m_FreeNodes,
|
||||
@@ -232,7 +231,7 @@ void BaseMenuStyle::ProcessWatchList()
|
||||
#if defined MENU_DEBUG
|
||||
if (total)
|
||||
{
|
||||
logger->LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
|
||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -244,7 +243,7 @@ void BaseMenuStyle::ProcessWatchList()
|
||||
client = do_lookup[i];
|
||||
player = GetMenuPlayer(client);
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
|
||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
|
||||
client,
|
||||
player->bInMenu,
|
||||
player->menuHoldTime,
|
||||
@@ -254,7 +253,7 @@ void BaseMenuStyle::ProcessWatchList()
|
||||
if (!player->bInMenu || !player->menuHoldTime)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
|
||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
|
||||
#endif
|
||||
m_WatchList.remove(client);
|
||||
continue;
|
||||
@@ -269,7 +268,7 @@ void BaseMenuStyle::ProcessWatchList()
|
||||
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
|
||||
g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
|
||||
#endif
|
||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||
|
||||
@@ -302,7 +301,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
ItemSelection type = states.slots[key_press].type;
|
||||
|
||||
/* Check if we should play a sound about the type */
|
||||
if (g_Menus.MenuSoundsEnabled() &&
|
||||
if (g_Menus.MenuSoundsEnabled() &&
|
||||
(!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
|
||||
{
|
||||
CellRecipientFilter filter;
|
||||
@@ -311,9 +310,9 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
clients[0] = client;
|
||||
filter.Initialize(clients, 1);
|
||||
|
||||
std::string *sound = g_Menus.GetMenuSound(type);
|
||||
const char *sound = g_Menus.GetMenuSound(type);
|
||||
|
||||
if (nullptr != sound && !sound->empty())
|
||||
if (sound != NULL)
|
||||
{
|
||||
edict_t *pEdict = PEntityOfEntIndex(client);
|
||||
if (pEdict)
|
||||
@@ -323,25 +322,15 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
if (pCollideable)
|
||||
{
|
||||
const Vector & pos = pCollideable->GetCollisionOrigin();
|
||||
enginesound->EmitSound(filter,
|
||||
client,
|
||||
CHAN_AUTO,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
sound->c_str(),
|
||||
-1,
|
||||
#endif
|
||||
sound->c_str(),
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
0,
|
||||
#endif
|
||||
0,
|
||||
PITCH_NORM,
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|
||||
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
|
||||
0,
|
||||
#endif
|
||||
|
||||
enginesound->EmitSound(filter,
|
||||
client,
|
||||
CHAN_AUTO,
|
||||
sound,
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
0,
|
||||
PITCH_NORM,
|
||||
&pos);
|
||||
}
|
||||
}
|
||||
@@ -388,9 +377,6 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
RemoveClientFromWatch(client);
|
||||
}
|
||||
|
||||
Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
|
||||
AutoHandleRooter ahr(hndl);
|
||||
|
||||
if (cancel)
|
||||
{
|
||||
mh->OnMenuCancel(menu, client, reason);
|
||||
@@ -412,7 +398,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
|
||||
client,
|
||||
menu,
|
||||
mh,
|
||||
@@ -475,7 +461,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
unsigned int time)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
|
||||
client,
|
||||
menu,
|
||||
mh,
|
||||
@@ -487,7 +473,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
|
||||
#endif
|
||||
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
||||
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
||||
@@ -498,7 +484,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
if (player->bAutoIgnore)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
|
||||
#endif
|
||||
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
||||
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
||||
@@ -517,7 +503,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
if (player->bInMenu)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
|
||||
#endif
|
||||
_CancelClientMenu(client, MenuCancel_Interrupted, true);
|
||||
}
|
||||
@@ -532,7 +518,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
if (!display)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
|
||||
#endif
|
||||
player->bAutoIgnore = false;
|
||||
player->bInMenu = false;
|
||||
@@ -562,7 +548,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
player->bAutoIgnore = false;
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
|
||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@@ -571,7 +557,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
||||
bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
|
||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
|
||||
#endif
|
||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||
menu_states_t &states = player->states;
|
||||
@@ -581,7 +567,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||
if (!display)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
|
||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
|
||||
#endif
|
||||
if (player->menuHoldTime)
|
||||
{
|
||||
@@ -598,15 +584,15 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||
player->bAutoIgnore = false;
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
|
||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
||||
m_pStyle(pStyle), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
|
||||
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
|
||||
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
||||
m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
|
||||
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
|
||||
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
|
||||
{
|
||||
}
|
||||
@@ -633,181 +619,84 @@ bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
||||
return false;
|
||||
}
|
||||
|
||||
CItem item(m_items.size());
|
||||
CItem item;
|
||||
|
||||
item.info = info;
|
||||
item.infoString = m_Strings.AddString(info);
|
||||
if (draw.display)
|
||||
item.display = std::make_unique<std::string>(draw.display);
|
||||
{
|
||||
item.displayString = m_Strings.AddString(draw.display);
|
||||
}
|
||||
item.style = draw.style;
|
||||
|
||||
m_items.push_back(std::move(item));
|
||||
m_items.push_back(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
||||
{
|
||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
|
||||
m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
||||
&& m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (position >= m_items.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CItem item(position);
|
||||
item.info = info;
|
||||
CItem item;
|
||||
item.infoString = m_Strings.AddString(info);
|
||||
if (draw.display)
|
||||
item.display = std::make_unique<std::string>(draw.display);
|
||||
{
|
||||
item.displayString = m_Strings.AddString(draw.display);
|
||||
}
|
||||
item.style = draw.style;
|
||||
|
||||
m_items.emplace(m_items.begin() + position, std::move(item));
|
||||
CVector<CItem>::iterator iter = m_items.iterAt(position);
|
||||
m_items.insert(iter, item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBaseMenu::RemoveItem(unsigned int position)
|
||||
{
|
||||
if (position >= m_items.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_items.erase(m_items.iterAt(position));
|
||||
|
||||
if (m_items.size() == 0)
|
||||
{
|
||||
m_Strings.Reset();
|
||||
}
|
||||
|
||||
m_items.erase(m_items.begin() + position);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBaseMenu::RemoveAllItems()
|
||||
{
|
||||
m_items.clear();
|
||||
m_Strings.Reset();
|
||||
}
|
||||
|
||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
|
||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
|
||||
{
|
||||
if (position >= m_items.size())
|
||||
return NULL;
|
||||
|
||||
if (client > 0 && position < m_RandomMaps[client].size())
|
||||
{
|
||||
position = m_RandomMaps[client][position];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (draw)
|
||||
{
|
||||
draw->display = m_items[position].display->c_str();
|
||||
draw->display = m_Strings.GetString(m_items[position].displayString);
|
||||
draw->style = m_items[position].style;
|
||||
}
|
||||
|
||||
return m_items[position].info.c_str();
|
||||
}
|
||||
|
||||
void CBaseMenu::ShufflePerClient(int start, int stop)
|
||||
{
|
||||
// limit map len to 255 items since it's using uint8
|
||||
int length = MIN(GetItemCount(), 255);
|
||||
if (stop >= 0)
|
||||
length = MIN(length, stop);
|
||||
|
||||
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||
{
|
||||
// populate per-client map ...
|
||||
m_RandomMaps[i].resize(length);
|
||||
for (int j = 0; j < length; j++)
|
||||
m_RandomMaps[i][j] = j;
|
||||
|
||||
// ... and random shuffle it
|
||||
for (int j = length - 1; j > start; j--)
|
||||
{
|
||||
int x = rand() % (j - start + 1) + start;
|
||||
uint8_t tmp = m_RandomMaps[i][x];
|
||||
m_RandomMaps[i][x] = m_RandomMaps[i][j];
|
||||
m_RandomMaps[i][j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMenu::SetClientMapping(int client, int *array, int length)
|
||||
{
|
||||
length = MIN(length, 255);
|
||||
m_RandomMaps[client].resize(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
m_RandomMaps[client][i] = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool CBaseMenu::IsPerClientShuffled()
|
||||
{
|
||||
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||
{
|
||||
if(m_RandomMaps[i].size() > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
||||
{
|
||||
if (client > 0 && position < m_RandomMaps[client].size())
|
||||
{
|
||||
position = m_RandomMaps[client][position];
|
||||
return m_items[position].index;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
void CBaseMenu::ShufflePerClient(int start, int stop)
|
||||
{
|
||||
// limit map len to 255 items since it's using uint8
|
||||
int length = MIN(GetItemCount(), 255);
|
||||
if (stop >= 0)
|
||||
length = MIN(length, stop);
|
||||
|
||||
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
|
||||
{
|
||||
// populate per-client map ...
|
||||
m_RandomMaps[i].resize(length);
|
||||
for (int j = 0; j < length; j++)
|
||||
m_RandomMaps[i][j] = j;
|
||||
|
||||
// ... and random shuffle it
|
||||
for (int j = length - 1; j > start; j--)
|
||||
{
|
||||
int x = rand() % (j - start + 1) + start;
|
||||
uint8_t tmp = m_RandomMaps[i][x];
|
||||
m_RandomMaps[i][x] = m_RandomMaps[i][j];
|
||||
m_RandomMaps[i][j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMenu::SetClientMapping(int client, int *array, int length)
|
||||
{
|
||||
length = MIN(length, 255);
|
||||
m_RandomMaps[client].resize(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
m_RandomMaps[client][i] = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool CBaseMenu::IsPerClientShuffled()
|
||||
{
|
||||
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
|
||||
{
|
||||
if(m_RandomMaps[i].length() > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
||||
{
|
||||
if (client > 0 && position < m_RandomMaps[client].length())
|
||||
{
|
||||
position = m_RandomMaps[client][position];
|
||||
return m_items[position].index;
|
||||
}
|
||||
|
||||
return position;
|
||||
return m_Strings.GetString(m_items[position].infoString);
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetItemCount()
|
||||
@@ -845,7 +734,7 @@ IMenuStyle *CBaseMenu::GetDrawStyle()
|
||||
|
||||
void CBaseMenu::SetDefaultTitle(const char *message)
|
||||
{
|
||||
m_Title = message;
|
||||
m_Title.assign(message);
|
||||
}
|
||||
|
||||
const char *CBaseMenu::GetDefaultTitle()
|
||||
@@ -861,7 +750,7 @@ void CBaseMenu::Cancel()
|
||||
}
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
||||
this,
|
||||
m_bShouldDelete);
|
||||
#endif
|
||||
@@ -885,7 +774,7 @@ void CBaseMenu::Destroy(bool releaseHandle)
|
||||
}
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
|
||||
this,
|
||||
releaseHandle,
|
||||
m_bCancelling,
|
||||
@@ -917,7 +806,7 @@ void CBaseMenu::InternalDelete()
|
||||
|
||||
m_hHandle = BAD_HANDLE;
|
||||
m_bDeleting = true;
|
||||
handlesys->FreeHandle(hndl, &sec);
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
}
|
||||
|
||||
m_pHandler->OnMenuDestroy(this);
|
||||
@@ -942,5 +831,7 @@ IMenuHandler *CBaseMenu::GetHandler()
|
||||
|
||||
unsigned int CBaseMenu::GetBaseMemUsage()
|
||||
{
|
||||
return m_Title.size() + (m_items.size() * sizeof(CItem));
|
||||
return m_Title.size()
|
||||
+ m_Strings.GetMemTable()->GetMemUsage()
|
||||
+ (m_items.size() * sizeof(CItem));
|
||||
}
|
||||
|
||||
+20
-47
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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
|
||||
@@ -32,54 +32,31 @@
|
||||
#ifndef _INCLUDE_MENUSTYLE_BASE_H
|
||||
#define _INCLUDE_MENUSTYLE_BASE_H
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <IMenuManager.h>
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <am-string.h>
|
||||
#include <am-vector.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_vector.h>
|
||||
#include "sm_memtable.h"
|
||||
#include "sm_fastlink.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
|
||||
class CItem
|
||||
{
|
||||
public:
|
||||
CItem(unsigned int index)
|
||||
CItem()
|
||||
{
|
||||
this->index = index;
|
||||
infoString = -1;
|
||||
displayString = -1;
|
||||
style = 0;
|
||||
access = 0;
|
||||
}
|
||||
CItem(CItem &&other)
|
||||
: info(std::move(other.info)),
|
||||
display(std::move(other.display))
|
||||
{
|
||||
index = other.index;
|
||||
style = other.style;
|
||||
access = other.access;
|
||||
}
|
||||
CItem & operator =(CItem &&other)
|
||||
{
|
||||
index = other.index;
|
||||
info = std::move(other.info);
|
||||
display = std::move(other.display);
|
||||
style = other.style;
|
||||
access = other.access;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int index;
|
||||
std::string info;
|
||||
std::unique_ptr<std::string> display;
|
||||
int infoString;
|
||||
int displayString;
|
||||
unsigned int style;
|
||||
unsigned int access;
|
||||
|
||||
private:
|
||||
CItem(const CItem &other) = delete;
|
||||
CItem &operator =(const CItem &other) = delete;
|
||||
};
|
||||
|
||||
class CBaseMenuPlayer
|
||||
@@ -98,7 +75,7 @@ public:
|
||||
|
||||
class CBaseMenu;
|
||||
|
||||
class BaseMenuStyle :
|
||||
class BaseMenuStyle :
|
||||
public IMenuStyle,
|
||||
public IClientListener
|
||||
{
|
||||
@@ -113,11 +90,11 @@ public: //IClientListener
|
||||
public: //what derived must implement
|
||||
virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0;
|
||||
virtual void SendDisplay(int client, IMenuPanel *display) =0;
|
||||
public: //what derived may implement
|
||||
virtual bool DoClientMenu(int client,
|
||||
CBaseMenu *menu,
|
||||
public: //what derived may implement
|
||||
virtual bool DoClientMenu(int client,
|
||||
CBaseMenu *menu,
|
||||
unsigned int first_item,
|
||||
IMenuHandler *mh,
|
||||
IMenuHandler *mh,
|
||||
unsigned int time);
|
||||
virtual bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time);
|
||||
virtual void AddClientToWatch(int client);
|
||||
@@ -144,7 +121,7 @@ public:
|
||||
virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw);
|
||||
virtual bool RemoveItem(unsigned int position);
|
||||
virtual void RemoveAllItems();
|
||||
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL, int client=0);
|
||||
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL);
|
||||
virtual unsigned int GetItemCount();
|
||||
virtual bool SetPagination(unsigned int itemsPerPage);
|
||||
virtual unsigned int GetPagination();
|
||||
@@ -158,18 +135,15 @@ public:
|
||||
virtual unsigned int GetMenuOptionFlags();
|
||||
virtual void SetMenuOptionFlags(unsigned int flags);
|
||||
virtual IMenuHandler *GetHandler();
|
||||
virtual void ShufflePerClient(int start, int stop);
|
||||
virtual void SetClientMapping(int client, int *array, int length);
|
||||
virtual bool IsPerClientShuffled();
|
||||
virtual unsigned int GetRealItemIndex(int client, unsigned int position);
|
||||
unsigned int GetBaseMemUsage();
|
||||
private:
|
||||
void InternalDelete();
|
||||
protected:
|
||||
std::string m_Title;
|
||||
String m_Title;
|
||||
IMenuStyle *m_pStyle;
|
||||
BaseStringTable m_Strings;
|
||||
unsigned int m_Pagination;
|
||||
std::vector<CItem> m_items;
|
||||
CVector<CItem> m_items;
|
||||
bool m_bShouldDelete;
|
||||
bool m_bCancelling;
|
||||
IdentityToken_t *m_pOwner;
|
||||
@@ -178,7 +152,6 @@ protected:
|
||||
Handle_t m_hHandle;
|
||||
IMenuHandler *m_pHandler;
|
||||
unsigned int m_nFlags;
|
||||
std::vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_MENUSTYLE_BASE_H
|
||||
|
||||
+25
-103
@@ -32,23 +32,10 @@
|
||||
#include "MenuStyle_Radio.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "UserMessages.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "GameConfigs.h"
|
||||
#include "PlayerManager.h"
|
||||
#if defined MENU_DEBUG
|
||||
#include <bridge/include/ILogger.h>
|
||||
#endif
|
||||
#include "logic_bridge.h"
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
#include <game/shared/berimbau/protobuf/berimbau_usermessages.pb.h>
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
#include <game/shared/vietnam/protobuf/vietnam_usermessages.pb.h>
|
||||
#include "Logger.h"
|
||||
#endif
|
||||
|
||||
extern const char *g_RadioNumTable[];
|
||||
@@ -57,14 +44,6 @@ int g_ShowMenuId = -1;
|
||||
bool g_bRadioInit = false;
|
||||
unsigned int g_RadioMenuTimeout = 0;
|
||||
|
||||
// back, next, exit
|
||||
#define MAX_PAGINATION_OPTIONS 3
|
||||
|
||||
#define MAX_MENUSLOT_KEYS 10
|
||||
|
||||
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
||||
static bool s_RadioClosesOnInvalidSlot = false;
|
||||
|
||||
CRadioStyle::CRadioStyle()
|
||||
{
|
||||
m_players = new CRadioMenuPlayer[256+1];
|
||||
@@ -87,10 +66,6 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
||||
}
|
||||
|
||||
g_bRadioInit = true;
|
||||
|
||||
// Always register the style. Use IsSupported() to check for validity before use.
|
||||
g_Menus.AddStyle(this);
|
||||
|
||||
const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg");
|
||||
if (!msg || msg[0] == '\0')
|
||||
{
|
||||
@@ -114,24 +89,7 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
||||
g_RadioMenuTimeout = 0;
|
||||
}
|
||||
|
||||
const char *items = g_pGameConf->GetKeyValue("RadioMenuMaxPageItems");
|
||||
if (items != NULL)
|
||||
{
|
||||
int value = atoi(items);
|
||||
|
||||
// Only override the mostly-safe default if it's a sane value
|
||||
if (value > MAX_PAGINATION_OPTIONS && value <= MAX_MENUSLOT_KEYS)
|
||||
{
|
||||
s_RadioMaxPageItems = value;
|
||||
}
|
||||
}
|
||||
|
||||
const char *closes = g_pGameConf->GetKeyValue("RadioMenuClosesOnInvalidSlot");
|
||||
if (closes != nullptr && strcmp(closes, "yes") == 0)
|
||||
{
|
||||
s_RadioClosesOnInvalidSlot = true;
|
||||
}
|
||||
|
||||
g_Menus.AddStyle(this);
|
||||
g_Menus.SetDefaultStyle(this);
|
||||
|
||||
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
|
||||
@@ -176,22 +134,13 @@ static unsigned int g_last_holdtime = 0;
|
||||
static unsigned int g_last_client_count = 0;
|
||||
static int g_last_clients[256];
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter)
|
||||
#else
|
||||
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
||||
#endif
|
||||
{
|
||||
int count = pFilter->GetRecipientCount();
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||
#else
|
||||
bf_read br(bf->GetBasePointer(), 3);
|
||||
|
||||
br.ReadWord();
|
||||
int c = br.ReadChar();
|
||||
#endif
|
||||
|
||||
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
|
||||
|
||||
@@ -207,7 +156,7 @@ void CRadioStyle::OnUserMessageSent(int msg_id)
|
||||
{
|
||||
int client = g_last_clients[i];
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
||||
client,
|
||||
m_players[client].bInExternMenu);
|
||||
#endif
|
||||
@@ -239,7 +188,7 @@ IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwn
|
||||
|
||||
unsigned int CRadioStyle::GetMaxPageItems()
|
||||
{
|
||||
return s_RadioMaxPageItems;
|
||||
return 10;
|
||||
}
|
||||
|
||||
const char *CRadioStyle::GetStyleName()
|
||||
@@ -268,6 +217,15 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
|
||||
return display;
|
||||
}
|
||||
|
||||
IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys)
|
||||
{
|
||||
CRadioDisplay *pPanel = MakeRadioDisplay(NULL);
|
||||
|
||||
pPanel->DirectSet(str, keys);
|
||||
|
||||
return pPanel;
|
||||
}
|
||||
|
||||
void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
|
||||
{
|
||||
m_FreeDisplays.push(display);
|
||||
@@ -334,12 +292,11 @@ void CRadioDisplay::Reset()
|
||||
keys = 0;
|
||||
}
|
||||
|
||||
bool CRadioDisplay::DirectSet(const char *str)
|
||||
void CRadioDisplay::DirectSet(const char *str, int keymap)
|
||||
{
|
||||
m_Title.clear();
|
||||
m_BufferText.assign(str);
|
||||
|
||||
return true;
|
||||
keys = keymap;
|
||||
}
|
||||
|
||||
unsigned int CRadioDisplay::GetCurrentKey()
|
||||
@@ -349,7 +306,7 @@ unsigned int CRadioDisplay::GetCurrentKey()
|
||||
|
||||
bool CRadioDisplay::SetCurrentKey(unsigned int key)
|
||||
{
|
||||
if (key < m_NextPos || m_NextPos > s_RadioMaxPageItems)
|
||||
if (key < m_NextPos || m_NextPos > 10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -385,7 +342,7 @@ void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
|
||||
|
||||
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
|
||||
{
|
||||
if (m_NextPos > s_RadioMaxPageItems || !CanDrawItem(item.style))
|
||||
if (m_NextPos > 10 || !CanDrawItem(item.style))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -460,7 +417,7 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
||||
{
|
||||
if (title[0] != '\0')
|
||||
{
|
||||
display_len = ke::SafeSprintf(display_pkt,
|
||||
display_len = UTIL_Format(display_pkt,
|
||||
sizeof(display_pkt),
|
||||
"%s\n%s",
|
||||
title,
|
||||
@@ -468,25 +425,17 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
||||
}
|
||||
else
|
||||
{
|
||||
display_len = ke::SafeStrcpy(display_pkt,
|
||||
display_len = UTIL_Format(display_pkt,
|
||||
sizeof(display_pkt),
|
||||
"%s",
|
||||
text);
|
||||
}
|
||||
|
||||
// Some games have implemented CHudMenu::SelectMenuItem to close the menu
|
||||
// even if an invalid slot has been selected, which causes us a problem as
|
||||
// we'll never get any notification from the client and we'll keep the menu
|
||||
// alive on our end indefinitely. For these games, pretend that every slot
|
||||
// is valid for selection so we're guaranteed to get a menuselect command.
|
||||
// We don't want to do this for every game as the common SelectMenuItem
|
||||
// implementation ignores invalid selections and keeps the menu open, which
|
||||
// is a much nicer user experience.
|
||||
display_keys = s_RadioClosesOnInvalidSlot ? 0x7ff : keys;
|
||||
display_keys = keys;
|
||||
}
|
||||
|
||||
void CRadioMenuPlayer::Radio_Refresh()
|
||||
{
|
||||
cell_t players[1] = { (cell_t)m_index };
|
||||
cell_t players[1] = {m_index};
|
||||
char *ptr = display_pkt;
|
||||
char save = 0;
|
||||
size_t len = display_len;
|
||||
@@ -502,18 +451,6 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
// TODO: find what happens past 240 on CS:GO
|
||||
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
if (!msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
msg->set_bits_valid_slots(display_keys);
|
||||
msg->set_display_time(time);
|
||||
msg->set_menu_string(ptr);
|
||||
g_UserMsgs.EndMessage();
|
||||
#else
|
||||
while (true)
|
||||
{
|
||||
if (len > 240)
|
||||
@@ -521,8 +458,7 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
save = ptr[240];
|
||||
ptr[240] = '\0';
|
||||
}
|
||||
|
||||
bf_write *buffer = g_UserMsgs.StartBitBufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
buffer->WriteWord(display_keys);
|
||||
buffer->WriteChar(time ? time : -1);
|
||||
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
||||
@@ -539,7 +475,6 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
display_last_refresh = gpGlobals->curtime;
|
||||
}
|
||||
@@ -575,7 +510,6 @@ unsigned int CRadioDisplay::GetApproxMemUsage()
|
||||
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
|
||||
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
|
||||
{
|
||||
m_Pagination = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
|
||||
}
|
||||
|
||||
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
||||
@@ -599,7 +533,7 @@ bool CRadioMenu::DisplayAtItem(int client,
|
||||
IMenuHandler *alt_handler)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
||||
this,
|
||||
client,
|
||||
time);
|
||||
@@ -609,7 +543,6 @@ bool CRadioMenu::DisplayAtItem(int client,
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoHandleRooter ahr(this->GetHandle());
|
||||
return g_RadioMenuStyle.DoClientMenu(client,
|
||||
this,
|
||||
start_item,
|
||||
@@ -617,17 +550,6 @@ bool CRadioMenu::DisplayAtItem(int client,
|
||||
time);
|
||||
}
|
||||
|
||||
bool CRadioMenu::SetPagination(unsigned int itemsPerPage)
|
||||
{
|
||||
const unsigned int maxPerPage = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
|
||||
if (itemsPerPage > maxPerPage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CBaseMenu::SetPagination(itemsPerPage);
|
||||
}
|
||||
|
||||
void CRadioMenu::Cancel_Finally()
|
||||
{
|
||||
g_RadioMenuStyle.CancelMenu(this);
|
||||
|
||||
+5
-15
@@ -37,13 +37,10 @@
|
||||
#include "MenuStyle_Base.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <IPlayerHelpers.h>
|
||||
#include "UserMessages.h"
|
||||
#include <IUserMessages.h>
|
||||
#include "sm_fastlink.h"
|
||||
#include <sh_stack.h>
|
||||
#include <sh_string.h>
|
||||
#include <compat_wrappers.h>
|
||||
#include "logic/common_logic.h"
|
||||
#include "AutoHandleRooter.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
@@ -68,11 +65,7 @@ private:
|
||||
class CRadioStyle :
|
||||
public BaseMenuStyle,
|
||||
public SMGlobalClass,
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
public IProtobufUserMessageListener
|
||||
#else
|
||||
public IBitBufUserMessageListener
|
||||
#endif
|
||||
public IUserMessageListener
|
||||
{
|
||||
public:
|
||||
CRadioStyle();
|
||||
@@ -91,11 +84,7 @@ public: //IMenuStyle
|
||||
unsigned int GetMaxPageItems();
|
||||
unsigned int GetApproxMemUsage();
|
||||
public: //IUserMessageListener
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
void OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter);
|
||||
#else
|
||||
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
|
||||
#endif
|
||||
void OnUserMessageSent(int msg_id);
|
||||
public:
|
||||
bool IsSupported();
|
||||
@@ -104,6 +93,7 @@ public:
|
||||
CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL);
|
||||
void FreeRadioDisplay(CRadioDisplay *display);
|
||||
CRadioMenuPlayer *GetRadioMenuPlayer(int client);
|
||||
IMenuPanel *MakeRadioDisplay(const char *str, int keys);
|
||||
private:
|
||||
CRadioMenuPlayer *m_players;
|
||||
CStack<CRadioDisplay *> m_FreeDisplays;
|
||||
@@ -131,7 +121,8 @@ public: //IMenuPanel
|
||||
bool SetCurrentKey(unsigned int key);
|
||||
int GetAmountRemaining();
|
||||
unsigned int GetApproxMemUsage();
|
||||
bool DirectSet(const char *str);
|
||||
public:
|
||||
void DirectSet(const char *str, int keymap);
|
||||
private:
|
||||
String m_BufferText;
|
||||
String m_Title;
|
||||
@@ -151,7 +142,6 @@ public:
|
||||
unsigned int time,
|
||||
unsigned int start_item,
|
||||
IMenuHandler *alt_handler/* =NULL */);
|
||||
bool SetPagination(unsigned int itemsPerPage);
|
||||
void Cancel_Finally();
|
||||
unsigned int GetApproxMemUsage();
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "sm_stringutil.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include "Translator.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "ConCmdManager.h"
|
||||
|
||||
@@ -66,14 +67,14 @@ bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCom
|
||||
void ValveMenuStyle::OnSourceModAllInitialized()
|
||||
{
|
||||
g_Players.AddClientListener(this);
|
||||
SH_ADD_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
|
||||
SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
|
||||
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
|
||||
}
|
||||
|
||||
void ValveMenuStyle::OnSourceModShutdown()
|
||||
{
|
||||
SH_RELEASE_CALLCLASS(g_pSPHCC);
|
||||
SH_REMOVE_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
|
||||
g_Players.RemoveClientListener(this);
|
||||
}
|
||||
|
||||
@@ -293,7 +294,7 @@ unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item)
|
||||
}
|
||||
|
||||
char buffer[255];
|
||||
ke::SafeSprintf(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
|
||||
UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
|
||||
|
||||
KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true);
|
||||
ki->SetString("command", g_OptionCmdTable[m_NextPos]);
|
||||
@@ -378,7 +379,7 @@ bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
||||
{
|
||||
if (option == MenuOption_IntroMessage)
|
||||
{
|
||||
ke::SafeStrcpy(m_IntroMsg, sizeof(m_IntroMsg), (const char *)valuePtr);
|
||||
strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg));
|
||||
return true;
|
||||
} else if (option == MenuOption_IntroColor) {
|
||||
unsigned int *array = (unsigned int *)valuePtr;
|
||||
@@ -404,7 +405,6 @@ bool CValveMenu::DisplayAtItem(int client,
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoHandleRooter ahr(this->GetHandle());
|
||||
return g_ValveMenuStyle.DoClientMenu(client, this, start_item, alt_handler ? alt_handler : m_pHandler, time);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
#include "KeyValues.h"
|
||||
#include "sm_fastlink.h"
|
||||
#include <compat_wrappers.h>
|
||||
#include "logic/common_logic.h"
|
||||
#include "AutoHandleRooter.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
@@ -77,7 +75,6 @@ public: //IMenuStyle
|
||||
IBaseMenu *CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner);
|
||||
unsigned int GetMaxPageItems();
|
||||
unsigned int GetApproxMemUsage();
|
||||
bool IsSupported() { return true; }
|
||||
private:
|
||||
void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin);
|
||||
private:
|
||||
@@ -108,7 +105,6 @@ public:
|
||||
bool SetCurrentKey(unsigned int key);
|
||||
int GetAmountRemaining();
|
||||
unsigned int GetApproxMemUsage();
|
||||
bool DirectSet(const char *str) { return false; }
|
||||
private:
|
||||
KeyValues *m_pKv;
|
||||
unsigned int m_NextPos;
|
||||
|
||||
+10
-208
@@ -34,56 +34,9 @@
|
||||
#include "MenuVoting.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <sourcemod.h>
|
||||
#include <Logger.h>
|
||||
#include <HalfLife2.h>
|
||||
#include <mathlib.h>
|
||||
#include <const.h>
|
||||
#include <ITranslator.h>
|
||||
#include "logic_bridge.h"
|
||||
|
||||
float g_next_vote = 0.0f;
|
||||
|
||||
#define VOTE_NOT_VOTING -2
|
||||
#define VOTE_PENDING -1
|
||||
|
||||
ConVar sm_vote_hintbox("sm_vote_progress_hintbox",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress in a hint box",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
ConVar sm_vote_chat("sm_vote_progress_chat",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress as chat messages",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
ConVar sm_vote_console("sm_vote_progress_console",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress as console messages",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
ConVar sm_vote_client_console("sm_vote_progress_client_console",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress as console messages to clients",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
|
||||
#else
|
||||
@@ -164,7 +117,7 @@ void VoteMenuHandler::OnClientDisconnected(int client)
|
||||
* newly connected client is not allowed to vote.
|
||||
*/
|
||||
int item;
|
||||
if ((item = m_ClientVotes[client]) >= VOTE_PENDING)
|
||||
if ((item = m_ClientVotes[client]) >= -1)
|
||||
{
|
||||
if (item >= 0)
|
||||
{
|
||||
@@ -172,7 +125,7 @@ void VoteMenuHandler::OnClientDisconnected(int client)
|
||||
assert(m_Votes[item] > 0);
|
||||
m_Votes[item]--;
|
||||
}
|
||||
m_ClientVotes[client] = VOTE_NOT_VOTING;
|
||||
m_ClientVotes[client] = -2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,13 +189,13 @@ bool VoteMenuHandler::IsClientInVotePool(int client)
|
||||
return false;
|
||||
}
|
||||
|
||||
return (m_ClientVotes[client] > VOTE_NOT_VOTING);
|
||||
return (m_ClientVotes[client] > -2);
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
|
||||
{
|
||||
if (!IsClientInVotePool(client)
|
||||
|| m_ClientVotes[client] == VOTE_PENDING)
|
||||
|| m_ClientVotes[client] == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -270,9 +223,7 @@ bool VoteMenuHandler::RedrawToClient(int client, bool revotes)
|
||||
assert((unsigned)m_ClientVotes[client] < m_Items);
|
||||
assert(m_Votes[m_ClientVotes[client]] > 0);
|
||||
m_Votes[m_ClientVotes[client]]--;
|
||||
m_ClientVotes[client] = VOTE_PENDING;
|
||||
m_Revoting[client] = true;
|
||||
m_NumVotes--;
|
||||
m_ClientVotes[client] = -1;
|
||||
}
|
||||
|
||||
if (m_nMenuTime == MENU_TIME_FOREVER)
|
||||
@@ -308,8 +259,7 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
|
||||
/* Mark all clients as not voting */
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
m_ClientVotes[i] = VOTE_NOT_VOTING;
|
||||
m_Revoting[i] = false;
|
||||
m_ClientVotes[i] = -2;
|
||||
}
|
||||
|
||||
m_Items = menu->GetItemCount();
|
||||
@@ -353,8 +303,6 @@ void VoteMenuHandler::StartVoting()
|
||||
|
||||
m_pHandler->OnMenuVoteStart(m_pCurMenu);
|
||||
|
||||
m_displayTimer = g_Timers.CreateTimer(this, 1.0, NULL, TIMER_FLAG_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
|
||||
|
||||
/* By now we know how many clients were set.
|
||||
* If there are none, we should end IMMEDIATELY.
|
||||
*/
|
||||
@@ -362,8 +310,6 @@ void VoteMenuHandler::StartVoting()
|
||||
{
|
||||
EndVoting();
|
||||
}
|
||||
|
||||
m_TotalClients = m_Clients;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::DecrementPlayerCount()
|
||||
@@ -400,11 +346,6 @@ void VoteMenuHandler::EndVoting()
|
||||
g_next_vote = gpGlobals->curtime + fVoteDelay;
|
||||
}
|
||||
|
||||
if (m_displayTimer)
|
||||
{
|
||||
g_Timers.KillTimer(m_displayTimer);
|
||||
}
|
||||
|
||||
if (m_bCancelled)
|
||||
{
|
||||
/* If we were cancelled, don't bother tabulating anything.
|
||||
@@ -451,7 +392,7 @@ void VoteMenuHandler::EndVoting()
|
||||
/* Build the client list */
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
if (m_ClientVotes[i] >= VOTE_PENDING)
|
||||
if (m_ClientVotes[i] >= -1)
|
||||
{
|
||||
client_vote[vote.num_clients].client = i;
|
||||
client_vote[vote.num_clients].item = m_ClientVotes[i];
|
||||
@@ -495,7 +436,7 @@ void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason
|
||||
|
||||
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
|
||||
{
|
||||
m_ClientVotes[client] = VOTE_PENDING;
|
||||
m_ClientVotes[client] = -1;
|
||||
m_pHandler->OnMenuDisplay(menu, client, display);
|
||||
}
|
||||
|
||||
@@ -514,62 +455,9 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
|
||||
/* Check by our item count, NOT the vote array size */
|
||||
if (item < m_Items)
|
||||
{
|
||||
unsigned int index = menu->GetRealItemIndex(client, item);
|
||||
m_ClientVotes[client] = index;
|
||||
m_Votes[index]++;
|
||||
m_ClientVotes[client] = item;
|
||||
m_Votes[item]++;
|
||||
m_NumVotes++;
|
||||
|
||||
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
|
||||
{
|
||||
static char buffer[1024];
|
||||
ItemDrawInfo dr;
|
||||
menu->GetItemInfo(item, &dr, client);
|
||||
|
||||
if (sm_vote_console.GetBool())
|
||||
{
|
||||
int target = SOURCEMOD_SERVER_LANGUAGE;
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
|
||||
&target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
|
||||
Engine_LogPrintWrapper(buffer);
|
||||
}
|
||||
|
||||
if (sm_vote_chat.GetBool() || sm_vote_client_console.GetBool())
|
||||
{
|
||||
int maxclients = g_Players.GetMaxClients();
|
||||
for (int i=1; i<=maxclients; i++)
|
||||
{
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
|
||||
assert(pPlayer);
|
||||
|
||||
if (pPlayer->IsInGame() && !pPlayer->IsFakeClient())
|
||||
{
|
||||
if (m_Revoting[client])
|
||||
{
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote",
|
||||
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
|
||||
}
|
||||
else
|
||||
{
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
|
||||
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
|
||||
}
|
||||
|
||||
if (sm_vote_chat.GetBool())
|
||||
{
|
||||
g_HL2.TextMsg(i, HUD_PRINTTALK, buffer);
|
||||
}
|
||||
|
||||
if (sm_vote_client_console.GetBool())
|
||||
{
|
||||
ClientConsolePrint(pPlayer->GetEdict(), buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuildVoteLeaders();
|
||||
DrawHintProgress();
|
||||
}
|
||||
|
||||
m_pHandler->OnMenuSelect(menu, client, item);
|
||||
@@ -592,9 +480,6 @@ void VoteMenuHandler::InternalReset()
|
||||
m_NumVotes = 0;
|
||||
m_bCancelled = false;
|
||||
m_pHandler = NULL;
|
||||
m_leaderList[0] = '\0';
|
||||
m_displayTimer = NULL;
|
||||
m_TotalClients = 0;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::CancelVoting()
|
||||
@@ -617,86 +502,3 @@ bool VoteMenuHandler::IsCancelling()
|
||||
return m_bCancelled;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::DrawHintProgress()
|
||||
{
|
||||
if (!sm_vote_hintbox.GetBool())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static char buffer[1024];
|
||||
|
||||
float timeRemaining = (m_fStartTime + m_nMenuTime) - gpGlobals->curtime;
|
||||
if (timeRemaining < 0)
|
||||
{
|
||||
timeRemaining = 0.0;
|
||||
}
|
||||
|
||||
int iTimeRemaining = RoundFloatToInt(timeRemaining);
|
||||
|
||||
int maxclients = g_Players.GetMaxClients();
|
||||
for (int i=1; i<=maxclients; i++)
|
||||
{
|
||||
if (g_Players.GetPlayerByIndex(i)->IsInGame())
|
||||
{
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count",
|
||||
&i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList);
|
||||
g_HL2.HintTextMsg(i, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoteMenuHandler::BuildVoteLeaders()
|
||||
{
|
||||
if (m_NumVotes == 0 || !sm_vote_hintbox.GetBool())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
menu_vote_result_t vote;
|
||||
menu_vote_result_t::menu_item_vote_t item_vote[256];
|
||||
|
||||
memset(&vote, 0, sizeof(vote));
|
||||
|
||||
/* Build the item list */
|
||||
for (unsigned int i=0; i<m_Items; i++)
|
||||
{
|
||||
if (m_Votes[i] > 0)
|
||||
{
|
||||
item_vote[vote.num_items].count = m_Votes[i];
|
||||
item_vote[vote.num_items].item = i;
|
||||
vote.num_votes += m_Votes[i];
|
||||
vote.num_items++;
|
||||
}
|
||||
}
|
||||
vote.item_list = item_vote;
|
||||
assert(vote.num_votes);
|
||||
|
||||
/* Sort the item list descending */
|
||||
qsort(item_vote,
|
||||
vote.num_items,
|
||||
sizeof(menu_vote_result_t::menu_item_vote_t),
|
||||
SortVoteItems);
|
||||
|
||||
/* Take the top 3 (if applicable) and draw them */
|
||||
int len = 0;
|
||||
for (unsigned int i=0; i<vote.num_items && i<3; i++)
|
||||
{
|
||||
int curItem = vote.item_list[i].item;
|
||||
ItemDrawInfo dr;
|
||||
m_pCurMenu->GetItemInfo(curItem, &dr);
|
||||
len += g_SourceMod.Format(m_leaderList + len, sizeof(m_leaderList) - len, "\n%i. %s: (%i)", i+1, dr.display, vote.item_list[i].count);
|
||||
}
|
||||
}
|
||||
|
||||
SourceMod::ResultType VoteMenuHandler::OnTimer(ITimer *pTimer, void *pData)
|
||||
{
|
||||
DrawHintProgress();
|
||||
|
||||
return Pl_Continue;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnTimerEnd(ITimer *pTimer, void *pData)
|
||||
{
|
||||
m_displayTimer = NULL;
|
||||
}
|
||||
|
||||
+1
-12
@@ -36,7 +36,6 @@
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <sh_vector.h>
|
||||
#include "sm_globals.h"
|
||||
#include <TimerSys.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
@@ -44,8 +43,7 @@ using namespace SourceMod;
|
||||
class VoteMenuHandler :
|
||||
public IMenuHandler,
|
||||
public SMGlobalClass,
|
||||
public IClientListener,
|
||||
public ITimedEvent
|
||||
public IClientListener
|
||||
{
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
@@ -63,9 +61,6 @@ public: //IMenuHandler
|
||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||
public: //ITimedEvent
|
||||
ResultType OnTimer(ITimer *pTimer, void *pData);
|
||||
void OnTimerEnd(ITimer *pTimer, void *pData);
|
||||
public:
|
||||
bool StartVote(IBaseMenu *menu,
|
||||
unsigned int num_clients,
|
||||
@@ -90,12 +85,9 @@ private:
|
||||
unsigned int time,
|
||||
unsigned int flags);
|
||||
void StartVoting();
|
||||
void DrawHintProgress();
|
||||
void BuildVoteLeaders();
|
||||
private:
|
||||
IMenuHandler *m_pHandler;
|
||||
unsigned int m_Clients;
|
||||
unsigned int m_TotalClients;
|
||||
unsigned int m_Items;
|
||||
CVector<unsigned int> m_Votes;
|
||||
IBaseMenu *m_pCurMenu;
|
||||
@@ -107,9 +99,6 @@ private:
|
||||
float m_fStartTime;
|
||||
unsigned int m_nMenuTime;
|
||||
int m_ClientVotes[256+1];
|
||||
bool m_Revoting[256+1];
|
||||
char m_leaderList[1024];
|
||||
ITimer *m_displayTimer;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn
|
||||
* 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>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "NativeInvoker.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
NativeInterface g_NInvoke;
|
||||
|
||||
NativeInvoker::NativeInvoker()
|
||||
{
|
||||
}
|
||||
|
||||
NativeInvoker::~NativeInvoker()
|
||||
{
|
||||
}
|
||||
|
||||
const char *NativeInterface::GetInterfaceName()
|
||||
{
|
||||
return SMINTERFACE_NINVOKE_NAME;
|
||||
}
|
||||
|
||||
unsigned int NativeInterface::GetInterfaceVersion()
|
||||
{
|
||||
return SMINTERFACE_NINVOKE_VERSION;
|
||||
}
|
||||
|
||||
void NativeInterface::OnSourceModAllInitialized()
|
||||
{
|
||||
g_ShareSys.AddInterface(NULL, &g_NInvoke);
|
||||
}
|
||||
|
||||
IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
|
||||
{
|
||||
return g_pSourcePawn2->CreateEmptyRuntime(name, bytes);
|
||||
}
|
||||
|
||||
INativeInvoker *NativeInterface::CreateInvoker()
|
||||
{
|
||||
return new NativeInvoker();
|
||||
}
|
||||
|
||||
bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
|
||||
{
|
||||
NativeEntry *entry;
|
||||
|
||||
entry = g_ShareSys.FindNative(name);
|
||||
if (entry == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
native = NULL;
|
||||
if (entry->replacement.owner != NULL)
|
||||
{
|
||||
native = entry->replacement.func;
|
||||
}
|
||||
else if (entry->owner != NULL)
|
||||
{
|
||||
native = entry->func;
|
||||
}
|
||||
|
||||
if (native == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->pContext = pContext;
|
||||
|
||||
m_curparam = 0;
|
||||
m_errorstate = SP_ERROR_NONE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cell_t NativeInvoker::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
m_info[m_curparam].marked = false;
|
||||
m_params[m_curparam] = cell;
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int NativeInvoker::PushCellByRef(cell_t *cell, int flags)
|
||||
{
|
||||
return PushArray(cell, 1, flags);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushFloat(float number)
|
||||
{
|
||||
cell_t val = *(cell_t *)&number;
|
||||
|
||||
return PushCell(val);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushFloatByRef(float *number, int flags)
|
||||
{
|
||||
return PushCellByRef((cell_t *)number, flags);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
|
||||
info->flags = inarray ? copyback : 0;
|
||||
info->marked = true;
|
||||
info->size = cells;
|
||||
info->str.is_sz = false;
|
||||
info->orig_addr = inarray;
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int NativeInvoker::PushString(const char *string)
|
||||
{
|
||||
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||
{
|
||||
return _PushString(buffer, sz_flags, cp_flags, length);
|
||||
}
|
||||
|
||||
int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
|
||||
info->marked = true;
|
||||
info->orig_addr = (cell_t *)string;
|
||||
info->flags = cp_flags;
|
||||
info->size = len;
|
||||
info->str.sz_flags = sz_flags;
|
||||
info->str.is_sz = true;
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void NativeInvoker::Cancel()
|
||||
{
|
||||
if (pContext == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_errorstate = SP_ERROR_NONE;
|
||||
m_curparam = 0;
|
||||
pContext = NULL;
|
||||
native = NULL;
|
||||
}
|
||||
|
||||
int NativeInvoker::SetError(int err)
|
||||
{
|
||||
m_errorstate = err;
|
||||
return err;
|
||||
}
|
||||
|
||||
int NativeInvoker::Invoke(cell_t *result)
|
||||
{
|
||||
int err = SP_ERROR_NONE;
|
||||
|
||||
if (pContext == NULL)
|
||||
{
|
||||
return SP_ERROR_INVALID_NATIVE;
|
||||
}
|
||||
|
||||
if (m_errorstate != SP_ERROR_NONE)
|
||||
{
|
||||
err = m_errorstate;
|
||||
Cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
cell_t tresult;
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
result = &tresult;
|
||||
}
|
||||
|
||||
//This is for re-entrancy!
|
||||
IPluginContext *ctx = pContext;
|
||||
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
|
||||
cell_t *temp_params = &_temp_params[1];
|
||||
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int numparams = m_curparam;
|
||||
unsigned int i;
|
||||
bool docopies = true;
|
||||
|
||||
if (numparams)
|
||||
{
|
||||
//Save the info locally, then reset it for re-entrant calls.
|
||||
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
||||
}
|
||||
m_curparam = 0;
|
||||
pContext = NULL;
|
||||
|
||||
/* Initialize 0th parameter */
|
||||
_temp_params[0] = numparams;
|
||||
|
||||
/* Browse the parameters and build arrays */
|
||||
for (i = 0; i < numparams; i++)
|
||||
{
|
||||
/* Is this marked as an array? */
|
||||
if (temp_info[i].marked)
|
||||
{
|
||||
if (!temp_info[i].str.is_sz)
|
||||
{
|
||||
/* Allocate a normal/generic array */
|
||||
if ((err = ctx->HeapAlloc(temp_info[i].size,
|
||||
&temp_info[i].local_addr,
|
||||
&temp_info[i].phys_addr))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (temp_info[i].orig_addr)
|
||||
{
|
||||
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate cells required for the string */
|
||||
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
|
||||
|
||||
/* Allocate the buffer */
|
||||
if ((err = ctx->HeapAlloc(cells,
|
||||
&temp_info[i].local_addr,
|
||||
&temp_info[i].phys_addr))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* Copy original string if necessary */
|
||||
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
|
||||
{
|
||||
/* Cut off UTF-8 properly */
|
||||
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
|
||||
{
|
||||
if ((err = ctx->StringToLocalUTF8(temp_info[i].local_addr,
|
||||
temp_info[i].size,
|
||||
(const char *)temp_info[i].orig_addr,
|
||||
NULL))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Copy a binary blob */
|
||||
else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
|
||||
{
|
||||
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
|
||||
}
|
||||
/* Copy ASCII characters */
|
||||
else
|
||||
{
|
||||
if ((err = ctx->StringToLocal(temp_info[i].local_addr,
|
||||
temp_info[i].size,
|
||||
(const char *)temp_info[i].orig_addr))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* End array/string calculation */
|
||||
/* Update the pushed parameter with the byref local address */
|
||||
temp_params[i] = temp_info[i].local_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just copy the value normally */
|
||||
temp_params[i] = m_params[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the call if we can */
|
||||
if (err == SP_ERROR_NONE)
|
||||
{
|
||||
*result = native(ctx, _temp_params);
|
||||
if (ctx->GetLastNativeError() != SP_ERROR_NONE)
|
||||
{
|
||||
docopies = false;
|
||||
ctx->ClearLastNativeError();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
docopies = false;
|
||||
}
|
||||
|
||||
/* i should be equal to the last valid parameter + 1 */
|
||||
while (i--)
|
||||
{
|
||||
if (!temp_info[i].marked)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
|
||||
{
|
||||
if (temp_info[i].orig_addr)
|
||||
{
|
||||
if (temp_info[i].str.is_sz)
|
||||
{
|
||||
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (temp_info[i].size == 1)
|
||||
{
|
||||
*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(temp_info[i].orig_addr,
|
||||
temp_info[i].phys_addr,
|
||||
temp_info[i].size * sizeof(cell_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* 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>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include <INativeInvoker.h>
|
||||
|
||||
struct ParamInfo
|
||||
{
|
||||
int flags; /* Copy-back flags */
|
||||
bool marked; /* Whether this is marked as being used */
|
||||
cell_t local_addr; /* Local address to free */
|
||||
cell_t *phys_addr; /* Physical address of our copy */
|
||||
cell_t *orig_addr; /* Original address to copy back to */
|
||||
ucell_t size; /* Size of array in bytes */
|
||||
struct
|
||||
{
|
||||
bool is_sz; /* is a string */
|
||||
int sz_flags; /* has sz flags */
|
||||
} str;
|
||||
};
|
||||
|
||||
class NativeInvoker : public INativeInvoker
|
||||
{
|
||||
public:
|
||||
NativeInvoker();
|
||||
~NativeInvoker();
|
||||
public: /* ICallable */
|
||||
int PushCell(cell_t cell);
|
||||
int PushCellByRef(cell_t *cell, int flags=SM_PARAM_COPYBACK);
|
||||
int PushFloat(float number);
|
||||
int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK);
|
||||
int PushArray(cell_t *inarray, unsigned int cells, int flags=0);
|
||||
int PushString(const char *string);
|
||||
int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
|
||||
void Cancel();
|
||||
public: /* INativeInvoker */
|
||||
bool Start(IPluginContext *pContext, const char *name);
|
||||
int Invoke(cell_t *result);
|
||||
private:
|
||||
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
||||
int SetError(int err);
|
||||
private:
|
||||
IPluginContext *pContext;
|
||||
SPVM_NATIVE_FUNC native;
|
||||
cell_t m_params[SP_MAX_EXEC_PARAMS];
|
||||
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int m_curparam;
|
||||
int m_errorstate;
|
||||
};
|
||||
|
||||
class NativeInterface :
|
||||
public INativeInterface,
|
||||
public SMGlobalClass
|
||||
{
|
||||
public: /* SMGlobalClass */
|
||||
void OnSourceModAllInitialized();
|
||||
public: /* SMInterface */
|
||||
unsigned int GetInterfaceVersion();
|
||||
const char *GetInterfaceName();
|
||||
public: /* INativeInvoker */
|
||||
IPluginRuntime *CreateRuntime(const char *name, size_t bytes);
|
||||
INativeInvoker *CreateInvoker();
|
||||
};
|
||||
|
||||
extern NativeInterface g_NInvoke;
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ */
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
#include "PluginSys.h"
|
||||
|
||||
CNativeOwner::CNativeOwner() : m_nMarkSerial(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CNativeOwner::SetMarkSerial(unsigned int serial)
|
||||
{
|
||||
m_nMarkSerial = serial;
|
||||
}
|
||||
|
||||
unsigned int CNativeOwner::GetMarkSerial()
|
||||
{
|
||||
return m_nMarkSerial;
|
||||
}
|
||||
|
||||
void CNativeOwner::AddDependent(CPlugin *pPlugin)
|
||||
{
|
||||
m_Dependents.push_back(pPlugin);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddWeakRef(const WeakNative & ref)
|
||||
{
|
||||
m_WeakRefs.push_back(ref);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((pEntry = g_ShareSys.AddNativeToCache(this, &natives[i])) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Natives.push_back(pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::PropogateMarkSerial(unsigned int serial)
|
||||
{
|
||||
CNativeOwner *pOwner;
|
||||
List<CPlugin *>::iterator iter;
|
||||
|
||||
for (iter = m_Dependents.begin();
|
||||
iter != m_Dependents.end();
|
||||
iter++)
|
||||
{
|
||||
pOwner = (*iter);
|
||||
pOwner->SetMarkSerial(serial);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::UnbindWeakRef(const WeakNative & ref)
|
||||
{
|
||||
sp_native_t *native;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = ref.pl->GetBaseContext();
|
||||
if ((pContext->GetNativeByIndex(ref.idx, &native)) == SP_ERROR_NONE)
|
||||
{
|
||||
/* If there is no reference, the native must be unbound */
|
||||
if (ref.entry == NULL)
|
||||
{
|
||||
native->status = SP_NATIVE_UNBOUND;
|
||||
native->pfn = NULL;
|
||||
}
|
||||
/* If we've cached a reference, it's a core native we can
|
||||
* rebind back to its original (this was a replacement).
|
||||
*/
|
||||
else
|
||||
{
|
||||
native->pfn = ref.entry->func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropEverything()
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
List<WeakNative>::iterator iter;
|
||||
List<NativeEntry *>::iterator ntv_iter;
|
||||
|
||||
/* Unbind and remove all weak references to us */
|
||||
iter = m_WeakRefs.begin();
|
||||
while (iter != m_WeakRefs.end())
|
||||
{
|
||||
UnbindWeakRef((*iter));
|
||||
iter = m_WeakRefs.erase(iter);
|
||||
}
|
||||
|
||||
/* Unmark our replacement natives */
|
||||
ntv_iter = m_ReplacedNatives.begin();
|
||||
while (ntv_iter != m_ReplacedNatives.end())
|
||||
{
|
||||
pEntry = (*ntv_iter);
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
ntv_iter = m_ReplacedNatives.erase(ntv_iter);
|
||||
}
|
||||
|
||||
/* Strip all of our natives from the cache */
|
||||
ntv_iter = m_Natives.begin();
|
||||
while (ntv_iter != m_Natives.end())
|
||||
{
|
||||
g_ShareSys.ClearNativeFromCache(this, (*ntv_iter)->name);
|
||||
ntv_iter = m_Natives.erase(ntv_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropWeakRefsTo(CPlugin *pPlugin)
|
||||
{
|
||||
List<WeakNative>::iterator iter;
|
||||
|
||||
iter = m_WeakRefs.begin();
|
||||
while (iter != m_WeakRefs.end())
|
||||
{
|
||||
WeakNative & ref = (*iter);
|
||||
|
||||
if (ref.pl == pPlugin)
|
||||
{
|
||||
iter = m_WeakRefs.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropRefsTo(CPlugin *pPlugin)
|
||||
{
|
||||
m_Dependents.remove(pPlugin);
|
||||
DropWeakRefsTo(pPlugin);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddReplacedNative(NativeEntry *pEntry)
|
||||
{
|
||||
m_ReplacedNatives.push_back(pEntry);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user