Compare commits
109
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34b5caf464 | ||
|
|
ecae5b0479 | ||
|
|
1ab9dc141f | ||
|
|
6a8529460f | ||
|
|
c63e2b318f | ||
|
|
c4a3c421ff | ||
|
|
cb3d03d699 | ||
|
|
faad5ff3ea | ||
|
|
cc02c00fd4 | ||
|
|
2bedba3f2c | ||
|
|
369f96ddfb | ||
|
|
ab1fb8309e | ||
|
|
5e9f27fe6d | ||
|
|
b8e4510f7e | ||
|
|
0d69ce8b9a | ||
|
|
a66f93b64b | ||
|
|
702ac32bc0 | ||
|
|
97c9cc9b23 | ||
|
|
f38f097396 | ||
|
|
b10edfa86f | ||
|
|
cf92376962 | ||
|
|
92d8d96cd9 | ||
|
|
ce7a98dffa | ||
|
|
f3af8539d2 | ||
|
|
35e12b16ba | ||
|
|
6e9c95034e | ||
|
|
34968def58 | ||
|
|
4800732c00 | ||
|
|
7d7bf38941 | ||
|
|
5c13a0bc69 | ||
|
|
3e63e611c2 | ||
|
|
c3598d8e71 | ||
|
|
f57097651b | ||
|
|
a5450aad18 | ||
|
|
0a4a06d9e1 | ||
|
|
dd51da519d | ||
|
|
c79f52e2c9 | ||
|
|
c4279da3b2 | ||
|
|
3923177037 | ||
|
|
80a0e24b66 | ||
|
|
75d770ba0f | ||
|
|
d9e6daa006 | ||
|
|
f08b60bc98 | ||
|
|
4d98fc2a3d | ||
|
|
0b4ec459d3 | ||
|
|
65269551f9 | ||
|
|
47b0022331 | ||
|
|
7df2b28fe0 | ||
|
|
7df1069613 | ||
|
|
7585acaeef | ||
|
|
dfcf953131 | ||
|
|
cb31a65807 | ||
|
|
6123c5e013 | ||
|
|
cb73b935ec | ||
|
|
76e8e7e50c | ||
|
|
40d049e1f6 | ||
|
|
48012ccf08 | ||
|
|
80ceb149b0 | ||
|
|
1ef60a13d0 | ||
|
|
e8e40d126e | ||
|
|
c7033827f5 | ||
|
|
ff27214615 | ||
|
|
7b45e963d5 | ||
|
|
96965ef7cd | ||
|
|
8f7ce184fb | ||
|
|
4bed0a2893 | ||
|
|
6ab2e23d9d | ||
|
|
dd27de8d85 | ||
|
|
8c79a6df33 | ||
|
|
e8111f3c0a | ||
|
|
a038181193 | ||
|
|
52fe916311 | ||
|
|
d01d7b1879 | ||
|
|
d8406a3efc | ||
|
|
d74204aded | ||
|
|
77be859667 | ||
|
|
71193c67b2 | ||
|
|
cc1493aa66 | ||
|
|
43946e6b6f | ||
|
|
5776909b13 | ||
|
|
048c227fcc | ||
|
|
95ab81f0db | ||
|
|
2fb01e412e | ||
|
|
6e9b4bf276 | ||
|
|
b344e81816 | ||
|
|
fec133bee6 | ||
|
|
594cc249ef | ||
|
|
0967035dd0 | ||
|
|
7e93cf8f6b | ||
|
|
7f20a7b6bb | ||
|
|
a9de6ed52c | ||
|
|
f0f50aa7bb | ||
|
|
36fab677a0 | ||
|
|
6c0d2a3743 | ||
|
|
e71eb5f704 | ||
|
|
4532b8a38d | ||
|
|
a089235b21 | ||
|
|
9f9f2baae2 | ||
|
|
49a643f411 | ||
|
|
8d7e8b2a85 | ||
|
|
848bc927a0 | ||
|
|
18d0f2a140 | ||
|
|
91a796b24d | ||
|
|
7e7544e036 | ||
|
|
9d676ed440 | ||
|
|
bad5252ee3 | ||
|
|
a2951b9ea8 | ||
|
|
f98cd68341 | ||
|
|
45b9573348 |
@@ -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
|
||||
|
||||
+1
-7
@@ -28,16 +28,10 @@ LIB-Debug/
|
||||
[Tt]humbs.db
|
||||
|
||||
# AMBuild build directories
|
||||
build/
|
||||
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
|
||||
+7
-82
@@ -1,86 +1,11 @@
|
||||
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
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
before_script:
|
||||
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh -s ${SDKS} && cd $CHECKOUT_DIR
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y g++-multilib libc6-dev-i386 lib32stdc++6 lib32z1-dev
|
||||
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && 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
|
||||
- python ../configure.py --enable-optimize --sdks=episode1,tf2,l4d2,csgo,dota
|
||||
- ambuild
|
||||
+358
-529
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Please visit [our wiki](https://wiki.alliedmods.net/Contributing_to_SourceMod) for information on how to contribute to Sourcemod.
|
||||
|
||||
As a sidenote, [Travis](https://travis-ci.org/alliedmodders/sourcemod) will automatically build your PR to make sure it compiles on Linux.
|
||||
@@ -6,23 +6,12 @@ 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
|
||||
- [Latest release](http://www.sourcemod.net/downloads.php): The latest stable SourceMod release
|
||||
- [Build snapshots](http://www.sourcemod.net/snapshots.php): Builds of recent development versions
|
||||
|
||||
Development
|
||||
-----------
|
||||
- [Issue tracker](https://github.com/alliedmodders/sourcemod/issues): Issues that require back and forth communication
|
||||
- [Issue tracker](https://bugs.alliedmods.net): 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_
|
||||
|
||||
+632
@@ -1,5 +1,637 @@
|
||||
SourceMod Changelog
|
||||
|
||||
SourceMod 1.6.3 [2014-11-25]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.6.3_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated game support for TF2, CS:GO, No More Room in Hell, Insurgency, PVK2 and Fistful of Frags.
|
||||
- Made changes to make TF2, CSS, DoDS, HL2DM, and SDK 2013 mods less likely to break on game update (PR 174, PR 192).
|
||||
- Added support for longer key names in languages.cfg (to fix Portuguese) (bug 6282, PR 208).
|
||||
|
||||
Developer Changes:
|
||||
- Updated TF2 player condition and holiday enums (Ross "Powerlord" Bemrose) (PR 183, PR 181).
|
||||
- Add support for TF2 player conditions >= 96 for condition functions/forwards (PR 205).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.6.2 [2014-09-20]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.6.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated game support for TF2, CS:GO, No More Room in Hell and Fistful of Frags.
|
||||
- Added compatibility shim to force Steam player auth strings to be in "Steam2" rendered format (PR 136).
|
||||
- Fixed possible performance regression in DBI handling.
|
||||
|
||||
Developer Changes:
|
||||
- Added new GetClientAuthId native to retrieve player auth strings in desired format (PR 159).
|
||||
- Updated TF2 weapon and player condition enums (FlaminSarge).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.6.1 [2014-08-17]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.6.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated game support for CS:GO and Fistful of Frags.
|
||||
- Added support for Romanian language.
|
||||
- Re-added languages.cfg, missing from 1.6.0, causing all clients to use server language.
|
||||
- Fixed a regression in version 1.6.0 that caused certain SDKHooks usage patterns to cause a server crash (PR 107).
|
||||
- Improved error reporting in basebans plugin when banreasons.txt is missing (PR 115).
|
||||
- Fixed incorrect logged gravity value for sm_gravity command (Ryan "VoiDeD" Stecker) (PR 116).
|
||||
- Fixed a regression in version 1.6.0 causing SDKHook_ReloadPost hooks to not fire in plugins (Peace-Maker) (PR 96).
|
||||
- Added workaround for game bug in TF2_RemoveWeaponSlot to avoid wearable entities left on map (Ryan "VoiDeD" Stecker) (bug 6206, PR 121).
|
||||
- Removed DisableJIT option from core.cfg. (It was never meant for normal use.)
|
||||
|
||||
Developer Changes:
|
||||
- Added new TF2_RemoveWearable native (Ryan "VoiDeD" Stecker, WildCard65) (PR 114).
|
||||
- Added new functions for interacting with and playing scripted game sounds (Ross "Powerlord" Bemrose) (bug 5942, PR 65).
|
||||
- Added new StringToKeyValues natives (Ryan "VoiDeD" Stecker) (PR 74).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.6.0 [2014-07-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.6.0_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Added support for Dota 2 (bug 5656, bug 6068).
|
||||
- Added support for Source SDK 2013 mods (bug 5917).
|
||||
- Added support for Insurgency (bug 5951).
|
||||
- Added support for Contagion (bug 6007).
|
||||
- Added support for Blade Symphony (bug 5949).
|
||||
- Updated support for some mods that moved to SDK 2013 - No More Room In Hell, Fistful of Frags, Empires, Synergy.
|
||||
- Updated gamedata and other support for TF2, DoD:S, HL2:DM, CS:S, CS:GO, Left 4 Dead, and Nuclear Dawn.
|
||||
- Added support for customizing ban reasons in basebans.sp (bug 5762) (Matthias "House" Kollek).
|
||||
- Added support for searching all gameinfo search paths when seeking mapcycle file (bug 5839).
|
||||
- Added sm_reload_translations command (bug 5750).
|
||||
- Added support for single-file gamedata custom overrides (bug 5386) (Ondrej "RavuAlHemio" Hošek).
|
||||
- Re-enabled SteamAuthstringValidation config option by default (bug 5791, PR 20).
|
||||
- Fixed plugins not reaching ext dep lists, making dependent plugin not unload on ext unload (bug 5851) (Peace-Maker).
|
||||
- Added printing of SendProp flags to netprop dumps (bug 6082).
|
||||
- Removed support for obsolete plugin_settings.cfg (bug 5605).
|
||||
- Fixed topmenu sorting not getting refreshed after reloading sorting config (bug 6032) (Peace-Maker).
|
||||
- Fixed error log filename date sometimes being incorrect (bug 5761) (Matheus "M28" Valadares).
|
||||
- Dump handle information when a plugin is forcefully unloaded. (bug 5666).
|
||||
- Fixed sm_cancelvote not resetting rtv state. (bug 5808) (Peace-Maker).
|
||||
- Fixed Mapchooser dying on single map rotation servers (bug 5179).
|
||||
- Fixed various problems with unloading ClientPrefs and SourceMod (bug 5874).
|
||||
- Fixed "sm version" command reporting incorrect compile time in many cases (bug 6078) (SystematicMania).
|
||||
- Clear default database driver reference if backing extension is unloaded (bug 5934) (Peace-Maker).
|
||||
- Moved funcommands material and sound definitions to gamedata for easier cross-game support (bug 6085).
|
||||
- Implement a watchdog timer for scripts that take too long to execute (bug 5837).
|
||||
- Use Linux game data for offsets and signatures/symbols on OS X if Mac-specific data is not available (bug 6056).
|
||||
|
||||
Developer Changes:
|
||||
- Added an API for off-thread SQL transactions. (bug 3775, PR 26).
|
||||
- Added string literal concatenation using ellipses "..." (bug 4261, PR 5) (Peace-Maker).
|
||||
- Added support for nested datatables. (bug 5446).
|
||||
- Added PbRemoveRepeatedFieldValue native (bug 6066).
|
||||
- Added support for getting/setting protobuf enum values with PbGetInt, PbSetInt, and PbAddInt natives.
|
||||
- Removed deprecated PbReadRepeated natives that existed briefly in 1.5.0-dev prerelease versions.
|
||||
- Added RequestFrame native for one-off next-frame actions (bug 5965).
|
||||
- Added CS_DMG_HEADSHOT define for CS:S and CS:GO (PR 7) (Bara20).
|
||||
- Added CS_SLOT_KNIFE define for CS:S and CS:GO (bug 6131).
|
||||
- Updated TF_WEAPON enum (PR 37) (FlaminSarge).
|
||||
- Added TFHoliday_AprilFools to TFHoliday enum (bug 6092) (Ross "Powerlord" Bemrose).
|
||||
- Added new TF2_IsHolidayActive native to TF2 Ext (bug 6095) (Ross "Powerlord" Bemrose).
|
||||
- Switch TF2 extension to hook CTFGameRules::IsHolidayActive for holiday forward (bug 6137, PR 42).
|
||||
- Added GetPlayerJingleFile native. (bug 5690) (FlaminSarge).
|
||||
- Added PrepSDKCall_SetAddress and Address support to PrepSDKCall_SetFromConf (bug 5261).
|
||||
- Added ability to disable TopMenu Title Caching (bug 6034) (Peace-Maker).
|
||||
- Added DisplayTopMenuCategory native (bug 6033) (Peace-Maker).
|
||||
- Added support for Valve search paths to GetFileSize native (bug 5931).
|
||||
- Fixed invalid entities sometimes passed to OnEntityCreated and OnEntityDestroyed (bug 6119).
|
||||
- Fixed inconsistencies with OnClientDisconnected foward calls (bug 5988, PR 16).
|
||||
- Changed OnClientSayCommand to now pass non-silent chat triggers onward (bug 5926) (SystematicMania).
|
||||
- Changed OnClientSayCommand forwards to strip quotes from chat (bug 5986) (SystematicMania).
|
||||
- Fixed FindStringIndex native not returning INVALID_STRING_INDEX when string not found (bug 6144, PR 40).
|
||||
- Fixed GroundEntChanged hooks not being called (bug 6050) (Peace-Maker).
|
||||
- Fixed INetChannelInfo natives to no longer require clients to be ingame (bug 5775) (SystematicMania).
|
||||
- Fixed replace param being respected inconsistently in SetTrieArray (bug 6113).
|
||||
- Fixed crash creating a timer when there are no handles available. (bug 5317) (Peace-Maker).
|
||||
- Fixed crash in ReconnectClient and InactivateClient natives when IServer ptr is null (bug 6122).
|
||||
- Fixed StoreFromAddress and LoadFromAddress continuing with bad values, usually crashing after error (bug 6080).
|
||||
- Fixed compiler bug with multidimensional array variable release (bug 6100).
|
||||
- Changed float comparison operators to return false for NaN (bug 6107).
|
||||
- Added support in spcomp for sp/inc files > 32767 lines (bug 5959).
|
||||
- Fixed FindFlagChar returning '?' for Admin_Custom6.
|
||||
- Fixed AllPluginsLoaded activities happening before SM is loaded.
|
||||
- Deduplicated a number of files used by extensions by moving them to the public directory (bug 5341).
|
||||
- Removed 'state' keyword from compiler (bug 4572) (Ryan "VoiDeD" Stecker).
|
||||
- Removed LogMessageEx definition from logging.inc because it never existed (bug 5897) (Peace-Maker).
|
||||
- Removed native override API (bug 5852).
|
||||
- Call OnLibraryAdded for all available libraries (bug 5925, PR 4).
|
||||
- Made IGameConfig::GetMemSig return value clearer (bug 6081).
|
||||
- Switched StringToInt(Ex) from using strtol to strtoul internally (bug 5939).
|
||||
- Added an spcomp option to print #included files (bug 5997).
|
||||
- Recompiled Regex extension libpcre against v8.32, enabling utf8, unicode props, and jit (bug 5593).
|
||||
- Optimized native calls if statically bound (bug 5842).
|
||||
|
||||
Internal Changes:
|
||||
- Now using new AlliedModders Template Library (AMTL) in many places, https://github.com/alliedmodders/amtl
|
||||
- Ported buildscripts to new AMBuild2 platform, https://github.com/alliedmodders/ambuild
|
||||
- Moved much logic from core to logic binary to reduce file sizes and compile times (bug 5606, bug 5607, bug 5680, bug 5953, PR 12, PR 13).
|
||||
- Refactored the JIT to use a newer, simpler macro assembler. (bug 5827).
|
||||
- Added sourcepawn interpreter (bug 5902).
|
||||
- Added support for compiling spcomp with emscripten.
|
||||
- Rewrite IThreader implementation around new synchronization primitives (bug 5862).
|
||||
- Rewrite DBManager to use the new synchronization primitives (bug 5870).
|
||||
- Overhauled internals of ClientPrefs extension for improved stability (bug 5538).
|
||||
- Changed ShareSys to store C++ native lists more optimally (bug 5852).
|
||||
- Simplified NativeEntry state (bug 5852).
|
||||
- Changed NativeEntry to use Refcounted to manage (bug 5852).
|
||||
- Switched Translator and GameConfigs to hash tables (bug 5878).
|
||||
- Switched numerous subsystems from KTrie to AMTL NameHashSet (bug 5884).
|
||||
- Refactored Trie natives to use AMTL HashMap instead of KTrie (bug 5892).
|
||||
- Removed usages of memtables from many subsystems (bug 5899).
|
||||
- Changed EventHook name storage to use AMTL AString (bug 6188).
|
||||
- Replaced SH List usages in game extensions with AMTL variants (PR 23).
|
||||
- Replaced SourceHook list usages in clientprefs with AMTL (PR 25).
|
||||
- Changed floating-point operations to use SSE when available (bug 5841).
|
||||
- Moved tracker related opcodes entirely to C++.
|
||||
- Statically align the stack at function boundaries (bug 5842).
|
||||
- Removed InfoVars, reassigned DAT from EBP to ESI to preserve C++ stacktraces in JIT code (5844).
|
||||
- Fixed dereferencing potential null pointer in CPlugin::GetProperty (bug 5725).
|
||||
- Fixed memory corruption when parsing natives. (bug 5840).
|
||||
- Fixed some memory errors (bug 5904).
|
||||
- Fixed unaligned memory access in spcomp.
|
||||
- Move versioning to a static library to improve trivial build speed (bug 5997).
|
||||
- Added many missing handle security checks (bug 5595).
|
||||
- Made GetEntityClassname get and cache m_iClassname offset from worldspawn for ents not having it in datadesc (bug 5654).
|
||||
- Cache m_iEFlags offset for datamaps dump instead of getting for each ent (bug 5657).
|
||||
- Fixed mismatched delete [] on thunks in JIT CompData dtor (bug 5639).
|
||||
- Fixed various memory issues. (bug 5766).
|
||||
- Added reference counting and use it for CGameConfig and IDatabase (bug 5876).
|
||||
- Added atomic reference counting and port DBI (bug 5876).
|
||||
- Replaced usages of deprecated Sourcehook Add/Remove macros (bug 5631).
|
||||
- Fixed SDKHooks hook ent validation missing first datatable name (bug 5881).
|
||||
- Fixed case where bots leave server without disconnect notice (hibernation) (PR 20).
|
||||
- Changed FindConVar to utilize convar cache for improved performance (PR 27) (VoiDeD).
|
||||
- Gave define value (of 1) to PLATFORM defs to match the same-name defs in some SDKs (PR 10).
|
||||
- Wrapped ClientPrintf into IGamePlayer (bug 6021).
|
||||
- Consolidated FileExists usage in logic bin (bug 5931).
|
||||
- Removed hardcoded paths to tier0/vstdlib in ICommandLine lookup.
|
||||
- Use updated IServerTools iface on TF2 for getting tempent list and FindEntityByClassname (PR 33).
|
||||
- Added early exit in entity output detour if entity has no classname to prevent crash.
|
||||
- Updated SDKTools entity output functions to use core's GetEntityClassname instead of own (PR 39).
|
||||
- Consolidated SDKTools entity factory lookups.
|
||||
- Changed SDKTools PlayerRunCmd to a global vtable hook to improve performance (bug 6051).
|
||||
- Changed SDKHooks to use global vtable hooks to improve performance (bug 6070).
|
||||
- Added client validation checks to EmitSound SoundsHooks (bug 5873).
|
||||
- Added missing meta results to some pre-hooks in SDKHooks.
|
||||
- Replaced magic numbers for sm_show_activity with named constants (PR 14).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.5.3 [2014-03-22]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.3_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated support for CS:GO after multiple breaking game updates.
|
||||
- Updated gamedata support for GoldenEye: Source (Peace-Maker).
|
||||
- Fixed crash on SDKHooks extension load in Alien Swarm (bug 6059).
|
||||
- Fixed memory leak from unmanaged forwards never being freed (bug 6025).
|
||||
- Fixed possible crash when unloading the CStrike extension.
|
||||
- Fixed crash in SDKHooks Reload post-hook (Peace-Maker).
|
||||
- Fixed FakeClientCommandEx always leaking memory (bug 5678).
|
||||
- Fixed extra entity networking occuring with SetEntProp natives on some games.
|
||||
- Fixed being able to nominate same map multiple times (bug 5109).
|
||||
- Fixed spurious FindEntityByClassname error being logged on some games and platforms.
|
||||
- Fixed an Anti-Flood bypass exploit (bug 5394).
|
||||
- Removed part of Addresses gamedata error handling which could cause false errors to be logged (bug 6044).
|
||||
- Fixed mapchooser not resetting nominations count when clearing nominations list (bug 5359).
|
||||
- Improved performances of client convar query handling (bug 6003).
|
||||
|
||||
Developer Changes:
|
||||
- Added GiveAmmo native to SDKTools (bug 6039) (Peace-Maker).
|
||||
- Added SQL_SetCharset native to (re)set charset even after reconnect (bug 5786) (Peace-Maker).
|
||||
- Added support for entity references in SDKHooks natives (bug 6069).
|
||||
- Added support for server passwords to DisplayAskConnectBox stock (bug 5984) (FlaminSarge).
|
||||
- Renamed SortFunc2D parameters to match documentation (bug 6014) (Peace-Maker).
|
||||
- Fixed param order in AddToTopMenu function doc (bug 6035) (Peace-Maker).
|
||||
- Added |any| tag to WritePackCell and ReadPackCell native param/return values (bug 6001).
|
||||
- Updated SDKHook_TakeDamage native for game updates.
|
||||
- Added default infinite value for TF2_AddCondition duration.
|
||||
- Added support for conditions >= 64 in TF2_OnConditionAdded/Removed (bug 5565, bug 5976) (FlaminSarge).
|
||||
- Updated TFCond and TF customkill enum values (bug 6012) (FlaminSarge).
|
||||
- Fixed regression causing incorrect return and inability to block in TF2_OnCalcIsAttackCritical forward.
|
||||
- Fixed TE_* natives operating on incorrect data for some tempents (bug 6072).
|
||||
- Fixed CS_AliasToWeaponID not returning a valid weaponID for cz75a.
|
||||
- Fixed CS_GetWeaponPrice returning incorrect value for M4A1 in CS:GO (bug 6045).
|
||||
- Increased max gamedata byte signature length.
|
||||
- Ported SM build scripts to AMBuild2 (bug 5997).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.5.2 [2013-10-29]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated gamedata support for TF2, CS:S, CS:GO, and HL2:DM.
|
||||
- Fixed crash from regression in SDKTools SetClientListening hook refcounting (bug 5956) (KyleS).
|
||||
- Fixed potential crash when having maps with format characters in name.
|
||||
- Fixed some nextmap issues with long map names.
|
||||
- SDKTools no longer requires gamedata for sm_dump_datamaps on TF2, CS:S, HL2:DM, and DoD:S (bug 5968).
|
||||
|
||||
Developer Changes:
|
||||
- Updated TFCond and TF custom dmg enums.
|
||||
- Updated TF2 critical hit detection logic in TF2_OnCalcIsAttackCritical to handle more cases, including when criticals are disabled (bug 5894).
|
||||
- Fixed GetEngineVersion native returning a bad value when running on MM:S 1.9.x or earlier (bug 5697).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.5.1 [2013-09-10]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated gamedata support for TF2.
|
||||
- Added missing DispatchKeyValue gamedata for HL2 CTF (bug 5114) (peace-maker).
|
||||
- Fixed translations not being loaded if identifier was not two or three characters (fixes Portuguese) (bug 5888).
|
||||
- Fixed runoff voting occurring when receiving the exact number of required votes (bug 5890).
|
||||
- Fixed reserve slot plugin hiding too many slots on Orangebox gamesif SourceTV and/or Replay are present (bug 5499).
|
||||
- Fixed some crashes in TF2 and unexpected behavior in all games with SDKHook_TakeDamage due to uninitialized var.
|
||||
- Fixed attempted triggers from gagged users displaying in chat (bug 5918).
|
||||
- Fixed errors in Italian translation (Oktober).
|
||||
- Added Norwegian translation (checkster).
|
||||
|
||||
Developer Changes:
|
||||
- Added CS_UpdateClientModel native to CStrike extension for CS:S and CS:GO (bug 5905) (Drifter).
|
||||
- Fixed setting weapon param in SDKHook_TakeDamage overwriting attacker instead of setting weapon (bug 5911) (KyleS)
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.5.0 [2013-08-25]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.0_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added support for Counter-Strike: Global Offensive (bug 5299, bug 5579).
|
||||
- Split CS:S, TF2, DoD:S, HL2:DM, and ND to separate binaries (bug 5370, bug 5813).
|
||||
- Added support for runoff voting in mapchooser (bug 4218).
|
||||
- Added option to require Steam validation before granting admin access (bug 4837) (VoiDeD).
|
||||
- Added localization support for many more core and base plugin messages (bug 5120, bug 5146).
|
||||
- Added the ability to override RegConsoleCommand-created commands (bug 5199).
|
||||
- Added support for "fuzzy" (partial) map names in map-related natives and cmds for L4D and later (bug 5599).
|
||||
- Updated Reserved Slots to use max humans as max count (bug 5444).
|
||||
- Added support for custom maxitems on radio menus (bug 5371).
|
||||
- Improved console config editing (bug 5470).
|
||||
- Increased map name buffer sizes in mapchooser to better account for nested maps (bug 5609) (Peace-Maker).
|
||||
- Fixed JIT conflicts with SELinux (bug 5581).
|
||||
- Added logged error when PlayerRunCommand offset lookup fails (bug 5535) (GoD-Tony).
|
||||
- Fixed double print when sending psay to self (bug 5649) (Peace-Maker).
|
||||
- Fixed check against uninitialized string in extension loader (bug 5546) (KyleS).
|
||||
- Fixed possible runtime errors in basetriggers for not-ingame clients (bug 5191) (Peace-Maker).
|
||||
- Check all possible mapcycle paths on newer orangebox games (bug 5719).
|
||||
- Fixed ReadMapList not seeing maps in all valve search paths (bug 5715) (VoiDeD).
|
||||
- Fixed typo in too-many-params native error message (Peace-Maker).
|
||||
- Fixed various issues in clientprefs (bug 5538) (KyleS).
|
||||
- Removed debug printout from PerformGravity (bug 5679) (KyleS).
|
||||
- Fixed broken translating in some plugins and natives (bug 5612) (KyleS).
|
||||
- Fixed issues with COMMAND_FILTER_NO_BOTS and @bots multi-target.
|
||||
- Fixed crash in SDKHooks when throwing bad ent type error on logical ent (KyleS).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added support for CS:GO to the CStrike extension (bug 5299) (Drifter).
|
||||
- Added support for new protobuf usermessages used in newer games (bug 5579, bug 5588, bug 5590, bug 5633).
|
||||
- Added latest SDKHooks version as first-party extension.
|
||||
- Updated SQLite to version 3.7.15.1 (bug 5235).
|
||||
- Added natives for changing team score and mvp stars on CSS/CSGO (bug 5295) (Drifter).
|
||||
- Added global pre and post forwards for client chat (bug 5394) (KyleS).
|
||||
- Added TF2_CanPlayerTeleport forward to the TF2 game extension (bug 5283) (VoiDeD).
|
||||
- Added GetEntityAddress native (bug 5269) (ProdigySim).
|
||||
- Added more parameters to PlayerRunCommand forward (bug 5346) (GoD-Tony).
|
||||
- Added forwards to basecomm plugin (bug 5466) (Drifter).
|
||||
- Added symbol lookup support to gamedata on Windows (bug 5511) (GoD-Tony).
|
||||
- Exposed GetLanguageInfo in ITranslator interface (bug 5249) (VoiDeD).
|
||||
- Increase maximum .sp line length to 4095 characters. (bug 5347) (theY4Kman).
|
||||
- Improved netprop dump output (bug 5471).
|
||||
- Added int64 typename to netprop dumps (bug 5655).
|
||||
- Added GetMaxHumanPlayers native exposing IServerGameClients func (bug 5551).
|
||||
- Added WeaponIDToAlias native to CStrike extension (bug 5460) (KyleS).
|
||||
- Fixed OnLibraryAdded/Removed not being called in all plugins (bug 5431).
|
||||
- Made thread worker processing limits configurable at runtime (bug 5326).
|
||||
- Added support in TF2 ext for detection of player conds >= 64 (bug 5565).
|
||||
- Updated button defines in entity_prop_stocks (bug 5564).
|
||||
- Added GetPlayerResourceEntity to SDKTools to replace old, semi-broken TF2-only version (bug 5491).
|
||||
- Exposed third parameter of TF2's AddCond in TF2_AddCondition (bug 5641) (FlaminSarge).
|
||||
- Added GetSteamAccountID function to IPlayerHelpers and native for sp (bug 5548) (KyleS).
|
||||
- Added ISDKHooks interface with entity listeners (bug 5602) (GoD-Tony).
|
||||
- Added file upload support to webternet extension.
|
||||
- Added more alternative names for TFClass_Heavy (bug 5338) (Afronanny).
|
||||
- Throw error instead of crash when calling SetTeamScore between maps (bug 5718) (KyleS).
|
||||
- Fixed clients not being marked as in kick queue in some cases (bug 5746) (SystematicMania).
|
||||
- Made compile.sh set working dir to own dir (bug 5710) (KyleS).
|
||||
- Added CS_IsValidWeaponID native and validity checks to other natives (bug 5566) (Drifter).
|
||||
- Numerous code documentation fixups (bug 5720) (Tsunami).
|
||||
- Fixed cmd listener callback return behavior to match func doc (bug 5882).
|
||||
|
||||
Internal Changes:
|
||||
|
||||
- Fixed handle misuse in clientprefs plugin (bug 5805) (KyleS).
|
||||
- Removed call to getchar() in debug build of compiler (bug 5626) (KyleS).
|
||||
- Fixed instability issues with cloned handles (bug 5245, bug 5240) (KyleS).
|
||||
- Changed extension unload order to avoid exposing finalization window (bug 5556) (KyleS).
|
||||
- Call OnPluginEnd before finalizer hooks have run (bug 4519).
|
||||
- Fixed potential for reading out of library bounds in MemoryUtils::FindPattern.
|
||||
- Fixed typo in TF2 ext asm.c causing accidental assignment instead of compare.
|
||||
- Overhauled versioning information (bug 5453).
|
||||
- Changed from RemoveEdict to using the Kill input for TF2_RemoveWeapon.
|
||||
- Fixed accidental assignment in each of SDKTools and sp compiler (bug 5745) (KyleS).
|
||||
- Fixed potential deadlock in HandleSystem::TryAndFreeSomeHandles (bug 5665) (KyleS).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.4.7 [2013-02-06]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.7_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM).
|
||||
- Updated gamedata for Left 4 Dead 2, Nuclear Dawn, No More Room in Hell, Zombie Panic Source, CSPromod, GoldenEye Source, Synergy, The Hidden, and PVKII.
|
||||
- Added system to block malware or illegal plugins (bug 5289).
|
||||
- Fixed a potential crash when a bad entity index is passed to certain functions (bug 5539) (KyleS).
|
||||
- Added an error message for when auto plugin configs fail to be created due to write error (bug 5465) (Drifter).
|
||||
- Fixed an issue where a malformed plugin could cause crashes (bug 5478).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new values to the TFCond TF2 conditions enum (bug 5537) (FlaminSarge).
|
||||
- Updated TFHoliday TF2 holidays enum (bug 5526) (Powerlord).
|
||||
- Fixed regression in SourceMod 1.3.0 causing GetEntPropEnt, GetEntDataEnt2, and GameRules_GetPropEnt to possibly return stale (incorrect) entity indexes in place of -1.
|
||||
- Added support for < 32-bit unsigned sign extension to GameRules_GetProp lookup (already in GetEntProp since SM 1.4.0).
|
||||
- Fixed < 32-bit unsigned sign extension in GetEntProp not being applied for array prop elements (bug 5591).
|
||||
- Fixed value size auto-detection in GetEntProp and GameRules_GetProp for ep2v's new SPROP_VARINT sendprops.
|
||||
- Fixed Sort_Random sort type not including first value in array sorting functions (bug 4292) (Peace-Maker).
|
||||
- Fixed GameRules_SetPropVector writing data to unexpected addresses instead of to the gamerules proxy entity (bug 5592) (ProdigySim).
|
||||
- Fixed VoteMenuToAll stock adding bots to list (bug 5253 (VoiDeD).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.4.6 [2012-09-04]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.6_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Fixed extraneous errors resulting from a bug in 1.4.5.
|
||||
|
||||
----------------------------------------------------------
|
||||
|
||||
SourceMod 1.4.5 [2012-09-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.5_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated Nuclear Dawn, Dino D-Day, and Zombie Panic gamedata.
|
||||
- Added compatibility for running on Metamod:Source 1.9.0.
|
||||
- Fixed very minor memory leaks in CStrike extension (bug 5456) (KyleS).
|
||||
- Fixed crash from plugins accessing netprops too early (bug 5297) (KyleS).
|
||||
- Fixed crash from plugins trying to access nested datadesc members (bug 5446).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new TF2 weapon and custom dmg defines.
|
||||
- Added new TF2 TFHoliday value (bug 5436) (Powerlord).
|
||||
- Fixed IClientListener::InterceptClientConnect not being able to properly block connections (bug 5461) (PimpinJuice).
|
||||
- Fixed PrepSDKCall_SetSignature native not working with symbol names on L4D2 linux (bug 5440).
|
||||
- Fixed resolution of GetProfilerTime native on non-Windows platforms.
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.4 [2012-07-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.4_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated Nuclear Dawn gamedata.
|
||||
- Fixed a crash that could occur when selecting an option on a clientprefs prefab menu (bug 5374).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new TF2 weapon and custom dmg defines.
|
||||
- Added new TF2 TFHoliday value (bug 5364) (Powerlord).
|
||||
- Updated sample extension to properly fill ninvoke with INativeInvoker ptr (bug 5340) (Afronanny).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.3 [2012-06-09]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.3_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Made clientprefs attempt to reconnect to the database on map change (bug 4745).
|
||||
- Log functions now respect sv_logecho (bug 5135).
|
||||
- Fixed client console vote output (bug 5290, bug 5205) (FlaminSarge).
|
||||
- Fixed error when reloading dependant plugins using aliased natives (bug 5302).
|
||||
- Fixed intermittent crash when looking for an invalid signature (bug 5301).
|
||||
- Fixed possible crash when reloading a plugin with an invalid binary (bug 5288).
|
||||
- Exposed extensions list to clients (bug 5221) (VoiDeD).
|
||||
- Fixed intermittent crashes in clientprefs (bug 4660).
|
||||
- Fixed crash when passing an invalid entity reference to ReferenceToEntity (bug 5330).
|
||||
- Fixed cstrike extension crash on shutdown (bug 5328).
|
||||
- Lowered threading API think time to 20ms, making threaded MySQL queries complete faster (bug 4733).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Fixed client serials not being unique on Windows (bug 5285).
|
||||
- Fixed broken SourceTV detection on L4D1 (bug 5216).
|
||||
- Fixed Float negation operator (bug 5292).
|
||||
- Updated TF2 condition defines (bug 5259) (FlaminSarge).
|
||||
- Adding missing SetMenuNoVoteButton native declaration (bug 4522) (GoD-Tony).
|
||||
- Fixed erroneous const-qualification of name param of GetAdminUsername (bug 5267).
|
||||
- Added GetGameTickCount native (bug 5209) (GoD-Tony).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.2 [2011-04-13]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Fixed regression in SourceMod 1.4.0 causing SM to cause load errors on The Ship (bug 5216).
|
||||
- Fixed toggling and player lag issues with sm_drug command (bugs 5217, 5218) (FlaminSarge).
|
||||
|
||||
Developer Changes:
|
||||
- Updated TF2-specific defines and enums (bug 5194).
|
||||
- Fixed StoreToAddress always writing 32 bits and throwing an error (bug 5248) (ProdigySim).
|
||||
- Fixed crash with StoreToAddress if memory wasn't writable (bug 5252) (Dr!fter).
|
||||
- Fixed return value of VoteMenuToAll (bug 5254) (VoiDeD).
|
||||
- Fixed bug in command lower-casing API guarantee
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.1 [2011-12-07]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Added gamedata for Adrenaline Gamer 2 and No More Room in Hell.
|
||||
- Fixed "not connected" error in reserve slots plugin (bug 5158) (ostrel).
|
||||
- Fixed ff trigger output printing to all in triggerer's language (rather than viewer's language) (bug 5161).
|
||||
- Fixed typo in one of basebans ban reasons (bug 5188).
|
||||
- Fixed formatting error in Swedish "Vote Count" phrase (bug 5174).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Fixed sp MaxClients not being updated on map changes after load (bug 5160).
|
||||
- Removed GLIBC_2.7 dependency from spcomp.
|
||||
- Increased buffer for sm_rcon command to fit larger responses (bug 5169).
|
||||
- BaseComm now properly registers a library allowing it to be required by other plugins (bug 5156).
|
||||
- Fixed TFHoliday enum values (bug 5155).
|
||||
- Updated TF2_OnIsHolidayActive ret behavior to match doc (bug 5155).
|
||||
- Added new TF2 deathflag and dmg custom defines (bug 5157).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.0 [2011-10-28]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.0_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added support for Max OS X (bug 4392).
|
||||
- Added support for Bloody Good Time (bug 4780).
|
||||
- Added support for E.Y.E Divine Cybermancy (bug 5035).
|
||||
- Added gamedata for Nuclear Dawn.
|
||||
- Added gamedata for International Online Soccer: Source (bug 5019).
|
||||
- Added gamedata for Half-Life 2 Capture the Flag (bug 5114).
|
||||
- Updated mapchooser and other base plugins with Nuclear Dawn specific fixes (bug 5117).
|
||||
- Fixed ServerLang value not being read properly on startup (bug 4675).
|
||||
- Added support for aliases in languages.cfg (bug 4858).
|
||||
- Added output display to sm_rcon command (bug 5018).
|
||||
- Flood protection bypass access can now be overridden with command name sm_flood_access (bug 4584).
|
||||
- Added a reset argument to sm cvars command to revset cvar values to default (bug 5043).
|
||||
- Fixed incorrect language identifiers for Chinese (both Trad. and Simplified) and Brazilian Portuguese not matching cl_language values (bug 5067).
|
||||
- Added translation support for Bulgarian (bg).
|
||||
- Fixed incorrect number of slots being hidden for reserve with sm_hideslots on Source 2009 with SourceTV or replay (bug 5094).
|
||||
- sm_hideslots changes now take effect immediately instead of waiting until a client joins or leaves (bug 5094).
|
||||
- Fixed sv_visiblemaxplayers getting stuck at previous max clients in some cases with reserves and SourceTV or replay (bug 5094).
|
||||
- Removed error logging if an optional extension is not found (bug 5112).
|
||||
- Fixed bots with semicolon in name being unkickable (bug 5120).
|
||||
- Changed strings in ice-related funcommands to be translatable (bug 4540).
|
||||
- Changed Bintools extension to use a single build for every engine (bug 4548).
|
||||
|
||||
Developer Changes:
|
||||
- Provided native interface for basecomm (bug 2594).
|
||||
- Client language detection is too late. (bug 3714) (Tony A. "GoD-Tony").
|
||||
- Added ServerCommandEx native to execute server command and retrieve output (bug 3873).
|
||||
- Added ability to update clientprefs cookies values on clients not currently connected (bug 3882) (databomb).
|
||||
- Added library "matchmaking_ds" support to gamedata lookups (bug 4158).
|
||||
- Rooted menu handles to callbacks (bug 4353).
|
||||
- Fixed corner cases with ExplodeString (bug 4629). (Michael "LumiStance").
|
||||
- Fixed return omission with else-after-return (bug 4852).
|
||||
- Added OnConditionAdded and OnConditionRemoved forwards to TF2 extension (bug 4851).
|
||||
- Added new natives and forward to the cstrike extension (bug 4732, bug 4985) (Dr!fter).
|
||||
- Added WaitingForPlayers forwards to the TF2 extension (bug 4704) (CrimsonGT).
|
||||
- Updated and added more TF2 condition, weapon, and damagecustom defines (multiple bug#s).
|
||||
- Fixed TF2_RemoveCondition not always removing conditions (bug 4981).
|
||||
- Fixed MaxClients not being updated correctly in some places with SourceTV or replay active (bug 4986).
|
||||
- Fixed some vars not being marked for init on first compile pass (bug 4643).
|
||||
- Increased symbol name limit to 63 characters (bug 4564) (javalia).
|
||||
- Fixed crash when dynamic arrays run out of memory (bug 4632).
|
||||
- Fixed a crash that could happen from looking up out-of-bounds edict or entity indexes (bug 5080).
|
||||
- Fixed client serials not getting cleared on disconnect (bug 5121).
|
||||
- Added error on declaring arrays that the compiler is too buggy to handle (bug 4977).
|
||||
- Removed reliance on gamedata for multiple SDKTools functions in ep2 and later (bug 4899).
|
||||
- Added InvalidateClient and ReconnectClient natives to SDKTools (bug 4931) (Brian "Afronanny" Simon).
|
||||
- Added ability to lookup and set values on the gamerules class (bug 4983.
|
||||
- BaseComm now uses AddCommandListener for chat hooks (bug 4991).
|
||||
- Fixed shutdown bug in SDKTools (bug 5063).
|
||||
- Fixed MM-enabled extensions continuing to load after failing MM attach (bug 5042).
|
||||
- Added GetDistGainFromSoundLevel native to SDKTools (bug 5066) (javalia).
|
||||
- Added CheckAccess native to check an AdminId's command access (bug 5083).
|
||||
- Fixed GetEntProp not sign-extending unsigned values less than 32 bits (bug 5105).
|
||||
- Fixed crashing when calling CreateEntityByName or CreateFakeClient when no map is running (now errors) (bug 5119).
|
||||
- Fixed erring in kick function (e. bad translation) causing client to become unkickable until disconnect (bug 5120).
|
||||
- Fixed KickClientEx not immediately kicking client if client was in kick queue (bug 5120).
|
||||
- Added IsClientSourceTV and IsClientReplay natives (bug 5124).
|
||||
- Added support for getting and setting individual array elements with Get/Set EntProp functions (bug 4160).
|
||||
- Added support for threaded query handles to SQL_GetInsertId and SQL_GetAffectedRows (bug 4699) (Nephyrin).
|
||||
- Added a GetGameRules function to ISDKTools for extensions to easily get the GameRules class pointer (bug 4707).
|
||||
- Added GetMessageName to IUserMessages (bug 4573) (Zach "theY4Kman" Kanzler)
|
||||
- Added HintTextMsg to IGameHelpers (bug 4950).
|
||||
- Added ProcessTargetString simple filter API (bug 4404).
|
||||
- Moved much functionality from core bins to logic bin (bug 4406, bug 4402).
|
||||
- Fixed bogus asserts in sp compiler (bug 4486, bug 4487).
|
||||
- Greatly improved sp compiler performance (~5x overall speedup) (bug 3820, bug 4493, bug 4495).
|
||||
- Changed entity output detours to use CDetour (bug 4416).
|
||||
- Enhanced nominations API (bug 4677) (CrimsonGT).
|
||||
- Added Linux support for profiling natives (bug 4927).
|
||||
- Added a new ValveCallType that allows for arbitrary |this| parameters, as well as associated features in gamedata and for reading/writing memory (bug 3520) (Downtown1).
|
||||
- Updated TF2 extension to handle Valve's changes to the "holiday" system (bug 5150).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.3.8 [2011-06-23]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.8_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated support for various games, including Garry's Mod, Zombie Panic, and Dino D-Day.
|
||||
- Added gamedata for Eternal Silence.
|
||||
- Fixed libgcc_s.so.1 load error present on some systems (bug 4876).
|
||||
- Handle leak notices now print to error log (in addition fatal log) (bug 4929).
|
||||
- Translator now properly falls back on bad server language (bug 4861).
|
||||
- Fixed invalid client errors from bad MaxClients value when SourceTV is late-loaded (bug 4881).
|
||||
- Fixed crash on plugin unload when two commands exist with same name, different casing (bug 4698).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Updated TF2 condition defines (bug 4916).
|
||||
- Fixed var names and docs for TF2_MakeBleed native (bug 4928).
|
||||
- Removed compiler double include check (bug 4863).
|
||||
- Fixed plugin compile errors when using GetEntityClassname (bug 4798).
|
||||
|
||||
---------------------------
|
||||
|
||||
SourceMod 1.3.7 [2011-04-15]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.7_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated support for various games, including Zombie Panic, CS ProMod, Empires, and GoldenEye: Source.
|
||||
- Added gamedata for Dino D-Day.
|
||||
- Fix precedence of voice mute flag versus specific client overrides (bug 4826).
|
||||
- Fix mistaken unhooking of voice hooks (bug 4804).
|
||||
- Fixed graphical glitches with funcommands effects in L4D1 (bug 3486).
|
||||
- Fixed bug in nominations that could cause "Unknown command" error (bug 4797).
|
||||
- Removed tv_enable hook to fix rare max client count issue (bug 4791).
|
||||
- Added missing unhooking of ClientConnect in PlayerManager (bug 4749).
|
||||
- Fixed sm_rtv printing "unknown command" (bug 4730).
|
||||
- Fixed voting crash when client console, chat, and SourceTV are enabled (bug 4676).
|
||||
- Fixed CDetour crash in TF2 extension when last plugin using forward is unloaded (bug 4713).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- SetEntProp now marks edict state as changed (bug 4855).
|
||||
- Added GetEntityClassname stock (bug 4798).
|
||||
- Fix compiler hanging when #including a directory (bug 4822).
|
||||
- Added GetEntityFlags and SetEntityFlags natives for better cross-engine compatibility. (bug 4809).
|
||||
- Fixed ClientPrefs natives not being marked optional when REQUIRE_EXTENSIONS not defined (bug 4839).
|
||||
- Changed some instances of LogMessage to LogAction (bug 4649).
|
||||
- Added some new language natives (bug 4613).
|
||||
- Fixed SetTeamScore not updating score on client (bug 2736).
|
||||
- Raised MAXPLAYERS from 64 to 65 (bug 4490).
|
||||
- Added and updated many TF2-specific defines in tf2.inc and tf2_stocks.inc.
|
||||
- Fixed TF2_GetPlayerConditionFlags no longer necessarily returning all set flags (bug 4726).
|
||||
- Fixed profiler flush not clearing, added 'report' and 'clear' (bug 4674).
|
||||
- Fixed GetPlayerDecalFile crash on L4D and L4D2 (bug 4729).
|
||||
- Fixed TF2_OnGetHoliday detour no longer firing under all circumstances (bug 4700).
|
||||
- Added TF2_IsPlayerInDuel native to TF2 extension (bug 4695).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.6 [2010-10-31]
|
||||
|
||||
@@ -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
|
||||
@@ -97,7 +93,7 @@ sm_hide_slots 0
|
||||
// Default: 1
|
||||
sm_chat_mode 1
|
||||
|
||||
// Specifies whether or not "timeleft" will automatically be triggered every
|
||||
// Specifies whether or not "timeleft" will automaticly be triggered every
|
||||
// x seconds. Valid values are 0 (Disabled) to 1800 seconds.
|
||||
// --
|
||||
// Requires: basetriggers.smx
|
||||
@@ -109,8 +105,8 @@ sm_timeleft_interval 0
|
||||
// 1 (Enabled)
|
||||
// --
|
||||
// Requires: basetriggers.smx
|
||||
// Default: 0
|
||||
sm_trigger_show 0
|
||||
// Default: 1
|
||||
sm_trigger_show 1
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// "hint" box (near the bottom of the screen in most games).
|
||||
|
||||
+22
-27
@@ -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
|
||||
@@ -114,28 +132,5 @@
|
||||
* 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"
|
||||
}
|
||||
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
+25
-40
@@ -1,49 +1,34 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
try:
|
||||
from ambuild2 import run, util
|
||||
from ambuild2 import run
|
||||
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)
|
||||
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)
|
||||
|
||||
# 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,
|
||||
run = run.PrepareBuild(sourcePath=sys.path[0])
|
||||
run.default_build_folder = 'obj-' + run.target_platform
|
||||
run.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||
help='Root search folder for HL2SDKs')
|
||||
run.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
|
||||
help='Path to MySQL 5')
|
||||
run.options.add_option('--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.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',
|
||||
run.options.add_option('--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.options.add_option('-s', '--sdks', default='all', dest='sdks',
|
||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
||||
'comma-delimited list of engine names (default: %default)')
|
||||
run.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
|
||||
default=False, help='Dump and upload breakpad symbols')
|
||||
run.Configure()
|
||||
|
||||
+56
-79
@@ -1,8 +1,7 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import os
|
||||
|
||||
project = builder.LibraryProject('sourcemod')
|
||||
|
||||
project = SM.HL2Project(builder, 'sourcemod')
|
||||
project.sources += [
|
||||
'MenuStyle_Valve.cpp',
|
||||
'logic_bridge.cpp',
|
||||
@@ -10,6 +9,8 @@ project.sources += [
|
||||
'sm_stringutil.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'smn_events.cpp',
|
||||
'smn_menus.cpp',
|
||||
'CDataPack.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
@@ -21,6 +22,7 @@ project.sources += [
|
||||
'NextMap.cpp',
|
||||
'ConCmdManager.cpp',
|
||||
'ConVarManager.cpp',
|
||||
'LibrarySys.cpp',
|
||||
'PlayerManager.cpp',
|
||||
'TimerSys.cpp',
|
||||
'CoreConfig.cpp',
|
||||
@@ -29,6 +31,7 @@ project.sources += [
|
||||
'smn_console.cpp',
|
||||
'UserMessages.cpp',
|
||||
'MenuManager.cpp',
|
||||
'smn_core.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
@@ -37,105 +40,79 @@ project.sources += [
|
||||
'EventManager.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'ConsoleDetours.cpp',
|
||||
'smn_commandline.cpp',
|
||||
'GameHooks.cpp',
|
||||
'sm_srvcmds.cpp',
|
||||
'ConsoleDetours.cpp'
|
||||
]
|
||||
|
||||
# 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)
|
||||
for sdk_name in SM.sdks:
|
||||
sdk = SM.sdks[sdk_name]
|
||||
binary_name = 'sourcemod.' + sdk.ext
|
||||
|
||||
binary = SM.HL2Config(project, binary_name, sdk)
|
||||
compiler = binary.compiler
|
||||
compiler.cxxincludes += [
|
||||
builder.sourcePath
|
||||
]
|
||||
|
||||
if needs_protobuf:
|
||||
if sdk.name == 'csgo':
|
||||
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')
|
||||
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', 'csgo', 'protobuf')
|
||||
]
|
||||
|
||||
if compiler.like('msvc'):
|
||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||
if cxx.target.platform == 'linux':
|
||||
elif sdk.name == 'dota':
|
||||
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', 'protobuf'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf')
|
||||
]
|
||||
|
||||
if builder.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':
|
||||
if sdk.name == 'csgo' or sdk.name == 'dota':
|
||||
if builder.target_platform == 'linux':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
|
||||
elif builder.target_platform == 'mac':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||
elif builder.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'
|
||||
if msvc_ver == 1800:
|
||||
vs_year = '2013'
|
||||
elif msvc_ver == 1700:
|
||||
vs_year = '2012'
|
||||
elif msvc_ver == 1600:
|
||||
vs_year = '2010'
|
||||
else:
|
||||
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
||||
raise Exception('Cannot find libprotobuf for MSVC version "' + compiler.version + '"')
|
||||
|
||||
if 'DEBUG' in compiler.defines:
|
||||
lib_path = os.path.join(sdk['path'], 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', '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:
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
compiler.linkflags.insert(0, binary.Dep(lib_path))
|
||||
|
||||
if sdk.name in ['csgo', 'dota']:
|
||||
binary.sources += ['smn_protobuf.cpp']
|
||||
else:
|
||||
binary.sources += ['smn_bitbuffer.cpp']
|
||||
|
||||
if sdk['name'] != 'blade':
|
||||
if sdk.name == 'csgo':
|
||||
binary.sources += [
|
||||
'vprof_tool.cpp',
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
||||
]
|
||||
|
||||
if needs_protobuf:
|
||||
elif sdk.name == 'dota':
|
||||
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'),
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'networkbasetypes.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'network_connection.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'ai_activity.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'usermessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_commonmessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_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)
|
||||
|
||||
|
||||
@@ -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,62 +1,71 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2019 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 <cstdlib>
|
||||
|
||||
#include "sm_platform.h"
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#error InvalidParameterHandler included in non-Windows build
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allows easy CRT invalid parameter redirection, previous handler is reset upon object destruction.
|
||||
*/
|
||||
class InvalidParameterHandler {
|
||||
public:
|
||||
InvalidParameterHandler() {
|
||||
this->old = _set_invalid_parameter_handler([](const wchar_t * expression, const wchar_t * function, const wchar_t * file, unsigned int line, uintptr_t pReserved) {
|
||||
return;
|
||||
});
|
||||
}
|
||||
InvalidParameterHandler(_invalid_parameter_handler newhandler) {
|
||||
this->old = _set_invalid_parameter_handler(newhandler);
|
||||
}
|
||||
~InvalidParameterHandler() {
|
||||
_set_invalid_parameter_handler(this->old);
|
||||
}
|
||||
|
||||
// explicitly disable copy cstr and assignment
|
||||
InvalidParameterHandler(const InvalidParameterHandler &) = delete;
|
||||
InvalidParameterHandler& operator=(const InvalidParameterHandler &) = delete;
|
||||
|
||||
private:
|
||||
_invalid_parameter_handler old;
|
||||
};
|
||||
/**
|
||||
* 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_CDATAPACK_H_
|
||||
#define _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
|
||||
#include <IDataPack.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
class CDataPack : public IDataPack
|
||||
{
|
||||
public:
|
||||
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 Initialize();
|
||||
private:
|
||||
void CheckSize(size_t sizetype);
|
||||
private:
|
||||
char *m_pBase;
|
||||
mutable char *m_curptr;
|
||||
size_t m_capacity;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
@@ -44,7 +44,11 @@ public: //IRecipientFilter
|
||||
bool IsReliable() const;
|
||||
bool IsInitMessage() const;
|
||||
int GetRecipientCount() const;
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
CEntityIndex GetRecipientIndex(int slot) const;
|
||||
#else
|
||||
int GetRecipientIndex(int slot) const;
|
||||
#endif
|
||||
public:
|
||||
void Initialize(const cell_t *ptr, size_t count);
|
||||
void SetToReliable(bool isreliable);
|
||||
@@ -79,7 +83,11 @@ inline int CellRecipientFilter::GetRecipientCount() const
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
inline CEntityIndex CellRecipientFilter::GetRecipientIndex(int slot) const
|
||||
#else
|
||||
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
|
||||
#endif
|
||||
{
|
||||
int ret;
|
||||
if ((slot < 0) || (slot >= GetRecipientCount()))
|
||||
@@ -91,7 +99,11 @@ inline int CellRecipientFilter::GetRecipientIndex(int slot) const
|
||||
ret = static_cast<int>(m_Players[slot]);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
return CEntityIndex(ret);
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
|
||||
|
||||
+164
-116
@@ -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,8 +29,6 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <ITextParsers.h>
|
||||
#include "ChatTriggers.h"
|
||||
#include "sm_stringutil.h"
|
||||
@@ -39,18 +37,32 @@
|
||||
#include "HalfLife2.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "sourcemod.h"
|
||||
#include "provider.h"
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
#else
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
ChatTriggers g_ChatTriggers;
|
||||
bool g_bSupressSilentFails = false;
|
||||
|
||||
ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false),
|
||||
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
|
||||
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
|
||||
{
|
||||
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
|
||||
@@ -60,47 +72,32 @@ ChatTriggers::ChatTriggers() : m_bWillProcessInPost(false),
|
||||
|
||||
ChatTriggers::~ChatTriggers()
|
||||
{
|
||||
delete [] m_PubTrigger;
|
||||
m_PubTrigger = NULL;
|
||||
delete [] m_PrivTrigger;
|
||||
m_PrivTrigger = NULL;
|
||||
delete [] m_ArgSBackup;
|
||||
m_ArgSBackup = 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)
|
||||
@@ -127,43 +124,70 @@ void ChatTriggers::OnSourceModAllInitialized_Post()
|
||||
|
||||
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(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(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(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(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));
|
||||
|
||||
if (m_bIsINS)
|
||||
{
|
||||
m_pSay2Cmd = FindCommand("say2");
|
||||
if (m_pSay2Cmd)
|
||||
{
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
}
|
||||
#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));
|
||||
m_pSaySquadCmd = FindCommand("say_squad");
|
||||
|
||||
if (m_pSaySquadCmd)
|
||||
{
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModShutdown()
|
||||
{
|
||||
hooks_.clear();
|
||||
if (m_pSayCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
}
|
||||
|
||||
if (m_pSayTeamCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (m_bIsINS && m_pSay2Cmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
if (m_pSaySquadCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
forwardsys->ReleaseForward(m_pShouldFloodBlock);
|
||||
forwardsys->ReleaseForward(m_pDidFloodBlock);
|
||||
@@ -171,20 +195,32 @@ void ChatTriggers::OnSourceModShutdown()
|
||||
forwardsys->ReleaseForward(m_pOnClientSayCmd_Post);
|
||||
}
|
||||
|
||||
bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void ChatTriggers::OnSayCommand_Pre(const CCommandContext &context, const CCommand &command)
|
||||
{
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
void ChatTriggers::OnSayCommand_Pre()
|
||||
{
|
||||
CCommand command;
|
||||
#endif
|
||||
int client = g_ConCmds.GetCommandClient();
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
m_bPluginIgnored = true;
|
||||
|
||||
const char *args = command->ArgS();
|
||||
const char *args = command.ArgS();
|
||||
|
||||
if (!args)
|
||||
return false;
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/* Save these off for post hook as the command data returned from the engine in older engine versions
|
||||
/* 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);
|
||||
m_Arg0Backup = command.Arg(0);
|
||||
size_t len = strlen(args);
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
@@ -197,7 +233,9 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
return true;
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -208,14 +246,16 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
|
||||
if (
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
!m_bIsINS &&
|
||||
!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;
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
args++;
|
||||
len--;
|
||||
@@ -244,16 +284,20 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
if (client == 0)
|
||||
{
|
||||
if (CallOnClientSayCommand(client) >= Pl_Handled)
|
||||
return true;
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
return false;
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
|
||||
/* We guarantee the client is connected */
|
||||
if (!pPlayer || !pPlayer->IsConnected())
|
||||
return false;
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/* Check if we need to block this message from being sent */
|
||||
if (ClientIsFlooding(client))
|
||||
@@ -261,32 +305,33 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
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!");
|
||||
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);
|
||||
}
|
||||
|
||||
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(m_ArgSBackup, m_PubTrigger, m_PubTriggerSize) == 0)
|
||||
{
|
||||
is_trigger = true;
|
||||
args = &m_ArgSBackup[m_PubTriggerSize];
|
||||
}
|
||||
else if (m_PrivTriggerSize && strncmp(m_ArgSBackup, m_PrivTrigger, m_PrivTriggerSize) == 0)
|
||||
{
|
||||
is_trigger = true;
|
||||
is_silent = true;
|
||||
} else if (strchr(m_PubTrigger.c_str(), m_ArgSBackup[0])) {
|
||||
is_trigger = true;
|
||||
}
|
||||
|
||||
if (is_trigger) {
|
||||
// Bump the args past the chat trigger - we only support single-character triggers now.
|
||||
args = &m_ArgSBackup[1];
|
||||
args = &m_ArgSBackup[m_PrivTriggerSize];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,17 +348,29 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
||||
}
|
||||
|
||||
if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
|
||||
return true;
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
if (CallOnClientSayCommand(client) >= Pl_Handled)
|
||||
return true;
|
||||
{
|
||||
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_DOTA
|
||||
void ChatTriggers::OnSayCommand_Post(const CCommandContext &context, const CCommand &command)
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
|
||||
#else
|
||||
void ChatTriggers::OnSayCommand_Post()
|
||||
#endif
|
||||
{
|
||||
int client = g_ConCmds.GetCommandClient();
|
||||
|
||||
if (m_bWillProcessInPost)
|
||||
{
|
||||
/* Reset this for re-entrancy */
|
||||
@@ -321,7 +378,11 @@ bool ChatTriggers::OnSayCommand_Post(int client, const ICommandArgs *command)
|
||||
|
||||
/* Execute the cached command */
|
||||
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
engine->ClientCommand(client, "%s", m_ToExecute);
|
||||
#else
|
||||
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
|
||||
#endif
|
||||
SetReplyTo(old);
|
||||
}
|
||||
|
||||
@@ -335,17 +396,16 @@ bool ChatTriggers::OnSayCommand_Post(int client, const ICommandArgs *command)
|
||||
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
||||
{
|
||||
/* 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,17 +423,17 @@ 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))
|
||||
@@ -387,9 +447,17 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
||||
/* See if we need to do extra string manipulation */
|
||||
if (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));
|
||||
}
|
||||
} else {
|
||||
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
||||
strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -461,23 +529,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();
|
||||
}
|
||||
|
||||
+26
-19
@@ -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,34 +48,43 @@ 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_DOTA
|
||||
void OnSayCommand_Pre(const CCommandContext &, const CCommand &command);
|
||||
void OnSayCommand_Post(const CCommandContext &, const CCommand &command);
|
||||
#elif 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 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;
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
ConCommand *m_pSay2Cmd;
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
ConCommand *m_pSaySquadCmd;
|
||||
#endif
|
||||
char *m_PubTrigger;
|
||||
size_t m_PubTriggerSize;
|
||||
char *m_PrivTrigger;
|
||||
size_t m_PrivTriggerSize;
|
||||
bool m_bWillProcessInPost;
|
||||
bool m_bIsChatTrigger;
|
||||
bool m_bWasFloodedMessage;
|
||||
|
||||
+133
-79
@@ -30,26 +30,33 @@
|
||||
*/
|
||||
|
||||
#include "ConCmdManager.h"
|
||||
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include "ChatTriggers.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "command_args.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "provider.h"
|
||||
#include "sm_srvcmds.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemod.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "ChatTriggers.h"
|
||||
#include "logic_bridge.h"
|
||||
|
||||
using namespace ke;
|
||||
|
||||
ConCmdManager g_ConCmds;
|
||||
|
||||
typedef std::list<CmdHook *> PluginHookList;
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
SH_DECL_HOOK2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||
#elif 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);
|
||||
|
||||
typedef ke::LinkedList<CmdHook *> PluginHookList;
|
||||
void RegisterInPlugin(CmdHook *hook);
|
||||
|
||||
ConCmdManager::ConCmdManager()
|
||||
{
|
||||
m_CmdClient = 0;
|
||||
}
|
||||
|
||||
ConCmdManager::~ConCmdManager()
|
||||
@@ -59,16 +66,19 @@ ConCmdManager::~ConCmdManager()
|
||||
void ConCmdManager::OnSourceModAllInitialized()
|
||||
{
|
||||
scripts->AddPluginsListener(this);
|
||||
rootmenu->AddRootConsoleCommand3("cmds", "List console commands", this);
|
||||
g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this);
|
||||
SH_ADD_HOOK(IServerGameClients, SetCommandClient, serverClients, SH_MEMBER(this, &ConCmdManager::SetCommandClient), false);
|
||||
}
|
||||
|
||||
void ConCmdManager::OnSourceModShutdown()
|
||||
{
|
||||
scripts->RemovePluginsListener(this);
|
||||
rootmenu->RemoveRootConsoleCommand("cmds", this);
|
||||
/* All commands should already be removed by the time we're done */
|
||||
SH_REMOVE_HOOK(IServerGameClients, SetCommandClient, serverClients, SH_MEMBER(this, &ConCmdManager::SetCommandClient), false);
|
||||
g_RootMenu.RemoveRootConsoleCommand("cmds", this);
|
||||
}
|
||||
|
||||
void ConCmdManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name)
|
||||
void ConCmdManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
|
||||
{
|
||||
/* Whoa, first get its information struct */
|
||||
ConCmdInfo *pInfo;
|
||||
@@ -103,7 +113,7 @@ void ConCmdManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
||||
delete hook;
|
||||
}
|
||||
|
||||
RemoveConCmd(pInfo, name, false);
|
||||
RemoveConCmd(pInfo, name, is_read_safe, false);
|
||||
}
|
||||
|
||||
void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
|
||||
@@ -121,13 +131,8 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
|
||||
if (hook->admin)
|
||||
hook->admin->group->hooks.remove(hook);
|
||||
|
||||
if (hook->info->hooks.empty()) {
|
||||
RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true);
|
||||
}
|
||||
else { // update plugin reference to next hook in line
|
||||
auto next = *hook->info->hooks.begin();
|
||||
next->info->pPlugin = next->plugin;
|
||||
}
|
||||
if (hook->info->hooks.empty())
|
||||
RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true, true);
|
||||
|
||||
iter = pList->erase(iter);
|
||||
delete hook;
|
||||
@@ -136,13 +141,28 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
|
||||
delete pList;
|
||||
}
|
||||
|
||||
void CommandCallback(DISPATCH_ARGS)
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void CommandCallback(const CCommandContext &context, const CCommand &command)
|
||||
{
|
||||
DISPATCH_PROLOGUE;
|
||||
EngineArgs args(command);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CommandCallback(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
void CommandCallback()
|
||||
{
|
||||
CCommand command;
|
||||
#endif
|
||||
|
||||
AutoEnterCommand autoEnterCommand(&args);
|
||||
g_ConCmds.InternalDispatch(sCoreProviderImpl.CommandClient(), &args);
|
||||
g_HL2.PushCommandStack(&command);
|
||||
|
||||
g_ConCmds.InternalDispatch(command);
|
||||
|
||||
g_HL2.PopCommandStack();
|
||||
}
|
||||
|
||||
void ConCmdManager::SetCommandClient(int client)
|
||||
{
|
||||
m_CmdClient = client + 1;
|
||||
}
|
||||
|
||||
ConCmdInfo *ConCmdManager::FindInTrie(const char *name)
|
||||
@@ -153,13 +173,30 @@ ConCmdInfo *ConCmdManager::FindInTrie(const char *name)
|
||||
return pInfo;
|
||||
}
|
||||
|
||||
ConCmdList::iterator ConCmdManager::FindInList(const char *cmd)
|
||||
{
|
||||
List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
|
||||
|
||||
while (iter != m_CmdList.end())
|
||||
{
|
||||
if (strcasecmp((*iter)->pCmd->GetName(), cmd) == 0)
|
||||
break;
|
||||
iter++;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
|
||||
{
|
||||
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||
ConCmdInfo *pInfo;
|
||||
|
||||
if (pInfo == NULL)
|
||||
if ((pInfo = FindInTrie(cmd)) == NULL)
|
||||
{
|
||||
return type;
|
||||
ConCmdList::iterator item = FindInList(cmd);
|
||||
if (item == m_CmdList.end())
|
||||
return type;
|
||||
pInfo = *item;
|
||||
}
|
||||
|
||||
cell_t result = type;
|
||||
@@ -170,7 +207,7 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int
|
||||
if (hook->type == CmdHook::Server || !hook->pf->IsRunnable())
|
||||
continue;
|
||||
|
||||
if (hook->admin && !CheckAccess(client, cmd, hook->admin.get()))
|
||||
if (hook->admin && !CheckAccess(client, cmd, hook->admin))
|
||||
{
|
||||
if (result < Pl_Handled)
|
||||
result = Pl_Handled;
|
||||
@@ -181,7 +218,6 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int
|
||||
hook->pf->PushCell(args);
|
||||
|
||||
cell_t tempres = result;
|
||||
|
||||
if (hook->pf->Execute(&tempres) == SP_ERROR_NONE)
|
||||
{
|
||||
if (tempres > result)
|
||||
@@ -194,13 +230,15 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int
|
||||
return (ResultType)result;
|
||||
}
|
||||
|
||||
bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
||||
void ConCmdManager::InternalDispatch(const CCommand &command)
|
||||
{
|
||||
int client = m_CmdClient;
|
||||
|
||||
if (client)
|
||||
{
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
if (!pPlayer || !pPlayer->IsConnected())
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,7 +252,17 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
||||
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||
if (pInfo == NULL)
|
||||
{
|
||||
return false;
|
||||
/* Unfortunately, we now have to do a slow lookup because Valve made client commands
|
||||
* case-insensitive. We can't even use our sortedness.
|
||||
*/
|
||||
if (client == 0 && !engine->IsDedicatedServer())
|
||||
return;
|
||||
|
||||
ConCmdList::iterator item = FindInList(cmd);
|
||||
if (item == m_CmdList.end())
|
||||
return;
|
||||
|
||||
pInfo = *item;
|
||||
}
|
||||
|
||||
/* This is a hack to prevent say triggers from firing on messages that were
|
||||
@@ -222,10 +270,10 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
||||
* "nicer" when we expose explicit say hooks.
|
||||
*/
|
||||
if (g_ChatTriggers.WasFloodedMessage())
|
||||
return false;
|
||||
return;
|
||||
|
||||
cell_t result = Pl_Continue;
|
||||
int argc = args->ArgC() - 1;
|
||||
int args = command.ArgC() - 1;
|
||||
|
||||
// On a listen server, sometimes the server host's client index can be set
|
||||
// as 0. So index 1 is passed to the command callback to correct this
|
||||
@@ -250,7 +298,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
||||
} else {
|
||||
// Check admin rights if needed. realClient isn't needed since we
|
||||
// should bypass admin checks if client == 0 anyway.
|
||||
if (client && hook->admin && !CheckAccess(client, cmd, hook->admin.get()))
|
||||
if (client && hook->admin && !CheckAccess(client, cmd, hook->admin))
|
||||
{
|
||||
if (result < Pl_Handled)
|
||||
result = Pl_Handled;
|
||||
@@ -261,7 +309,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
||||
hook->pf->PushCell(realClient);
|
||||
}
|
||||
|
||||
hook->pf->PushCell(argc);
|
||||
hook->pf->PushCell(args);
|
||||
|
||||
cell_t tempres = result;
|
||||
if (hook->pf->Execute(&tempres) == SP_ERROR_NONE)
|
||||
@@ -274,9 +322,11 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
||||
}
|
||||
|
||||
if (result >= Pl_Handled)
|
||||
return !pInfo->sourceMod;
|
||||
|
||||
return false;
|
||||
{
|
||||
if (!pInfo->sourceMod)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin)
|
||||
@@ -296,20 +346,20 @@ bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmi
|
||||
char buffer[128];
|
||||
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "No Access", &client))
|
||||
{
|
||||
ke::SafeStrcpy(buffer, sizeof(buffer), "You do not have access to this command");
|
||||
UTIL_Format(buffer, sizeof(buffer), "You do not have access to this command");
|
||||
}
|
||||
|
||||
unsigned int replyto = g_ChatTriggers.GetReplyTo();
|
||||
if (replyto == SM_REPLY_CONSOLE)
|
||||
{
|
||||
char fullbuffer[192];
|
||||
ke::SafeSprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer);
|
||||
UTIL_Format(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer);
|
||||
pPlayer->PrintToConsole(fullbuffer);
|
||||
}
|
||||
else if (replyto == SM_REPLY_CHAT)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -321,10 +371,9 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
||||
const char *group,
|
||||
int adminflags,
|
||||
const char *description,
|
||||
int flags,
|
||||
IPlugin *pPlugin)
|
||||
int flags)
|
||||
{
|
||||
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin);
|
||||
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
|
||||
|
||||
if (!pInfo)
|
||||
return false;
|
||||
@@ -334,12 +383,12 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
||||
{
|
||||
if (!m_CmdGrps.add(i, group))
|
||||
return false;
|
||||
i->value = new CommandGroup();
|
||||
i->value = NoAddRef(new CommandGroup());
|
||||
}
|
||||
RefPtr<CommandGroup> cmdgroup = i->value;
|
||||
Ref<CommandGroup> cmdgroup = i->value;
|
||||
|
||||
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description, pPlugin);
|
||||
pHook->admin = std::make_unique<AdminCmdInfo>(cmdgroup, adminflags);
|
||||
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description);
|
||||
pHook->admin = new AdminCmdInfo(cmdgroup, adminflags);
|
||||
|
||||
/* First get the command group override, if any */
|
||||
bool override = adminsys->GetCommandOverride(group,
|
||||
@@ -359,7 +408,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
||||
pHook->admin->eflags = pHook->admin->flags;
|
||||
pInfo->eflags = pHook->admin->eflags;
|
||||
|
||||
cmdgroup->hooks.push_back(pHook);
|
||||
cmdgroup->hooks.append(pHook);
|
||||
pInfo->hooks.append(pHook);
|
||||
RegisterInPlugin(pHook);
|
||||
return true;
|
||||
@@ -368,16 +417,15 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
||||
bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
|
||||
const char *name,
|
||||
const char *description,
|
||||
int flags,
|
||||
IPlugin *pPlugin)
|
||||
int flags)
|
||||
|
||||
{
|
||||
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags, pPlugin);
|
||||
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
|
||||
|
||||
if (!pInfo)
|
||||
return false;
|
||||
|
||||
CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description, pPlugin);
|
||||
CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description);
|
||||
|
||||
pInfo->hooks.append(pHook);
|
||||
RegisterInPlugin(pHook);
|
||||
@@ -404,13 +452,13 @@ void RegisterInPlugin(CmdHook *hook)
|
||||
const char *cmd = (*iter)->info->pCmd->GetName();
|
||||
if (strcmp(orig, cmd) < 0)
|
||||
{
|
||||
pList->emplace(iter, hook);
|
||||
pList->insertBefore(iter, hook);
|
||||
return;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
pList->emplace_back(hook);
|
||||
pList->append(hook);
|
||||
}
|
||||
|
||||
void ConCmdManager::AddToCmdList(ConCmdInfo *info)
|
||||
@@ -469,12 +517,12 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
|
||||
if (!r.found())
|
||||
return;
|
||||
|
||||
RefPtr<CommandGroup> group(r->value);
|
||||
Ref<CommandGroup> group(r->value);
|
||||
|
||||
for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++)
|
||||
{
|
||||
CmdHook *hook = *iter;
|
||||
if (!remove)
|
||||
if (remove)
|
||||
hook->admin->eflags = bits;
|
||||
else
|
||||
hook->admin->eflags = hook->admin->flags;
|
||||
@@ -483,7 +531,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
|
||||
}
|
||||
}
|
||||
|
||||
void ConCmdManager::RemoveConCmd(ConCmdInfo *info, const char *name, bool untrack)
|
||||
void ConCmdManager::RemoveConCmd(ConCmdInfo *info, const char *name, bool is_read_safe, bool untrack)
|
||||
{
|
||||
/* Remove from the trie */
|
||||
m_Cmds.remove(name);
|
||||
@@ -506,8 +554,15 @@ void ConCmdManager::RemoveConCmd(ConCmdInfo *info, const char *name, bool untrac
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_read_safe)
|
||||
{
|
||||
/* Remove the external hook */
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, info->pCmd, SH_STATIC(CommandCallback), false);
|
||||
}
|
||||
if (untrack)
|
||||
{
|
||||
UntrackConCommandBase(info->pCmd, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,11 +591,15 @@ bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags)
|
||||
return true;
|
||||
}
|
||||
|
||||
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags, IPlugin *pPlugin)
|
||||
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
|
||||
{
|
||||
ConCmdInfo *pInfo;
|
||||
if (!m_Cmds.retrieve(name, &pInfo))
|
||||
{
|
||||
ConCmdList::iterator item = FindInList(name);
|
||||
if (item != m_CmdList.end())
|
||||
return *item;
|
||||
|
||||
pInfo = new ConCmdInfo();
|
||||
/* Find the commandopan */
|
||||
ConCommand *pCmd = FindCommand(name);
|
||||
@@ -557,17 +616,12 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
|
||||
char *new_name = sm_strdup(name);
|
||||
char *new_help = sm_strdup(description);
|
||||
pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
|
||||
pInfo->pPlugin = pPlugin;
|
||||
pInfo->sourceMod = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrackConCommandBase(pCmd, this);
|
||||
CommandHook::Callback callback = [this] (int client, const ICommandArgs *args) -> bool {
|
||||
AutoEnterCommand autoEnterCommand(args);
|
||||
return this->InternalDispatch(client, args);
|
||||
};
|
||||
pInfo->sh_hook = sCoreProviderImpl.AddCommandHook(pCmd, callback);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CommandCallback), false);
|
||||
}
|
||||
|
||||
pInfo->pCmd = pCmd;
|
||||
@@ -579,17 +633,17 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
|
||||
return pInfo;
|
||||
}
|
||||
|
||||
void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command)
|
||||
void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||
{
|
||||
if (command->ArgC() >= 3)
|
||||
if (command.ArgC() >= 3)
|
||||
{
|
||||
const char *text = command->Arg(2);
|
||||
const char *text = command.Arg(2);
|
||||
|
||||
IPlugin *pPlugin = scripts->FindPluginByConsoleArg(text);
|
||||
|
||||
if (!pPlugin)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Plugin \"%s\" was not found.", text);
|
||||
g_RootMenu.ConsolePrint("[SM] Plugin \"%s\" was not found.", text);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -599,20 +653,20 @@ void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
||||
PluginHookList *pList;
|
||||
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] No commands found for: %s", plname);
|
||||
g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname);
|
||||
return;
|
||||
}
|
||||
if (pList->empty())
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] No commands found for: %s", plname);
|
||||
g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *type = NULL;
|
||||
const char *name;
|
||||
const char *help;
|
||||
UTIL_ConsolePrint("[SM] Listing commands for: %s", plname);
|
||||
UTIL_ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]");
|
||||
g_RootMenu.ConsolePrint("[SM] Listing commands for: %s", plname);
|
||||
g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]");
|
||||
for (PluginHookList::iterator iter = pList->begin(); iter != pList->end(); iter++)
|
||||
{
|
||||
CmdHook *hook = *iter;
|
||||
@@ -623,14 +677,14 @@ void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
||||
|
||||
name = hook->info->pCmd->GetName();
|
||||
if (hook->helptext.length())
|
||||
help = hook->helptext.c_str();
|
||||
help = hook->helptext.chars();
|
||||
else
|
||||
help = hook->info->pCmd->GetHelpText();
|
||||
UTIL_ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
|
||||
g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UTIL_ConsolePrint("[SM] Usage: sm cmds <plugin #>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm cmds <plugin #>");
|
||||
}
|
||||
|
||||
+39
-53
@@ -32,14 +32,6 @@
|
||||
#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>
|
||||
@@ -48,8 +40,11 @@
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <IAdminSystem.h>
|
||||
#include "concmd_cleaner.h"
|
||||
#include "GameHooks.h"
|
||||
#include <sm_namehashset.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <am-utility.h>
|
||||
#include <am-inlinelist.h>
|
||||
#include <am-linkedlist.h>
|
||||
#include <am-refcounting.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@@ -58,18 +53,18 @@ struct ConCmdInfo;
|
||||
|
||||
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
||||
{
|
||||
std::list<CmdHook *> hooks;
|
||||
ke::LinkedList<CmdHook *> hooks;
|
||||
};
|
||||
|
||||
struct AdminCmdInfo
|
||||
{
|
||||
AdminCmdInfo(const ke::RefPtr<CommandGroup> &group, FlagBits flags)
|
||||
AdminCmdInfo(const ke::Ref<CommandGroup> &group, FlagBits flags)
|
||||
: group(group),
|
||||
flags(flags),
|
||||
eflags(0)
|
||||
{
|
||||
}
|
||||
ke::RefPtr<CommandGroup> group;
|
||||
ke::Ref<CommandGroup> group;
|
||||
FlagBits flags; /* default flags */
|
||||
FlagBits eflags; /* effective flags */
|
||||
};
|
||||
@@ -81,11 +76,10 @@ struct CmdHook : public ke::InlineListNode<CmdHook>
|
||||
Client
|
||||
};
|
||||
|
||||
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description, IPlugin *plugin)
|
||||
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description)
|
||||
: type(type),
|
||||
info(cmd),
|
||||
pf(fun),
|
||||
plugin(plugin),
|
||||
helptext(description)
|
||||
{
|
||||
}
|
||||
@@ -93,9 +87,8 @@ struct CmdHook : public ke::InlineListNode<CmdHook>
|
||||
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 */
|
||||
ke::AString helptext; /* help text */
|
||||
ke::AutoPtr<AdminCmdInfo> admin; /* admin requirements, if any */
|
||||
};
|
||||
|
||||
typedef ke::InlineList<CmdHook> CmdHookList;
|
||||
@@ -104,37 +97,14 @@ struct ConCmdInfo
|
||||
{
|
||||
ConCmdInfo()
|
||||
{
|
||||
pPlugin = nullptr;
|
||||
sourceMod = false;
|
||||
pCmd = nullptr;
|
||||
pCmd = NULL;
|
||||
eflags = 0;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
typedef List<ConCmdInfo *> ConCmdList;
|
||||
@@ -145,7 +115,13 @@ class ConCmdManager :
|
||||
public IPluginsListener,
|
||||
public IConCommandTracker
|
||||
{
|
||||
friend void CommandCallback(DISPATCH_ARGS);
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
friend void CommandCallback(const CCommandContext &context, const CCommand &command);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
friend void CommandCallback(const CCommand &command);
|
||||
#else
|
||||
friend void CommandCallback();
|
||||
#endif
|
||||
public:
|
||||
ConCmdManager();
|
||||
~ConCmdManager();
|
||||
@@ -155,41 +131,51 @@ 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 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);
|
||||
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);
|
||||
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
||||
|
||||
// Case insensitive
|
||||
ConCmdList::iterator FindInList(const char *name);
|
||||
|
||||
// Case sensitive
|
||||
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;
|
||||
typedef StringHashMap<ke::Ref<CommandGroup> > GroupMap;
|
||||
|
||||
NameHashSet<ConCmdInfo *, ConCmdInfo::ConCmdPolicy> m_Cmds; /* command lookup */
|
||||
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */
|
||||
GroupMap m_CmdGrps; /* command group map */
|
||||
ConCmdList m_CmdList; /* command list */
|
||||
int m_CmdClient; /* current client */
|
||||
};
|
||||
|
||||
extern ConCmdManager g_ConCmds;
|
||||
|
||||
+166
-74
@@ -29,23 +29,31 @@
|
||||
|
||||
#include "ConVarManager.h"
|
||||
#include "HalfLife2.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>
|
||||
|
||||
ConVarManager g_ConVarManager;
|
||||
|
||||
#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_DOTA
|
||||
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
|
||||
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
|
||||
#elif 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;
|
||||
|
||||
enum {
|
||||
eQueryCvarValueStatus_Cancelled = -1,
|
||||
};
|
||||
NameHashSet<ConVarInfo *> convar_cache;
|
||||
|
||||
class ConVarReentrancyGuard
|
||||
{
|
||||
@@ -81,7 +89,7 @@ public:
|
||||
|
||||
ConVarReentrancyGuard *ConVarReentrancyGuard::chain = NULL;
|
||||
|
||||
ConVarManager::ConVarManager() : m_ConVarType(0)
|
||||
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -104,12 +112,29 @@ void ConVarManager::OnSourceModStartup(bool late)
|
||||
|
||||
void ConVarManager::OnSourceModAllInitialized()
|
||||
{
|
||||
/**
|
||||
* 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(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||
m_bIsDLLQueryHooked = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_Players.AddClientListener(this);
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
|
||||
#else
|
||||
SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
|
||||
#endif
|
||||
|
||||
scripts->AddPluginsListener(this);
|
||||
|
||||
/* 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()
|
||||
@@ -155,10 +180,32 @@ void ConVarManager::OnSourceModShutdown()
|
||||
}
|
||||
convar_cache.clear();
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
/* Unhook things */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
SH_REMOVE_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||
m_bIsDLLQueryHooked = false;
|
||||
}
|
||||
else if (m_bIsVSPQueryHooked)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DOTA
|
||||
SH_REMOVE_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||
#endif
|
||||
m_bIsVSPQueryHooked = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_Players.RemoveClientListener(this);
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
|
||||
#else
|
||||
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
|
||||
#endif
|
||||
|
||||
/* Remove the 'convars' option from the 'sm' console command */
|
||||
rootmenu->RemoveRootConsoleCommand("cvars", this);
|
||||
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
|
||||
|
||||
scripts->RemovePluginsListener(this);
|
||||
|
||||
@@ -166,12 +213,45 @@ void ConVarManager::OnSourceModShutdown()
|
||||
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 || PLAPI_VERSION >= 11
|
||||
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 && SOURCE_ENGINE != SE_DOTA
|
||||
SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||
m_bIsVSPQueryHooked = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
|
||||
{
|
||||
return convar_cache.retrieve(name, pVar);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -210,27 +290,18 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
ConVarList *pConVarList;
|
||||
List<ConVarQuery>::iterator iter;
|
||||
|
||||
/* 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();)
|
||||
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||
{
|
||||
ConVarQuery &query = (*iter);
|
||||
if (query.pCallback->GetParentRuntime() == pRuntime)
|
||||
@@ -251,19 +322,6 @@ void ConVarManager::OnClientDisconnected(int client)
|
||||
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;
|
||||
}
|
||||
@@ -282,19 +340,19 @@ 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);
|
||||
const char *arg = command.Arg(2);
|
||||
if (argcount >= 4 && strcmp(arg, "reset") == 0)
|
||||
{
|
||||
wantReset = true;
|
||||
arg = command->Arg(3);
|
||||
arg = command.Arg(3);
|
||||
}
|
||||
|
||||
/* Get plugin object */
|
||||
@@ -302,7 +360,7 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
||||
|
||||
if (!plugin)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Plugin \"%s\" was not found.", arg);
|
||||
g_RootMenu.ConsolePrint("[SM] Plugin \"%s\" was not found.", arg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -316,14 +374,14 @@ 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]");
|
||||
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/reset each one */
|
||||
@@ -332,7 +390,7 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
||||
/*const */ConVar *pConVar = const_cast<ConVar *>(*iter);
|
||||
if (!wantReset)
|
||||
{
|
||||
UTIL_ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
||||
} else {
|
||||
pConVar->Revert();
|
||||
}
|
||||
@@ -340,14 +398,14 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
||||
|
||||
if (wantReset)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] Reset %d convars for: %s", pConVarList->size(), plname);
|
||||
g_RootMenu.ConsolePrint("[SM] Reset %d convars for: %s", pConVarList->size(), plname);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Display usage of subcommand */
|
||||
UTIL_ConsolePrint("[SM] Usage: sm cvars [reset] <plugin #>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm cvars [reset] <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 +414,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 +421,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
|
||||
@@ -415,7 +466,6 @@ 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);
|
||||
@@ -432,7 +482,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);
|
||||
@@ -575,24 +625,48 @@ 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 SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
cookie = engine->StartQueryCvarValue(CEntityIndex(IndexOfEdict(pPlayer)), name);
|
||||
#else
|
||||
cookie = engine->StartQueryCvarValue(pPlayer, name);
|
||||
#endif
|
||||
}
|
||||
#if SOURCE_ENGINE != SE_DOTA
|
||||
else if (m_bIsVSPQueryHooked)
|
||||
{
|
||||
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return InvalidQueryCvarCookie;
|
||||
}
|
||||
|
||||
if (pCallback != NULL)
|
||||
{
|
||||
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) };
|
||||
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 = scripts->FindPluginByContext(pContext->GetContext());
|
||||
|
||||
/* Check plugin for an existing convar list */
|
||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||
{
|
||||
@@ -622,7 +696,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,8 +720,16 @@ 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)
|
||||
@@ -660,16 +746,23 @@ 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)
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||
#else
|
||||
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||
#endif // SE_DOTA
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
if (g_Players.HandleConVarQuery(cookie, pPlayer, result, cvarName, cvarValue))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
IPluginFunction *pCallback = NULL;
|
||||
cell_t value = 0;
|
||||
List<ConVarQuery>::iterator iter;
|
||||
@@ -690,7 +783,11 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
||||
cell_t ret;
|
||||
|
||||
pCallback->PushCell(cookie);
|
||||
pCallback->PushCell(client);
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
pCallback->PushCell(player.Get());
|
||||
#else
|
||||
pCallback->PushCell(IndexOfEdict(pPlayer));
|
||||
#endif
|
||||
pCallback->PushCell(result);
|
||||
pCallback->PushString(cvarName);
|
||||
|
||||
@@ -711,7 +808,7 @@ 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;
|
||||
@@ -726,10 +823,5 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugi
|
||||
*pVar = pInfo->pVar;
|
||||
}
|
||||
|
||||
if (ppPlugin)
|
||||
{
|
||||
*ppPlugin = pInfo->pPlugin;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
+35
-34
@@ -43,7 +43,11 @@
|
||||
#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 +66,12 @@ 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, const ConVarInfo *info)
|
||||
{
|
||||
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();
|
||||
}
|
||||
};
|
||||
return strcmp(name, info->pVar->GetName()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -111,15 +100,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;
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||
public: //IClientListener
|
||||
void OnClientDisconnected(int client);
|
||||
public:
|
||||
@@ -155,28 +145,39 @@ 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_DOTA
|
||||
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
|
||||
const char *cvarName, const char *cvarValue);
|
||||
#elif 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;
|
||||
|
||||
+356
-26
@@ -50,10 +50,7 @@
|
||||
#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>
|
||||
@@ -62,12 +59,26 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SH_IMPL_VERSION >= 5
|
||||
# if SOURCE_ENGINE == SE_DOTA
|
||||
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||
# elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
# else
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
# endif
|
||||
#else
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHVPAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>,bool);
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
# endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
#if SH_IMPL_VERSION >= 4
|
||||
|
||||
class GenericCommandHooker : public IConCommandLinkListener
|
||||
{
|
||||
struct HackInfo
|
||||
@@ -123,16 +134,18 @@ class GenericCommandHooker : public IConCommandLinkListener
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
# if SOURCE_ENGINE == SE_DOTA
|
||||
void Dispatch(const CCommandContext &context, const CCommand& args)
|
||||
# elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void Dispatch(const CCommand& args)
|
||||
#else
|
||||
# else
|
||||
void Dispatch()
|
||||
#endif
|
||||
# endif
|
||||
{
|
||||
cell_t res = ConsoleDetours::Dispatch(META_IFACEPTR(ConCommand)
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
# if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
, args
|
||||
#endif
|
||||
# endif
|
||||
);
|
||||
if (res >= Pl_Handled)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
@@ -182,7 +195,7 @@ class GenericCommandHooker : public IConCommandLinkListener
|
||||
size_t index;
|
||||
if (!FindVtable(vtable, index))
|
||||
{
|
||||
logger->LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
|
||||
g_Logger.LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,7 +219,7 @@ public:
|
||||
|
||||
if (dispatch.thisptroffs < 0)
|
||||
{
|
||||
logger->LogError("Command filter could not determine ConCommand layout");
|
||||
g_Logger.LogError("Command filter could not determine ConCommand layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -215,7 +228,7 @@ public:
|
||||
|
||||
if (!vtables.size())
|
||||
{
|
||||
logger->LogError("Command filter could not find any cvars!");
|
||||
g_Logger.LogError("Command filter could not find any cvars!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -249,6 +262,308 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* END DVP HOOK VERSION
|
||||
*/
|
||||
|
||||
#else /* SH_IMPL_VERSION >= 4 */
|
||||
|
||||
/**
|
||||
* BEGIN ENGINE DETOUR VERSION
|
||||
*/
|
||||
|
||||
# include <jit/jit_helpers.h>
|
||||
# include <jit/x86/x86_macros.h>
|
||||
|
||||
class GenericCommandHooker
|
||||
{
|
||||
struct Patch
|
||||
{
|
||||
Patch() : applied(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool applied;
|
||||
void *base;
|
||||
unsigned char search[16];
|
||||
size_t search_len;
|
||||
size_t offset;
|
||||
size_t saveat;
|
||||
int regparam;
|
||||
void *detour;
|
||||
};
|
||||
|
||||
Patch ces;
|
||||
Patch cgc;
|
||||
|
||||
public:
|
||||
static void DelayedActivation(void *inparam)
|
||||
{
|
||||
GenericCommandHooker *cdtrs = reinterpret_cast<GenericCommandHooker*>(inparam);
|
||||
/* Safe to re-enter because the frame queue is lock+swapped. */
|
||||
if ((!cdtrs->ces.applied || !cdtrs->cgc.applied) &&
|
||||
g_HL2.PeekCommandStack() != NULL)
|
||||
{
|
||||
g_SourceMod.AddFrameAction(GenericCommandHooker::DelayedActivation, cdtrs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cdtrs->ces.applied)
|
||||
cdtrs->ApplyPatch(&cdtrs->ces);
|
||||
if (!cdtrs->cgc.applied)
|
||||
cdtrs->ApplyPatch(&cdtrs->cgc);
|
||||
}
|
||||
|
||||
bool Enable()
|
||||
{
|
||||
const char *platform = NULL;
|
||||
# if defined(PLATFORM_WINDOWS)
|
||||
platform = "Windows";
|
||||
# else
|
||||
void *addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
|
||||
Dl_info info;
|
||||
if (!dladdr(addrInBase, &info))
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find engine name");
|
||||
return false;
|
||||
}
|
||||
if (strstr(info.dli_fname, "engine_i486"))
|
||||
{
|
||||
platform = "Linux_486";
|
||||
}
|
||||
else if (strstr(info.dli_fname, "engine_i686"))
|
||||
{
|
||||
platform = "Linux_686";
|
||||
}
|
||||
else if (strstr(info.dli_fname, "engine_amd"))
|
||||
{
|
||||
platform = "Linux_AMD";
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Logger.LogError("Command filter could not determine engine (%s)", info.dli_fname);
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!PrepPatch("Cmd_ExecuteString", "CES", platform, &ces))
|
||||
return false;
|
||||
if (!PrepPatch("CGameClient::ExecuteString", "CGC", platform, &cgc))
|
||||
return false;
|
||||
|
||||
if (g_HL2.PeekCommandStack() != NULL)
|
||||
{
|
||||
g_SourceMod.AddFrameAction(GenericCommandHooker::DelayedActivation, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
ApplyPatch(&ces);
|
||||
ApplyPatch(&cgc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
UndoPatch(&ces);
|
||||
UndoPatch(&cgc);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
# if !defined PLATFORM_WINDOWS
|
||||
# define PAGE_READWRITE PROT_READ|PROT_WRITE
|
||||
# define PAGE_EXECUTE_READ PROT_READ|PROT_EXEC
|
||||
|
||||
static inline uintptr_t AddrToPage(uintptr_t address)
|
||||
{
|
||||
return (address & ~(uintptr_t(sysconf(_SC_PAGE_SIZE) - 1)));
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
void Protect(void *addr, size_t length, int prot)
|
||||
{
|
||||
# if defined PLATFORM_WINDOWS
|
||||
DWORD ignore;
|
||||
VirtualProtect(addr, length, prot, &ignore);
|
||||
# else
|
||||
uintptr_t startPage = AddrToPage(uintptr_t(addr));
|
||||
length += (uintptr_t(addr) - startPage);
|
||||
mprotect((void*)startPage, length, prot);
|
||||
# endif
|
||||
}
|
||||
|
||||
void UndoPatch(Patch *patch)
|
||||
{
|
||||
if (!patch->applied || patch->detour == NULL)
|
||||
return;
|
||||
|
||||
g_pSourcePawn->FreePageMemory(patch->detour);
|
||||
|
||||
unsigned char *source = (unsigned char *)patch->base + patch->offset;
|
||||
Protect(source, patch->search_len, PAGE_READWRITE);
|
||||
for (size_t i = 0; i < patch->search_len; i++)
|
||||
source[i] = patch->search[i];
|
||||
Protect(source, patch->search_len, PAGE_EXECUTE_READ);
|
||||
}
|
||||
|
||||
void ApplyPatch(Patch *patch)
|
||||
{
|
||||
assert(!patch->applied);
|
||||
|
||||
size_t length = 0;
|
||||
void *callback = (void*)&ConsoleDetours::Dispatch;
|
||||
|
||||
/* Bogus assignment to make compiler is doing the right thing. */
|
||||
patch->detour = callback;
|
||||
|
||||
/* Assemgle the detour. */
|
||||
JitWriter writer;
|
||||
writer.outbase = NULL;
|
||||
writer.outptr = NULL;
|
||||
do
|
||||
{
|
||||
/* Need a specific register, or value on stack? */
|
||||
if (patch->regparam != -1)
|
||||
IA32_Push_Reg(&writer, patch->regparam);
|
||||
/* Call real function. */
|
||||
IA32_Write_Jump32_Abs(&writer, IA32_Call_Imm32(&writer, 0), callback);
|
||||
/* Restore stack. */
|
||||
if (patch->regparam != -1)
|
||||
IA32_Pop_Reg(&writer, patch->regparam);
|
||||
/* Copy any saved bytes */
|
||||
if (patch->saveat)
|
||||
{
|
||||
for (size_t i = patch->saveat; i < patch->search_len; i++)
|
||||
{
|
||||
writer.write_ubyte(patch->search[i]);
|
||||
}
|
||||
}
|
||||
/* Jump back to the caller. */
|
||||
unsigned char *target = (unsigned char *)patch->base + patch->offset + patch->search_len;
|
||||
IA32_Jump_Imm32_Abs(&writer, target);
|
||||
/* Assemble, if we can. */
|
||||
if (writer.outbase == NULL)
|
||||
{
|
||||
length = writer.outptr - writer.outbase;
|
||||
patch->detour = g_pSourcePawn->AllocatePageMemory(length);
|
||||
if (patch->detour == NULL)
|
||||
{
|
||||
g_Logger.LogError("Ran out of memory!");
|
||||
return;
|
||||
}
|
||||
g_pSourcePawn->SetReadWrite(patch->detour);
|
||||
writer.outbase = (jitcode_t)patch->detour;
|
||||
writer.outptr = writer.outbase;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
g_pSourcePawn->SetReadExecute(patch->detour);
|
||||
|
||||
unsigned char *source = (unsigned char *)patch->base + patch->offset;
|
||||
Protect(source, 6, PAGE_READWRITE);
|
||||
source[0] = 0xFF;
|
||||
source[1] = 0x25;
|
||||
*(void **)&source[2] = &patch->detour;
|
||||
Protect(source, 6, PAGE_EXECUTE_READ);
|
||||
|
||||
patch->applied = true;
|
||||
}
|
||||
|
||||
bool PrepPatch(const char *signature, const char *name, const char *platform, Patch *patch)
|
||||
{
|
||||
/* Get the base address of the function. */
|
||||
if (!g_pGameConf->GetMemSig(signature, &patch->base) || patch->base == NULL)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find signature: %s", signature);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *value;
|
||||
char keyname[255];
|
||||
|
||||
/* Get the verification bytes that will be written over. */
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Patch_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) == NULL)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find key: %s", keyname);
|
||||
return false;
|
||||
}
|
||||
patch->search_len = UTIL_DecodeHexString(patch->search, sizeof(patch->search), value);
|
||||
if (patch->search_len < 6)
|
||||
{
|
||||
g_Logger.LogError("Error decoding %s value, or not long enough", keyname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the offset into the function. */
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Offset_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) == NULL)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find key: %s", keyname);
|
||||
return false;
|
||||
}
|
||||
patch->offset = atoi(value);
|
||||
if (patch->offset > 20000)
|
||||
{
|
||||
g_Logger.LogError("Command filter %s value is bogus", keyname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the number of bytes to save from what was written over. */
|
||||
patch->saveat = 0;
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Save_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) != NULL)
|
||||
{
|
||||
patch->saveat = atoi(value);
|
||||
if (patch->saveat >= patch->search_len)
|
||||
{
|
||||
g_Logger.LogError("Command filter %s value is too large", keyname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get register for parameter, if any. */
|
||||
patch->regparam = -1;
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Reg_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) != NULL)
|
||||
{
|
||||
patch->regparam = atoi(value);
|
||||
}
|
||||
|
||||
/* Everything loaded from gamedata, make sure the patch will succeed. */
|
||||
unsigned char *address = (unsigned char *)patch->base + patch->offset;
|
||||
for (size_t i = 0; i < patch->search_len; i++)
|
||||
{
|
||||
if (address[i] != patch->search[i])
|
||||
{
|
||||
g_Logger.LogError("Command filter %s has changed (byte %x is not %x sub-offset %d)",
|
||||
name, address[i], patch->search[i], i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static bool dummy_hook_set = false;
|
||||
void DummyHook()
|
||||
{
|
||||
if (dummy_hook_set)
|
||||
{
|
||||
dummy_hook_set = false;
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* BEGIN THE ACTUALLY GENERIC CODE.
|
||||
*/
|
||||
@@ -307,13 +622,13 @@ bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
|
||||
IChangeableForward *forward;
|
||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||
if (!m_Listeners.retrieve(str, &forward))
|
||||
{
|
||||
forward = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
|
||||
Param_String, Param_Cell);
|
||||
m_Listeners.insert(str.get(), forward);
|
||||
m_Listeners.insert(str, forward);
|
||||
}
|
||||
forward->AddFunction(fun);
|
||||
}
|
||||
@@ -329,18 +644,18 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
|
||||
IChangeableForward *forward;
|
||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||
if (!m_Listeners.retrieve(str, &forward))
|
||||
return false;
|
||||
return forward->RemoveFunction(fun);
|
||||
}
|
||||
}
|
||||
|
||||
cell_t ConsoleDetours::InternalDispatch(int client, const ICommandArgs *args)
|
||||
cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
|
||||
{
|
||||
char name[255];
|
||||
const char *realname = args->Arg(0);
|
||||
const char *realname = args.Arg(0);
|
||||
size_t len = strlen(realname);
|
||||
|
||||
// Disallow command strings that are too long, for now.
|
||||
@@ -359,7 +674,7 @@ cell_t ConsoleDetours::InternalDispatch(int client, const ICommandArgs *args)
|
||||
cell_t result = Pl_Continue;
|
||||
m_pForward->PushCell(client);
|
||||
m_pForward->PushString(name);
|
||||
m_pForward->PushCell(args->ArgC() - 1);
|
||||
m_pForward->PushCell(args.ArgC() - 1);
|
||||
m_pForward->Execute(&result, NULL);
|
||||
|
||||
/* Don't let plugins block this. */
|
||||
@@ -378,7 +693,7 @@ cell_t ConsoleDetours::InternalDispatch(int client, const ICommandArgs *args)
|
||||
cell_t result2 = Pl_Continue;
|
||||
forward->PushCell(client);
|
||||
forward->PushString(name);
|
||||
forward->PushCell(args->ArgC() - 1);
|
||||
forward->PushCell(args.ArgC() - 1);
|
||||
forward->Execute(&result2, NULL);
|
||||
|
||||
if (result2 > result)
|
||||
@@ -398,12 +713,27 @@ cell_t ConsoleDetours::Dispatch(ConCommand *pBase)
|
||||
{
|
||||
CCommand args;
|
||||
#endif
|
||||
EngineArgs cargs(args);
|
||||
cell_t res;
|
||||
g_HL2.PushCommandStack(&args);
|
||||
cell_t res = g_ConsoleDetours.InternalDispatch(g_ConCmds.GetCommandClient(), args);
|
||||
g_HL2.PopCommandStack();
|
||||
|
||||
#if SH_IMPL_VERSION < 4
|
||||
if (res >= Pl_Handled)
|
||||
{
|
||||
AutoEnterCommand autoEnterCommand(&cargs);
|
||||
res = g_ConsoleDetours.InternalDispatch(sCoreProviderImpl.CommandClient(), &cargs);
|
||||
/* See bug 4020 - we can't optimize this because looking at the vtable
|
||||
* is probably more expensive, since there's no SH_GET_ORIG_VFNPTR_ENTRY.
|
||||
*/
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, pBase, SH_STATIC(DummyHook), false);
|
||||
dummy_hook_set = true;
|
||||
pBase->Dispatch();
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, pBase, SH_STATIC(DummyHook), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure the command gets invoked. See bug 4019 on making this better. */
|
||||
pBase->Dispatch();
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,6 @@
|
||||
#include <IForwardSys.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
|
||||
namespace SourceMod {
|
||||
class ICommandArgs;
|
||||
} // namespace SourceMod
|
||||
|
||||
class ConsoleDetours :
|
||||
public SMGlobalClass,
|
||||
public IFeatureProvider
|
||||
@@ -58,7 +54,7 @@ public:
|
||||
bool AddListener(IPluginFunction *fun, const char *command);
|
||||
bool RemoveListener(IPluginFunction *fun, const char *command);
|
||||
private:
|
||||
cell_t InternalDispatch(int client, const SourceMod::ICommandArgs *args);
|
||||
cell_t InternalDispatch(int client, const CCommand& args);
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
static cell_t Dispatch(ConCommand *pBase, const CCommand& args);
|
||||
#else
|
||||
|
||||
+62
-75
@@ -33,20 +33,13 @@
|
||||
#include "CoreConfig.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_srvcmds.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "Logger.h"
|
||||
#include "frame_hooks.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "compat_wrappers.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;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
|
||||
@@ -67,12 +60,23 @@ ConVar *g_ServerCfgFile = NULL;
|
||||
|
||||
void CheckAndFinalizeConfigs();
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||
void Hook_ExecDispatchPre(const CCommandContext &context, const CCommand &cmd)
|
||||
#elif 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
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
void Hook_ExecDispatchPre()
|
||||
#endif
|
||||
{
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
@@ -87,7 +91,9 @@ void Hook_ExecDispatchPre()
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void Hook_ExecDispatchPost(const CCommandContext &context, const CCommand &cmd)
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void Hook_ExecDispatchPost(const CCommand &cmd)
|
||||
#else
|
||||
void Hook_ExecDispatchPost()
|
||||
@@ -111,7 +117,7 @@ void CheckAndFinalizeConfigs()
|
||||
|
||||
void CoreConfig::OnSourceModAllInitialized()
|
||||
{
|
||||
rootmenu->AddRootConsoleCommand3("config", "Set core configuration options", this);
|
||||
g_RootMenu.AddRootConsoleCommand("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);
|
||||
@@ -127,7 +133,7 @@ CoreConfig::~CoreConfig()
|
||||
|
||||
void CoreConfig::OnSourceModShutdown()
|
||||
{
|
||||
rootmenu->RemoveRootConsoleCommand("config", this);
|
||||
g_RootMenu.RemoveRootConsoleCommand("config", this);
|
||||
forwardsys->ReleaseForward(g_pOnServerCfg);
|
||||
forwardsys->ReleaseForward(g_pOnConfigsExecuted);
|
||||
forwardsys->ReleaseForward(g_pOnAutoConfigsBuffered);
|
||||
@@ -177,45 +183,44 @@ 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("[SM] Config option \"%s\" successfully set to \"%s\".", option, value);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (argcount >= 3) {
|
||||
const char *option = command->Arg(2);
|
||||
const char *option = command.Arg(2);
|
||||
|
||||
const char *value = GetCoreConfigValue(option);
|
||||
|
||||
if (value == NULL)
|
||||
{
|
||||
UTIL_ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||
} else {
|
||||
UTIL_ConsolePrint("[SM] Config option \"%s\" is set to \"%s\".", option, value);
|
||||
g_RootMenu.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()
|
||||
@@ -232,7 +237,7 @@ void CoreConfig::Initialize()
|
||||
*/
|
||||
if (corecfg)
|
||||
{
|
||||
ke::path::Format(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -241,11 +246,11 @@ void CoreConfig::Initialize()
|
||||
/* Format path to config file */
|
||||
if (basepath)
|
||||
{
|
||||
ke::path::Format(filePath, sizeof(filePath), "%s/%s/%s", g_SourceMod.GetGamePath(), basepath, "configs/core.cfg");
|
||||
g_LibSys.PathFormat(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());
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), sm_corecfgfile.GetDefault());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +262,7 @@ void CoreConfig::Initialize()
|
||||
{
|
||||
/* :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 +274,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 +282,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 +290,23 @@ 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));
|
||||
ke::AString vstr(value);
|
||||
m_KeyValues.replace(option, ke::Move(vstr));
|
||||
|
||||
return result;
|
||||
return ConfigResult_Ignore;
|
||||
}
|
||||
|
||||
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
||||
{
|
||||
StringHashMap<std::string>::Result r = m_KeyValues.find(key);
|
||||
StringHashMap<ke::AString>::Result r = m_KeyValues.find(key);
|
||||
if (!r.found())
|
||||
return NULL;
|
||||
return r->value.c_str();
|
||||
return r->value.chars();
|
||||
}
|
||||
|
||||
bool SM_AreConfigsExecuted()
|
||||
@@ -336,12 +341,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 +367,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 +386,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 +400,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;
|
||||
@@ -412,11 +419,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 +429,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 */
|
||||
@@ -465,7 +469,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
}
|
||||
else
|
||||
{
|
||||
logger->LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
|
||||
g_Logger.LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
|
||||
return can_create;
|
||||
}
|
||||
}
|
||||
@@ -474,7 +478,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool 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);
|
||||
}
|
||||
|
||||
@@ -529,7 +533,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);
|
||||
}
|
||||
}
|
||||
@@ -576,24 +580,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)));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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,7 @@ private:
|
||||
*/
|
||||
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
||||
private:
|
||||
StringHashMap<std::string> m_KeyValues;
|
||||
StringHashMap<ke::AString> 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;
|
||||
+4
-14
@@ -31,10 +31,7 @@
|
||||
|
||||
#include "EventManager.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "PlayerManager.h"
|
||||
|
||||
#include "logic_bridge.h"
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
|
||||
EventManager g_EventManager;
|
||||
|
||||
@@ -158,7 +155,7 @@ 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
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
|
||||
int EventManager::GetEventDebugID()
|
||||
{
|
||||
return EVENT_DEBUG_ID_INIT;
|
||||
@@ -362,13 +359,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 */
|
||||
@@ -433,7 +423,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);
|
||||
@@ -484,7 +474,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
pForward->PushCell(BAD_HANDLE);
|
||||
}
|
||||
|
||||
pForward->PushString(pHook->name.c_str());
|
||||
pForward->PushString(pHook->name.chars());
|
||||
pForward->PushCell(bDontBroadcast);
|
||||
pForward->Execute(NULL);
|
||||
|
||||
@@ -505,7 +495,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
{
|
||||
assert(pHook->pPostHook == NULL);
|
||||
assert(pHook->pPreHook == NULL);
|
||||
m_EventHooks.remove(pHook->name.c_str());
|
||||
m_EventHooks.remove(pHook->name.chars());
|
||||
delete pHook;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-10
@@ -41,8 +41,6 @@
|
||||
#include <IForwardSys.h>
|
||||
#include <IPluginSys.h>
|
||||
|
||||
class IClient;
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct EventInfo
|
||||
@@ -71,15 +69,11 @@ struct EventHook
|
||||
IChangeableForward *pPostHook;
|
||||
bool postCopy;
|
||||
unsigned int refCount;
|
||||
std::string name;
|
||||
ke::AString 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();
|
||||
return strcmp(name, hook->name.chars()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,7 +110,7 @@ public: // IPluginsListener
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public: // IGameEventListener2
|
||||
void FireGameEvent(IGameEvent *pEvent);
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
|
||||
int GetEventDebugID();
|
||||
#endif
|
||||
public:
|
||||
@@ -132,7 +126,6 @@ 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);
|
||||
|
||||
@@ -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_
|
||||
+183
-542
File diff suppressed because it is too large
Load Diff
+21
-124
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* 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
|
||||
@@ -36,7 +36,6 @@
|
||||
#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>
|
||||
@@ -48,11 +47,11 @@
|
||||
#include <datamap.h>
|
||||
#include <ihandleentity.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
#include <string_t.h>
|
||||
#endif
|
||||
|
||||
namespace SourceMod {
|
||||
class ICommandArgs;
|
||||
} // namespace SourceMod
|
||||
class CCommand;
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
@@ -60,94 +59,39 @@ 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
|
||||
struct SendPropPolicy
|
||||
{
|
||||
static inline bool matches(const char *name, const SendPropInfo &info)
|
||||
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
|
||||
{
|
||||
return strcmp(name, info.name.c_str()) == 0;
|
||||
return strcmp(name, info.prop->GetName()) == 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;
|
||||
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
|
||||
};
|
||||
|
||||
struct DataMapCacheInfo
|
||||
struct DataMapCachePolicy
|
||||
{
|
||||
static inline bool matches(const char *name, const DataMapCacheInfo &info)
|
||||
static inline bool matches(const char *name, const sm_datatable_info_t &info)
|
||||
{
|
||||
return strcmp(name, info.name.c_str()) == 0;
|
||||
return strcmp(name, info.prop->fieldName) == 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;
|
||||
};
|
||||
|
||||
typedef NameHashSet<DataMapCacheInfo> DataMapCache;
|
||||
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
|
||||
|
||||
struct DelayedFakeCliCmd
|
||||
{
|
||||
@@ -158,7 +102,7 @@ struct DelayedFakeCliCmd
|
||||
|
||||
struct CachedCommandInfo
|
||||
{
|
||||
const ICommandArgs *args;
|
||||
const CCommand *args;
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
char cmd[300];
|
||||
#endif
|
||||
@@ -179,33 +123,16 @@ public:
|
||||
int m_SerialNumber;
|
||||
CEntInfo *m_pPrev;
|
||||
CEntInfo *m_pNext;
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
#if (SOURCE_ENGINE >= SE_PORTAL2) && (SOURCE_ENGINE != SE_DOTA)
|
||||
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();
|
||||
@@ -214,14 +141,11 @@ public:
|
||||
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);
|
||||
@@ -250,26 +174,20 @@ public: //IGameHelpers
|
||||
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 || PLAPI_VERSION < 11
|
||||
bool IsOriginalEngine();
|
||||
#endif
|
||||
private:
|
||||
void PushCommandStack(const ICommandArgs *cmd);
|
||||
void PopCommandStack();
|
||||
DataTableInfo *_FindServerClass(const char *classname);
|
||||
private:
|
||||
void InitLogicalEntData();
|
||||
@@ -288,31 +206,10 @@ private:
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
#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.
|
||||
@@ -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_POSIX
|
||||
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)
|
||||
@@ -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;
|
||||
+517
-7
@@ -34,37 +34,547 @@
|
||||
#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>
|
||||
|
||||
bool g_in_game_log_hook = false;
|
||||
|
||||
static LoggerCore g_LoggerCore;
|
||||
Logger g_Logger;
|
||||
|
||||
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
|
||||
|
||||
/**
|
||||
* :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;
|
||||
}
|
||||
|
||||
static void HookLogPrint(const char *message)
|
||||
{
|
||||
g_in_game_log_hook = true;
|
||||
bool stopped = logicore.callbacks->OnLogPrint(message);
|
||||
bool stopped = logicore.OnLogPrint(message);
|
||||
g_in_game_log_hook = false;
|
||||
|
||||
if (stopped)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void LoggerCore::OnSourceModStartup(bool late)
|
||||
void Logger::OnSourceModStartup(bool late)
|
||||
{
|
||||
InitLogger(m_Mode);
|
||||
|
||||
SH_ADD_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
|
||||
}
|
||||
|
||||
void LoggerCore::OnSourceModAllShutdown()
|
||||
void Logger::OnSourceModAllShutdown()
|
||||
{
|
||||
CloseLogger();
|
||||
SH_REMOVE_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
|
||||
}
|
||||
|
||||
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, SOURCEMOD_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_NrmCurDay = curtime->tm_mday;
|
||||
m_ErrCurDay = 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;
|
||||
}
|
||||
|
||||
static ConVar *sv_logecho = icvar->FindVar("sv_logecho");
|
||||
|
||||
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);
|
||||
|
||||
if (!sv_logecho || sv_logecho->GetBool())
|
||||
{
|
||||
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, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
LogMessageEx(vafmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogMessageEx(const char *vafmt, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Mode == LoggingMode_Game)
|
||||
{
|
||||
_PrintToGameLog(vafmt, 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_NrmCurDay != 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_NrmCurDay = 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, SOURCEMOD_VERSION);
|
||||
}
|
||||
LogToOpenFileEx(fp, vafmt, 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, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
LogErrorEx(vafmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogErrorEx(const char *vafmt, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
if (curtime->tm_mday != m_ErrCurDay)
|
||||
{
|
||||
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_ErrCurDay = 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;
|
||||
}
|
||||
LogToOpenFileEx(fp, vafmt, 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, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
LogFatalEx(msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogFatalEx(const char *msg, va_list ap)
|
||||
{
|
||||
/* :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.
|
||||
*/
|
||||
|
||||
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;
|
||||
LogToOpenFileEx(fp, msg, ap);
|
||||
m_Active = false;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
bool g_in_game_log_hook = false;
|
||||
|
||||
void Engine_LogPrintWrapper(const char *msg)
|
||||
{
|
||||
if (g_in_game_log_hook)
|
||||
|
||||
+64
-1
@@ -38,13 +38,76 @@
|
||||
|
||||
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 LogMessageEx(const char *msg, va_list ap);
|
||||
void LogError(const char *msg, ...);
|
||||
void LogErrorEx(const char *msg, va_list ap);
|
||||
void LogFatal(const char *msg, ...);
|
||||
void LogFatalEx(const char *msg, va_list ap);
|
||||
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_NrmCurDay;
|
||||
int m_ErrCurDay;
|
||||
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_
|
||||
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
# (C)2004-2008 SourceMod Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
SMSDK = ..
|
||||
HL2SDK_ORIG = ../../hl2sdk
|
||||
HL2SDK_OB = ../../hl2sdk-ob
|
||||
HL2SDK_CSS = ../../hl2sdk-css
|
||||
HL2SDK_OB_VALVE = ../../hl2sdk-ob-valve
|
||||
HL2SDK_L4D = ../../hl2sdk-l4d
|
||||
HL2SDK_L4D2 = ../../hl2sdk-l4d2
|
||||
HL2SDK_CSGO = ../../hl2sdk-csgo
|
||||
MMSOURCE = ../../mmsource-central
|
||||
|
||||
#####################################
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
#####################################
|
||||
|
||||
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
|
||||
Database.cpp DebugReporter.cpp EventManager.cpp HalfLife2.cpp Logger.cpp \
|
||||
PlayerManager.cpp TimerSys.cpp UserMessages.cpp \
|
||||
sm_autonatives.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 \
|
||||
frame_hooks.cpp concmd_cleaner.cpp NextMap.cpp \
|
||||
NativeOwner.cpp logic_bridge.cpp ConsoleDetours.cpp
|
||||
OBJECTS += smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||
smn_database.cpp smn_entities.cpp smn_events.cpp \
|
||||
smn_fakenatives.cpp smn_filesystem.cpp smn_halflife.cpp \
|
||||
smn_keyvalues.cpp smn_player.cpp \
|
||||
smn_usermsgs.cpp smn_menus.cpp smn_vector.cpp \
|
||||
smn_hudtext.cpp smn_nextmap.cpp
|
||||
OBJECTS += ExtensionSys.cpp \
|
||||
ForwardSys.cpp \
|
||||
HandleSys.cpp \
|
||||
LibrarySys.cpp \
|
||||
PluginInfoDatabase.cpp \
|
||||
PluginSys.cpp \
|
||||
ShareSys.cpp \
|
||||
NativeInvoker.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
|
||||
|
||||
ifneq (,$(filter original orangebox css orangeboxvalve left4dead left4dead2 csgo,$(ENGINE)))
|
||||
override ENGSET = true
|
||||
endif
|
||||
|
||||
ifeq "$(ENGINE)" "original"
|
||||
HL2SDK = $(HL2SDK_ORIG)
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
CFLAGS += -DSOURCE_ENGINE=1
|
||||
METAMOD = $(MMSOURCE)/core-legacy
|
||||
INCLUDE += -I$(HL2SDK)/public/dlls
|
||||
BINARY = sourcemod.1.ep1.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangebox"
|
||||
HL2SDK = $(HL2SDK_OB)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=3
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.ep2.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "css"
|
||||
HL2SDK = $(HL2SDK_CSS)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=6
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.css.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangeboxvalve"
|
||||
HL2SDK = $(HL2SDK_OB_VALVE)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=7
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.ep2v.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "left4dead"
|
||||
HL2SDK = $(HL2SDK_L4D)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=8
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.l4d.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "left4dead2"
|
||||
HL2SDK = $(HL2SDK_L4D2)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=9
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.l4d2.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "csgo"
|
||||
HL2SDK = $(HL2SDK_CSGO)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=12
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.csgo.so
|
||||
endif
|
||||
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
|
||||
OS := $(shell uname -s)
|
||||
|
||||
ifeq "$(OS)" "Darwin"
|
||||
LIB_EXT = dylib
|
||||
HL2LIB = $(HL2SDK)/lib/mac
|
||||
else
|
||||
LIB_EXT = so
|
||||
ifeq "$(ENGINE)" "original"
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
else
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
|
||||
LIB_SUFFIX = _i486.$(LIB_EXT)
|
||||
else
|
||||
LIB_PREFIX = lib
|
||||
ifneq (,$(filter orangeboxvalve css,$(ENGINE)))
|
||||
ifneq "$(OS)" "Darwin"
|
||||
LIB_SUFFIX = _srv.$(LIB_EXT)
|
||||
else
|
||||
LIB_SUFFIX = .$(LIB_EXT)
|
||||
endif
|
||||
else
|
||||
LIB_SUFFIX = .$(LIB_EXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_BLOODYGOODTIME=4 -DSE_EYE=5 \
|
||||
-DSE_CSS=6 -DSE_ORANGEBOXVALVE=7 -DSE_LEFT4DEAD=8 -DSE_LEFT4DEAD2=9 -DSE_ALIENSWARM=10 \
|
||||
-DSE_PORTAL2=11 -DSE_CSGO=12
|
||||
|
||||
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a $(LIB_PREFIX)vstdlib$(LIB_SUFFIX) \
|
||||
$(LIB_PREFIX)tier0$(LIB_SUFFIX) -static-libgcc
|
||||
|
||||
ifeq "$(ENGINE)" "csgo"
|
||||
LINK += $(HL2LIB)/interfaces_i486.a
|
||||
endif
|
||||
|
||||
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 -DPOSIX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||
-Wno-uninitialized -Wno-unused -Wno-switch -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H \
|
||||
-DSM_DEFAULT_THREADER -m32 -DCOMPILER_GCC
|
||||
CPPFLAGS += -Wno-non-virtual-dtor -Wno-overloaded-virtual -fno-threadsafe-statics -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)
|
||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX)
|
||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX)
|
||||
$(MAKE) -f Makefile sourcemod
|
||||
|
||||
check:
|
||||
if [ "$(ENGSET)" = "false" ]; then \
|
||||
echo "You must supply one of the following values for ENGINE:"; \
|
||||
echo "csgo, left4dead2, left4dead, orangeboxvalve, css, orangebox, or 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)/$(BINARY)
|
||||
+35
-38
@@ -38,7 +38,6 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "sourcemm_api.h"
|
||||
#include "logic_bridge.h"
|
||||
|
||||
@@ -69,29 +68,6 @@ void MenuManager::OnSourceModAllInitialized()
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::OnSourceModAllShutdown()
|
||||
{
|
||||
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
|
||||
@@ -332,7 +308,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 +398,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 +420,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))
|
||||
@@ -470,7 +446,7 @@ skip_search:
|
||||
char text[50];
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
|
||||
{
|
||||
ke::SafeStrcpy(text, sizeof(text), "No Vote");
|
||||
UTIL_Format(text, sizeof(text), "No Vote");
|
||||
}
|
||||
ItemDrawInfo dr(text, 0);
|
||||
position = panel->DrawItem(dr);
|
||||
@@ -594,7 +570,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;
|
||||
}
|
||||
@@ -630,7 +606,7 @@ skip_search:
|
||||
{
|
||||
if (!logicore.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);
|
||||
@@ -640,7 +616,7 @@ skip_search:
|
||||
{
|
||||
if (!logicore.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);
|
||||
@@ -661,7 +637,7 @@ skip_search:
|
||||
{
|
||||
if (!logicore.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);
|
||||
@@ -692,7 +668,7 @@ skip_search:
|
||||
{
|
||||
if (!logicore.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 +699,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 +732,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_SelectSound.size() > 0)
|
||||
{
|
||||
sound = &m_SelectSound;
|
||||
sound = m_SelectSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -743,7 +740,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitBackSound.size() > 0)
|
||||
{
|
||||
sound = &m_ExitBackSound;
|
||||
sound = m_ExitBackSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -751,7 +748,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitSound.size() > 0)
|
||||
{
|
||||
sound = &m_ExitSound;
|
||||
sound = m_ExitSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+10
-6
@@ -36,8 +36,8 @@
|
||||
#include <sh_vector.h>
|
||||
#include <sh_stack.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include "sm_globals.h"
|
||||
#include <string>
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
@@ -55,8 +55,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 +99,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 +109,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;
|
||||
|
||||
+62
-180
@@ -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
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "MenuManager.h"
|
||||
#include "CellRecipientFilter.h"
|
||||
#if defined MENU_DEBUG
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include "Logger.h"
|
||||
#endif
|
||||
#include "logic_bridge.h"
|
||||
#include "AutoHandleRooter.h"
|
||||
@@ -59,7 +59,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 +67,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 +75,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 +99,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 +115,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 +135,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 +191,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 +214,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 +232,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 +244,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 +254,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 +269,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 +302,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 +311,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,23 +323,22 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
if (pCollideable)
|
||||
{
|
||||
const Vector & pos = pCollideable->GetCollisionOrigin();
|
||||
enginesound->EmitSound(filter,
|
||||
client,
|
||||
CHAN_AUTO,
|
||||
enginesound->EmitSound(filter,
|
||||
client,
|
||||
CHAN_AUTO,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
sound->c_str(),
|
||||
-1,
|
||||
sound,
|
||||
-1,
|
||||
#endif
|
||||
sound->c_str(),
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
sound,
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
0,
|
||||
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,
|
||||
PITCH_NORM,
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
|
||||
0,
|
||||
#endif
|
||||
&pos);
|
||||
@@ -412,7 +411,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 +474,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 +486,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 +497,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 +516,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 +531,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 +561,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 +570,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 +580,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 +597,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_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)
|
||||
{
|
||||
}
|
||||
@@ -628,49 +627,49 @@ Handle_t CBaseMenu::GetHandle()
|
||||
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
||||
{
|
||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
||||
&& m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||
&& m_items.length() >= m_pStyle->GetMaxPageItems())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CItem item(m_items.size());
|
||||
CItem item;
|
||||
|
||||
item.info = info;
|
||||
if (draw.display)
|
||||
item.display = std::make_unique<std::string>(draw.display);
|
||||
item.display = new ke::AString(draw.display);
|
||||
item.style = draw.style;
|
||||
|
||||
m_items.push_back(std::move(item));
|
||||
m_items.append(ke::Move(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())
|
||||
m_items.length() >= m_pStyle->GetMaxPageItems())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (position >= m_items.size())
|
||||
if (position >= m_items.length())
|
||||
return false;
|
||||
|
||||
CItem item(position);
|
||||
CItem item;
|
||||
item.info = info;
|
||||
if (draw.display)
|
||||
item.display = std::make_unique<std::string>(draw.display);
|
||||
item.display = new ke::AString(draw.display);
|
||||
item.style = draw.style;
|
||||
|
||||
m_items.emplace(m_items.begin() + position, std::move(item));
|
||||
m_items.insert(position, ke::Move(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBaseMenu::RemoveItem(unsigned int position)
|
||||
{
|
||||
if (position >= m_items.size())
|
||||
if (position >= m_items.length())
|
||||
return false;
|
||||
|
||||
m_items.erase(m_items.begin() + position);
|
||||
m_items.remove(position);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -679,140 +678,23 @@ void CBaseMenu::RemoveAllItems()
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
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())
|
||||
if (position >= m_items.length())
|
||||
return NULL;
|
||||
|
||||
if (client > 0 && position < m_RandomMaps[client].size())
|
||||
{
|
||||
position = m_RandomMaps[client][position];
|
||||
}
|
||||
|
||||
if (draw)
|
||||
{
|
||||
draw->display = m_items[position].display->c_str();
|
||||
draw->display = m_items[position].display->chars();
|
||||
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_items[position].info.chars();
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetItemCount()
|
||||
{
|
||||
return m_items.size();
|
||||
return m_items.length();
|
||||
}
|
||||
|
||||
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
||||
@@ -850,7 +732,7 @@ void CBaseMenu::SetDefaultTitle(const char *message)
|
||||
|
||||
const char *CBaseMenu::GetDefaultTitle()
|
||||
{
|
||||
return m_Title.c_str();
|
||||
return m_Title.chars();
|
||||
}
|
||||
|
||||
void CBaseMenu::Cancel()
|
||||
@@ -861,7 +743,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 +767,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,
|
||||
@@ -942,5 +824,5 @@ IMenuHandler *CBaseMenu::GetHandler()
|
||||
|
||||
unsigned int CBaseMenu::GetBaseMemUsage()
|
||||
{
|
||||
return m_Title.size() + (m_items.size() * sizeof(CItem));
|
||||
return m_Title.length() + (m_items.length() * sizeof(CItem));
|
||||
}
|
||||
|
||||
+24
-36
@@ -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,9 +32,6 @@
|
||||
#ifndef _INCLUDE_MENUSTYLE_BASE_H
|
||||
#define _INCLUDE_MENUSTYLE_BASE_H
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <IMenuManager.h>
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <am-string.h>
|
||||
@@ -46,40 +43,36 @@ using namespace SourceMod;
|
||||
class CItem
|
||||
{
|
||||
public:
|
||||
CItem(unsigned int index)
|
||||
CItem()
|
||||
{
|
||||
this->index = index;
|
||||
style = 0;
|
||||
access = 0;
|
||||
}
|
||||
CItem(CItem &&other)
|
||||
: info(std::move(other.info)),
|
||||
display(std::move(other.display))
|
||||
CItem(ke::Moveable<CItem> other)
|
||||
: info(ke::Move(other->info)),
|
||||
display(ke::Move(other->display))
|
||||
{
|
||||
index = other.index;
|
||||
style = other.style;
|
||||
access = other.access;
|
||||
style = other->style;
|
||||
access = other->access;
|
||||
}
|
||||
CItem & operator =(CItem &&other)
|
||||
CItem & operator =(ke::Moveable<CItem> other)
|
||||
{
|
||||
index = other.index;
|
||||
info = std::move(other.info);
|
||||
display = std::move(other.display);
|
||||
style = other.style;
|
||||
access = other.access;
|
||||
info = ke::Move(other->info);
|
||||
display = ke::Move(other->display);
|
||||
style = other->style;
|
||||
access = other->access;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int index;
|
||||
std::string info;
|
||||
std::unique_ptr<std::string> display;
|
||||
ke::AString info;
|
||||
ke::AutoPtr<ke::AString> display;
|
||||
unsigned int style;
|
||||
unsigned int access;
|
||||
|
||||
private:
|
||||
CItem(const CItem &other) = delete;
|
||||
CItem &operator =(const CItem &other) = delete;
|
||||
CItem(const CItem &other) KE_DELETE;
|
||||
CItem &operator =(const CItem &other) KE_DELETE;
|
||||
};
|
||||
|
||||
class CBaseMenuPlayer
|
||||
@@ -98,7 +91,7 @@ public:
|
||||
|
||||
class CBaseMenu;
|
||||
|
||||
class BaseMenuStyle :
|
||||
class BaseMenuStyle :
|
||||
public IMenuStyle,
|
||||
public IClientListener
|
||||
{
|
||||
@@ -113,11 +106,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 +137,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 +151,14 @@ 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;
|
||||
ke::AString m_Title;
|
||||
IMenuStyle *m_pStyle;
|
||||
unsigned int m_Pagination;
|
||||
std::vector<CItem> m_items;
|
||||
ke::Vector<CItem> m_items;
|
||||
bool m_bShouldDelete;
|
||||
bool m_bCancelling;
|
||||
IdentityToken_t *m_pOwner;
|
||||
@@ -178,7 +167,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
|
||||
|
||||
+31
-40
@@ -35,7 +35,7 @@
|
||||
#include <IGameConfigs.h>
|
||||
#include "PlayerManager.h"
|
||||
#if defined MENU_DEBUG
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include "Logger.h"
|
||||
#endif
|
||||
#include "logic_bridge.h"
|
||||
|
||||
@@ -45,10 +45,6 @@
|
||||
|
||||
#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>
|
||||
#endif
|
||||
|
||||
extern const char *g_RadioNumTable[];
|
||||
@@ -63,7 +59,7 @@ unsigned int g_RadioMenuTimeout = 0;
|
||||
#define MAX_MENUSLOT_KEYS 10
|
||||
|
||||
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
||||
static bool s_RadioClosesOnInvalidSlot = false;
|
||||
|
||||
|
||||
CRadioStyle::CRadioStyle()
|
||||
{
|
||||
@@ -87,10 +83,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')
|
||||
{
|
||||
@@ -126,12 +118,7 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -151,7 +138,11 @@ void CRadioStyle::OnSourceModShutdown()
|
||||
|
||||
bool CRadioStyle::IsSupported()
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
return false;
|
||||
#else
|
||||
return (g_ShowMenuId != -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
|
||||
@@ -182,9 +173,10 @@ void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFi
|
||||
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
||||
#endif
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DOTA
|
||||
int count = pFilter->GetRecipientCount();
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||
#else
|
||||
bf_read br(bf->GetBasePointer(), 3);
|
||||
@@ -199,6 +191,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
|
||||
{
|
||||
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CRadioStyle::OnUserMessageSent(int msg_id)
|
||||
@@ -207,7 +200,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
|
||||
@@ -268,6 +261,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 +336,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()
|
||||
@@ -460,7 +461,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,24 +469,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()
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DOTA
|
||||
cell_t players[1] = { (cell_t)m_index };
|
||||
char *ptr = display_pkt;
|
||||
char save = 0;
|
||||
@@ -502,13 +496,10 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
// If or when we need to support multiple games per engine with this, we can switch to reflection
|
||||
// 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);
|
||||
@@ -542,6 +533,7 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
#endif
|
||||
|
||||
display_last_refresh = gpGlobals->curtime;
|
||||
#endif // !DOTA
|
||||
}
|
||||
|
||||
int CRadioDisplay::GetAmountRemaining()
|
||||
@@ -599,7 +591,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 +601,6 @@ bool CRadioMenu::DisplayAtItem(int client,
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoHandleRooter ahr(this->GetHandle());
|
||||
return g_RadioMenuStyle.DoClientMenu(client,
|
||||
this,
|
||||
start_item,
|
||||
|
||||
@@ -40,10 +40,7 @@
|
||||
#include "UserMessages.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;
|
||||
|
||||
@@ -104,6 +101,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 +129,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;
|
||||
|
||||
@@ -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.
|
||||
@@ -65,16 +65,20 @@ bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCom
|
||||
|
||||
void ValveMenuStyle::OnSourceModAllInitialized()
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DOTA
|
||||
g_Players.AddClientListener(this);
|
||||
SH_ADD_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
|
||||
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ValveMenuStyle::OnSourceModShutdown()
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DOTA
|
||||
SH_RELEASE_CALLCLASS(g_pSPHCC);
|
||||
SH_REMOVE_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
|
||||
g_Players.RemoveClientListener(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
|
||||
@@ -293,7 +297,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 +382,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 +408,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;
|
||||
|
||||
+3
-4
@@ -514,16 +514,15 @@ 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);
|
||||
menu->GetItemInfo(item, &dr);
|
||||
|
||||
if (sm_vote_console.GetBool())
|
||||
{
|
||||
|
||||
+41
-47
@@ -35,10 +35,7 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcehook.h"
|
||||
#include "logic_bridge.h"
|
||||
#include "compat_wrappers.h"
|
||||
#include <time.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include "sm_srvcmds.h"
|
||||
|
||||
NextMapManager g_NextMap;
|
||||
|
||||
@@ -48,22 +45,34 @@ SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, co
|
||||
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
#else
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
ConCommand *changeLevelCmd = NULL;
|
||||
|
||||
ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
|
||||
ConVar sm_maphistory_size("sm_maphistory_size", "20");
|
||||
|
||||
bool g_forcedChange = false;
|
||||
|
||||
void NextMapManager::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#else
|
||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#endif
|
||||
|
||||
ConCommand *pCmd = FindCommand("changelevel");
|
||||
if (pCmd != NULL)
|
||||
@@ -75,7 +84,11 @@ void NextMapManager::OnSourceModAllInitialized_Post()
|
||||
|
||||
void NextMapManager::OnSourceModShutdown()
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#else
|
||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#endif
|
||||
|
||||
if (changeLevelCmd != NULL)
|
||||
{
|
||||
@@ -109,8 +122,6 @@ bool NextMapManager::SetNextMap(const char *map)
|
||||
return true;
|
||||
}
|
||||
|
||||
static char g_nextMap[PLATFORM_MAX_PATH];
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
||||
#else
|
||||
@@ -119,29 +130,21 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
|
||||
{
|
||||
if (g_forcedChange)
|
||||
{
|
||||
logger->LogMessage("[SM] Changed map to \"%s\"", map);
|
||||
g_Logger.LogMessage("[SM] Changed map to \"%s\"", map);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
const char *newmap = sm_nextmap.GetString();
|
||||
if (newmap[0] != '\0') {
|
||||
ke::SafeStrcpy(g_nextMap, sizeof(g_nextMap), newmap);
|
||||
newmap = g_nextMap;
|
||||
|
||||
// Clear the value so that if the map load fails later we don't get stuck in a loop.
|
||||
// This might cause us to go off-cycle for a map, but nextmap will get us back on track.
|
||||
sm_nextmap.SetValue("");
|
||||
}
|
||||
|
||||
if (newmap[0] == '\0' || !g_HL2.IsMapValid(newmap))
|
||||
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
logger->LogMessage("[SM] Changed map to \"%s\"", newmap);
|
||||
g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
|
||||
|
||||
ke::SafeStrcpy(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
|
||||
ke::SafeStrcpy(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
|
||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
|
||||
@@ -152,15 +155,6 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
|
||||
|
||||
void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
||||
{
|
||||
// If we were controlling the map change, reset sm_nextmap to be the name of the map we successfully changed to.
|
||||
// This maintains an old API contract on the plugin side. We use the real map name even if it was different from
|
||||
// the expected map name as if the expected map failed to load we let the game take over instead, but the nextmap
|
||||
// plugin compares the sm_nextmap value to the current map to decide if it should advance the mapcycle.
|
||||
if (g_nextMap[0] != '\0') {
|
||||
sm_nextmap.SetValue(mapName);
|
||||
g_nextMap[0] = '\0';
|
||||
}
|
||||
|
||||
/* Skip the first 'mapchange' when the server starts up */
|
||||
if (m_tempChangeInfo.startTime != 0)
|
||||
{
|
||||
@@ -173,36 +167,33 @@ void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
||||
{
|
||||
/* Something intercepted the mapchange */
|
||||
char newReason[255];
|
||||
ke::SafeSprintf(newReason, sizeof(newReason), "%s (Map overridden)", m_tempChangeInfo.m_changeReason);
|
||||
UTIL_Format(newReason, sizeof(newReason), "%s (Map overridden)", m_tempChangeInfo.m_changeReason);
|
||||
m_mapHistory.push_back(new MapChangeData(lastMap, newReason, m_tempChangeInfo.startTime));
|
||||
}
|
||||
|
||||
int historydiff = sm_maphistory_size.GetInt();
|
||||
if (historydiff > 0)
|
||||
/* TODO: Should this be customizable? */
|
||||
if (m_mapHistory.size() > 20)
|
||||
{
|
||||
historydiff -= m_mapHistory.size();
|
||||
} else if (historydiff < 0)
|
||||
{
|
||||
historydiff = (m_mapHistory.size() * -1);
|
||||
}
|
||||
SourceHook::List<MapChangeData *>::iterator iter;
|
||||
iter = m_mapHistory.begin();
|
||||
|
||||
for (SourceHook::List<MapChangeData *>::iterator iter = m_mapHistory.begin(); historydiff++ < 0; iter = m_mapHistory.erase(iter))
|
||||
{
|
||||
delete (MapChangeData *)*iter;
|
||||
|
||||
m_mapHistory.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
m_tempChangeInfo.m_mapName[0] ='\0';
|
||||
m_tempChangeInfo.m_changeReason[0] = '\0';
|
||||
m_tempChangeInfo.startTime = time(NULL);
|
||||
ke::SafeStrcpy(lastMap, sizeof(lastMap), mapName);
|
||||
UTIL_Format(lastMap, sizeof(lastMap), "%s", mapName);
|
||||
}
|
||||
|
||||
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
|
||||
{
|
||||
/* Store the mapname and reason */
|
||||
ke::SafeStrcpy(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
|
||||
ke::SafeStrcpy(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
|
||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), "%s", mapName);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "%s", changeReason);
|
||||
|
||||
/* Change level and skip our hook */
|
||||
g_forcedChange = true;
|
||||
@@ -216,7 +207,10 @@ NextMapManager::NextMapManager()
|
||||
m_mapHistory = SourceHook::List<MapChangeData *>();
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command)
|
||||
{
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CmdChangeLevelCallback(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
@@ -232,7 +226,7 @@ void CmdChangeLevelCallback()
|
||||
|
||||
if (g_NextMap.m_tempChangeInfo.m_mapName[0] == '\0')
|
||||
{
|
||||
ke::SafeStrcpy(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
|
||||
ke::SafeStrcpy(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
|
||||
UTIL_Format(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
|
||||
UTIL_Format(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -33,17 +33,16 @@
|
||||
#define _INCLUDE_SOURCEMOD_NEXTMAP_H_
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include <eiface.h>
|
||||
#include "eiface.h"
|
||||
#include "sh_list.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
struct MapChangeData
|
||||
{
|
||||
MapChangeData(const char *mapName, const char *changeReason, time_t time)
|
||||
{
|
||||
ke::SafeStrcpy(m_mapName, sizeof(m_mapName), mapName);
|
||||
ke::SafeStrcpy(m_changeReason, sizeof(m_changeReason), changeReason);
|
||||
UTIL_Format(m_mapName, sizeof(m_mapName), mapName);
|
||||
UTIL_Format(m_changeReason, sizeof(m_changeReason), changeReason);
|
||||
startTime = time;
|
||||
}
|
||||
|
||||
@@ -59,7 +58,9 @@ struct MapChangeData
|
||||
time_t startTime;
|
||||
};
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CmdChangeLevelCallback(const CCommand &command);
|
||||
#else
|
||||
void CmdChangeLevelCallback();
|
||||
@@ -70,7 +71,9 @@ class NextMapManager : public SMGlobalClass
|
||||
public:
|
||||
NextMapManager();
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
friend void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
friend void CmdChangeLevelCallback(const CCommand &command);
|
||||
#else
|
||||
friend void CmdChangeLevelCallback();
|
||||
@@ -96,7 +99,7 @@ public:
|
||||
|
||||
private:
|
||||
MapChangeData m_tempChangeInfo;
|
||||
char lastMap[PLATFORM_MAX_PATH];
|
||||
char lastMap[32];
|
||||
};
|
||||
|
||||
extern NextMapManager g_NextMap;
|
||||
|
||||
+453
-683
File diff suppressed because it is too large
Load Diff
+43
-73
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 sts=8 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2015 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
|
||||
@@ -38,20 +38,13 @@
|
||||
#include <IForwardSys.h>
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <IAdminSystem.h>
|
||||
#include <ITranslator.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_vector.h>
|
||||
#include <am-string.h>
|
||||
#include <am-deque.h>
|
||||
#include "ConVarManager.h"
|
||||
|
||||
#include <steam/steamclientpublic.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
class IClient;
|
||||
|
||||
#define PLAYER_LIFE_UNKNOWN 0
|
||||
#define PLAYER_LIFE_ALIVE 1
|
||||
#define PLAYER_LIFE_DEAD 2
|
||||
@@ -78,10 +71,6 @@ public:
|
||||
const char *GetIPAddress();
|
||||
const char *GetAuthString(bool validated = true);
|
||||
unsigned int GetSteamAccountID(bool validated = true);
|
||||
const CSteamID &GetSteamId(bool validated = true);
|
||||
uint64_t GetSteamId64(bool validated = true) { return GetSteamId(validated).ConvertToUint64(); }
|
||||
const char *GetSteam2Id(bool validated = true);
|
||||
const char *GetSteam3Id(bool validated = true);
|
||||
edict_t *GetEdict();
|
||||
bool IsInGame();
|
||||
bool WasCountedAsInGame();
|
||||
@@ -96,7 +85,6 @@ public:
|
||||
bool IsInKickQueue();
|
||||
IPlayerInfo *GetPlayerInfo();
|
||||
unsigned int GetLanguageId();
|
||||
unsigned int GetOriginalLanguageId();
|
||||
void SetLanguageId(unsigned int id);
|
||||
int GetUserId();
|
||||
bool RunAdminCacheChecks();
|
||||
@@ -109,67 +97,54 @@ public:
|
||||
void DoBasicAdminChecks();
|
||||
void MarkAsBeingKicked();
|
||||
int GetLifeState();
|
||||
|
||||
// This can be NULL for fakeclients due to limitations in our impl
|
||||
IClient *GetIClient() const;
|
||||
private:
|
||||
void Initialize(const char *name, const char *ip, edict_t *pEntity);
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
void SetName(const char *name);
|
||||
void DumpAdmin(bool deleting);
|
||||
void UpdateAuthIds();
|
||||
void SetAuthString(const char *auth);
|
||||
void Authorize();
|
||||
void Authorize_Post();
|
||||
void DoPostConnectAuthorization();
|
||||
bool IsAuthStringValidated();
|
||||
bool SetEngineString();
|
||||
bool SetCSteamID();
|
||||
void ClearNetchannelQueue(void);
|
||||
private:
|
||||
bool m_IsConnected = false;
|
||||
bool m_IsInGame = false;
|
||||
bool m_IsAuthorized = false;
|
||||
bool m_bIsInKickQueue = false;
|
||||
bool m_IsConnected;
|
||||
bool m_IsInGame;
|
||||
bool m_IsAuthorized;
|
||||
bool m_bIsInKickQueue;
|
||||
String m_Name;
|
||||
String m_Ip;
|
||||
String m_IpNoPort;
|
||||
std::string m_AuthID;
|
||||
std::string m_Steam2Id;
|
||||
std::string m_Steam3Id;
|
||||
AdminId m_Admin = INVALID_ADMIN_ID;
|
||||
bool m_TempAdmin = false;
|
||||
edict_t *m_pEdict = nullptr;
|
||||
IPlayerInfo *m_Info = nullptr;
|
||||
IClient *m_pIClient = nullptr;
|
||||
String m_AuthID;
|
||||
AdminId m_Admin;
|
||||
bool m_TempAdmin;
|
||||
edict_t *m_pEdict;
|
||||
IPlayerInfo *m_Info;
|
||||
String m_LastPassword;
|
||||
bool m_bAdminCheckSignalled = false;
|
||||
bool m_bAdminCheckSignalled;
|
||||
int m_iIndex;
|
||||
unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
|
||||
unsigned int m_OriginalLangId = SOURCEMOD_LANGUAGE_ENGLISH;
|
||||
int m_UserId = -1;
|
||||
bool m_bFakeClient = false;
|
||||
bool m_bIsSourceTV = false;
|
||||
bool m_bIsReplay = false;
|
||||
unsigned int m_LangId;
|
||||
int m_UserId;
|
||||
bool m_bFakeClient;
|
||||
bool m_bIsSourceTV;
|
||||
bool m_bIsReplay;
|
||||
serial_t m_Serial;
|
||||
CSteamID m_SteamId;
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
||||
unsigned int m_SteamAccountID;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
QueryCvarCookie_t m_LanguageCookie;
|
||||
#endif
|
||||
std::deque<std::string> m_PrintfBuffer;
|
||||
};
|
||||
|
||||
class PlayerManager :
|
||||
public SMGlobalClass,
|
||||
public IPlayerManager,
|
||||
public IGameEventListener2
|
||||
public IPlayerManager
|
||||
{
|
||||
friend class CPlayer;
|
||||
public:
|
||||
PlayerManager();
|
||||
~PlayerManager();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModStartup(bool late) override;
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModLevelEnd();
|
||||
@@ -179,6 +154,16 @@ public:
|
||||
CPlayer *GetPlayerByIndex(int client) const;
|
||||
void RunAuthChecks();
|
||||
public:
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
bool OnClientConnect(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
bool OnClientConnect_Post(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
void OnClientPutInServer(CEntityIndex index, char const *playername);
|
||||
void OnClientDisconnect(CEntityIndex index, int reason);
|
||||
void OnClientDisconnect_Post(CEntityIndex index, int reason);
|
||||
void OnClientCommand(CEntityIndex index, const CCommand &args);
|
||||
void OnClientSettingsChanged(CEntityIndex index);
|
||||
//void OnClientSettingsChanged_Pre(CEntityIndex client);
|
||||
#else
|
||||
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
void OnClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
@@ -186,19 +171,13 @@ public:
|
||||
void OnClientDisconnect_Post(edict_t *pEntity);
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnClientCommand(edict_t *pEntity, const CCommand &args);
|
||||
#if SOURCE_ENGINE >= SE_EYE
|
||||
void OnClientCommandKeyValues(edict_t *pEntity, KeyValues *pCommand);
|
||||
void OnClientCommandKeyValues_Post(edict_t *pEntity, KeyValues *pCommand);
|
||||
#endif
|
||||
#else
|
||||
void OnClientCommand(edict_t *pEntity);
|
||||
#endif
|
||||
void OnClientSettingsChanged(edict_t *pEntity);
|
||||
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
||||
void OnClientLanguageChanged(int client, unsigned int language);
|
||||
#endif
|
||||
void OnServerHibernationUpdate(bool bHibernating);
|
||||
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
||||
void OnPrintfFrameAction(unsigned int serial);
|
||||
public: //IPlayerManager
|
||||
void AddClientListener(IClientListener *listener);
|
||||
void RemoveClientListener(IClientListener *listener);
|
||||
@@ -206,7 +185,6 @@ public: //IPlayerManager
|
||||
IGamePlayer *GetGamePlayer(edict_t *pEdict);
|
||||
int GetMaxClients();
|
||||
int GetNumPlayers();
|
||||
int GetNumClients();
|
||||
int GetClientOfUserId(int userid);
|
||||
bool IsServerActivated();
|
||||
int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags);
|
||||
@@ -217,8 +195,6 @@ public: //IPlayerManager
|
||||
int GetClientFromSerial(unsigned int serial);
|
||||
void ClearAdminId(AdminId id);
|
||||
void RecheckAnyAdmins();
|
||||
public: // IGameEventListener2
|
||||
void FireGameEvent(IGameEvent *pEvent);
|
||||
public:
|
||||
inline int MaxClients()
|
||||
{
|
||||
@@ -238,15 +214,15 @@ public:
|
||||
unsigned int GetReplyTo();
|
||||
unsigned int SetReplyTo(unsigned int reply);
|
||||
void MaxPlayersChanged(int newvalue = -1);
|
||||
inline bool InClientCommandKeyValuesHook()
|
||||
{
|
||||
return m_bInCCKVHook;
|
||||
}
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
bool HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
||||
#endif
|
||||
private:
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void OnServerActivate();
|
||||
#else
|
||||
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
#endif
|
||||
void InvalidatePlayer(CPlayer *pPlayer);
|
||||
private:
|
||||
List<IClientListener *> m_hooks;
|
||||
@@ -256,11 +232,8 @@ private:
|
||||
IForward *m_cldisconnect_post;
|
||||
IForward *m_clputinserver;
|
||||
IForward *m_clcommand;
|
||||
IForward *m_clcommandkv;
|
||||
IForward *m_clcommandkv_post;
|
||||
IForward *m_clinfochanged;
|
||||
IForward *m_clauth;
|
||||
IForward *m_cllang;
|
||||
IForward *m_onActivate;
|
||||
IForward *m_onActivate2;
|
||||
CPlayer *m_Players;
|
||||
@@ -268,7 +241,7 @@ private:
|
||||
int m_maxClients;
|
||||
int m_PlayerCount;
|
||||
int m_PlayersSinceActive;
|
||||
bool m_bServerActivated;
|
||||
bool m_FirstPass;
|
||||
unsigned int *m_AuthQueue;
|
||||
String m_PassInfoVar;
|
||||
bool m_QueryLang;
|
||||
@@ -279,14 +252,11 @@ private:
|
||||
bool m_bIsReplayActive;
|
||||
int m_SourceTVUserId;
|
||||
int m_ReplayUserId;
|
||||
bool m_bInCCKVHook;
|
||||
int m_ClientCount;
|
||||
private:
|
||||
static const int NETMSG_TYPE_BITS = 5; // SVC_Print overhead for netmsg type
|
||||
static const int SVC_Print_BufferSize = 2048 - 1; // -1 for terminating \0
|
||||
};
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
void CmdMaxplayersCallback(const CCommandContext &context, const CCommand &command);
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CmdMaxplayersCallback(const CCommand &command);
|
||||
#else
|
||||
void CmdMaxplayersCallback();
|
||||
|
||||
+3
-9
@@ -69,13 +69,6 @@ class DefaultMapTimer :
|
||||
public IConVarChangeListener
|
||||
{
|
||||
public:
|
||||
|
||||
#if SOURCE_ENGINE == SE_BMS
|
||||
static constexpr int kMapTimeScaleFactor = 60;
|
||||
#else
|
||||
static constexpr int kMapTimeScaleFactor = 1;
|
||||
#endif
|
||||
|
||||
DefaultMapTimer()
|
||||
{
|
||||
m_bInUse = false;
|
||||
@@ -88,7 +81,7 @@ public:
|
||||
|
||||
int GetMapTimeLimit()
|
||||
{
|
||||
return (mp_timelimit->GetInt() / kMapTimeScaleFactor);
|
||||
return mp_timelimit->GetInt();
|
||||
}
|
||||
|
||||
void SetMapTimerStatus(bool enabled)
|
||||
@@ -112,7 +105,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
extra_time /= (60 / kMapTimeScaleFactor);
|
||||
extra_time /= 60;
|
||||
|
||||
mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
|
||||
}
|
||||
@@ -491,3 +484,4 @@ bool TimerSystem::GetMapTimeLeft(float *time_left)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+23
-95
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2013 AlliedModders LLC. All rights reserved.
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
#include <sh_list.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
#define GETCHECK_FIELD() \
|
||||
const protobuf::FieldDescriptor *field = msg->GetDescriptor()->FindFieldByName(pszFieldName); \
|
||||
@@ -118,13 +117,6 @@ public:
|
||||
return msg;
|
||||
}
|
||||
|
||||
inline bool HasField(const char *pszFieldName)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
return msg->GetReflection()->HasField(*msg, field);
|
||||
}
|
||||
|
||||
inline bool GetInt32(const char *pszFieldName, int32 *out)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
@@ -348,20 +340,6 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetInt64OrUnsigned(const char *pszFieldName, int64 *out)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE2(INT64, UINT64);
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
|
||||
if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT64)
|
||||
*out = (int64)msg->GetReflection()->GetUInt64(*msg, field);
|
||||
else
|
||||
*out = msg->GetReflection()->GetInt64(*msg, field);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SetInt32OrUnsignedOrEnum(const char *pszFieldName, int32 value)
|
||||
{
|
||||
@@ -388,24 +366,6 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SetInt64OrUnsigned(const char *pszFieldName, int64 value)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE2(INT64, UINT64);
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
|
||||
if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT64)
|
||||
{
|
||||
msg->GetReflection()->SetUInt64(msg, field, (uint64)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->GetReflection()->SetInt64(msg, field, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetRepeatedInt32OrUnsignedOrEnum(const char *pszFieldName, int index, int32 *out)
|
||||
{
|
||||
@@ -423,21 +383,6 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetRepeatedInt64OrUnsigned(const char *pszFieldName, int index, int64 *out)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE2(INT64, UINT64);
|
||||
CHECK_FIELD_REPEATED();
|
||||
CHECK_REPEATED_ELEMENT(index);
|
||||
|
||||
if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT64)
|
||||
*out = (int64)msg->GetReflection()->GetRepeatedUInt64(*msg, field, index);
|
||||
else
|
||||
*out = msg->GetReflection()->GetRepeatedInt64(*msg, field, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SetRepeatedInt32OrUnsignedOrEnum(const char *pszFieldName, int index, int32 value)
|
||||
{
|
||||
@@ -465,25 +410,6 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SetRepeatedInt64OrUnsigned(const char *pszFieldName, int index, int64 value)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE2(INT64, UINT64);
|
||||
CHECK_FIELD_REPEATED();
|
||||
CHECK_REPEATED_ELEMENT(index);
|
||||
|
||||
if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT64)
|
||||
{
|
||||
msg->GetReflection()->SetRepeatedUInt64(msg, field, index, (uint64)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->GetReflection()->SetRepeatedInt64(msg, field, index, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool AddInt32OrUnsignedOrEnum(const char *pszFieldName, int32 value)
|
||||
{
|
||||
@@ -510,24 +436,6 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool AddInt64OrUnsigned(const char *pszFieldName, int64 value)
|
||||
{
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE2(INT64, UINT64);
|
||||
CHECK_FIELD_REPEATED();
|
||||
|
||||
if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT64)
|
||||
{
|
||||
msg->GetReflection()->AddUInt64(msg, field, (uint64)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->GetReflection()->AddInt64(msg, field, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetBool(const char *pszFieldName, bool *out)
|
||||
{
|
||||
@@ -764,7 +672,7 @@ public:
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
|
||||
std::string scratch;
|
||||
ke::SafeStrcpy(out, size, msg->GetReflection()->GetStringReference(*msg, field, &scratch).c_str());
|
||||
strncopy(out, msg->GetReflection()->GetStringReference(*msg, field, &scratch).c_str(), size);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -787,7 +695,7 @@ public:
|
||||
CHECK_REPEATED_ELEMENT(index);
|
||||
|
||||
std::string scratch;
|
||||
ke::SafeStrcpy(out, size, msg->GetReflection()->GetRepeatedStringReference(*msg, field, index, &scratch).c_str());
|
||||
strncopy(out, msg->GetReflection()->GetRepeatedStringReference(*msg, field, index, &scratch).c_str(), size);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -816,6 +724,9 @@ public:
|
||||
|
||||
inline bool GetColor(const char *pszFieldName, Color *out)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
@@ -829,10 +740,14 @@ public:
|
||||
);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool SetColor(const char *pszFieldName, const Color &value)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
@@ -844,10 +759,14 @@ public:
|
||||
msgRGBA->set_a(value.a());
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_REPEATED();
|
||||
@@ -862,10 +781,14 @@ public:
|
||||
);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_REPEATED();
|
||||
@@ -878,10 +801,14 @@ public:
|
||||
msgRGBA->set_a(value.a());
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool AddColor(const char *pszFieldName, const Color &value)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_REPEATED();
|
||||
@@ -893,6 +820,7 @@ public:
|
||||
msgRGBA->set_a(value.a());
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
|
||||
|
||||
+38
-47
@@ -33,18 +33,15 @@
|
||||
#include "sm_stringutil.h"
|
||||
#include "logic_bridge.h"
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
#include <dota_usermessage_helpers.h>
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
#include <cstrike15_usermessage_helpers.h>
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
#include <berimbau_usermessage_helpers.h>
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
#include <vietnam_usermessage_helpers.h>
|
||||
#endif
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
UserMessages g_UserMsgs;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||
#else
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
@@ -53,7 +50,7 @@ SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRec
|
||||
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
||||
#endif
|
||||
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
||||
#endif // ==SE_CSGO || ==SE_BLADE || ==SE_MCV
|
||||
#endif // ==SE_CSGO
|
||||
|
||||
UserMessages::UserMessages()
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
@@ -97,7 +94,7 @@ void UserMessages::OnSourceModAllShutdown()
|
||||
{
|
||||
if (m_HookCount)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||
#else
|
||||
@@ -112,13 +109,12 @@ void UserMessages::OnSourceModAllShutdown()
|
||||
|
||||
int UserMessages::GetMessageIndex(const char *msg)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
// Can split this per engine and/or game later
|
||||
return g_DotaUsermessageHelpers.GetIndex(msg);
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
// Can split this per engine and/or game later
|
||||
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
return g_BerimbauUsermessageHelpers.GetIndex(msg);
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
return g_VietnamUsermessageHelpers.GetIndex(msg);
|
||||
#else
|
||||
|
||||
int msgid;
|
||||
@@ -154,17 +150,15 @@ int UserMessages::GetMessageIndex(const char *msg)
|
||||
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
const char *pszName = g_DotaUsermessageHelpers.GetName(msgid);
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msgid);
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
const char *pszName = g_VietnamUsermessageHelpers.GetName(msgid);
|
||||
#endif
|
||||
if (!pszName)
|
||||
return false;
|
||||
|
||||
ke::SafeStrcpy(buffer, maxlength, pszName);
|
||||
strncopy(buffer, pszName, maxlength);
|
||||
return true;
|
||||
#else
|
||||
if (m_FallbackSearch)
|
||||
@@ -177,7 +171,7 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
||||
|
||||
if (msg)
|
||||
{
|
||||
ke::SafeStrcpy(buffer, maxlength, msg);
|
||||
strncopy(buffer, msg, maxlength);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -309,7 +303,7 @@ bool UserMessages::EndMessage()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
@@ -339,7 +333,7 @@ bool UserMessages::EndMessage()
|
||||
} else {
|
||||
engine->MessageEnd();
|
||||
}
|
||||
#endif // SE_CSGO || SE_BLADE || SE_MCV
|
||||
#endif // SE_CSGO || SE_DOTA
|
||||
|
||||
m_InExec = false;
|
||||
m_CurFlags = 0;
|
||||
@@ -424,7 +418,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
||||
|
||||
if (!m_HookCount++)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||
#else
|
||||
@@ -448,12 +442,10 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
return g_DotaUsermessageHelpers.GetPrototype(msg_type);
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
return g_BerimbauUsermessageHelpers.GetPrototype(msg_type);
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
return g_VietnamUsermessageHelpers.GetPrototype(msg_type);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -503,7 +495,7 @@ void UserMessages::_DecRefCounter()
|
||||
{
|
||||
if (--m_HookCount == 0)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||
#else
|
||||
@@ -515,19 +507,14 @@ void UserMessages::_DecRefCounter()
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msg_type);
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msg_type);
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
const char *pszName = g_VietnamUsermessageHelpers.GetName(msg_type);
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
||||
#endif
|
||||
|
||||
OnStartMessage_Pre(&filter, msg_type, pszName);
|
||||
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
{
|
||||
int size = msg.ByteSize();
|
||||
@@ -540,7 +527,11 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
|
||||
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
||||
}
|
||||
|
||||
OnStartMessage_Post(&filter, msg_type, pszName);
|
||||
#if SOURCE_ENGINE == SE_DOTA
|
||||
OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
||||
#endif
|
||||
|
||||
OnMessageEnd_Pre();
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
@@ -572,7 +563,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
|
||||
RETURN_META(res)
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
@@ -612,7 +603,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
@@ -777,7 +768,7 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
|
||||
if (!handled && intercepted)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||
#else
|
||||
bf_write *engine_bfw;
|
||||
@@ -789,11 +780,11 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
||||
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
||||
ENGINE_CALL(MessageEnd)();
|
||||
#endif // SE_CSGO || SE_BLADE || SE_MCV
|
||||
#endif // SE_CSGO || SE_DOTA
|
||||
}
|
||||
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
int size = m_OrigBuffer->ByteSize();
|
||||
uint8 *data = (uint8 *)stackalloc(size);
|
||||
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||
@@ -823,7 +814,7 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
iter++;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
delete pTempMsg;
|
||||
#endif
|
||||
}
|
||||
|
||||
+3
-3
@@ -44,7 +44,7 @@
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
#define USE_PROTOBUF_USERMESSAGES
|
||||
#endif
|
||||
|
||||
@@ -102,12 +102,12 @@ public: //IUserMessages
|
||||
bool intercept=false);
|
||||
UserMessageType GetUserMessageType() const;
|
||||
public:
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
|
||||
@@ -1,77 +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_CCOMMANDARGS_IMPL_H_
|
||||
#define _INCLUDE_SOURCEMOD_CCOMMANDARGS_IMPL_H_
|
||||
|
||||
#include "sourcemm_api.h"
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <compat_wrappers.h>
|
||||
|
||||
#if SOURCE_ENGINE==SE_EPISODEONE || SOURCE_ENGINE==SE_DARKMESSIAH
|
||||
class EngineArgs : public ICommandArgs
|
||||
{
|
||||
public:
|
||||
EngineArgs(const CCommand& _cmd)
|
||||
{
|
||||
}
|
||||
const char *Arg(int n) const
|
||||
{
|
||||
return engine->Cmd_Argv(n);
|
||||
}
|
||||
int ArgC() const
|
||||
{
|
||||
return engine->Cmd_Argc();
|
||||
}
|
||||
const char *ArgS() const
|
||||
{
|
||||
return engine->Cmd_Args();
|
||||
}
|
||||
};
|
||||
#else
|
||||
class EngineArgs : public ICommandArgs
|
||||
{
|
||||
const CCommand *cmd;
|
||||
public:
|
||||
EngineArgs(const CCommand& _cmd) : cmd(&_cmd)
|
||||
{
|
||||
}
|
||||
const char *Arg(int n) const
|
||||
{
|
||||
return cmd->Arg(n);
|
||||
}
|
||||
int ArgC() const
|
||||
{
|
||||
return cmd->ArgC();
|
||||
}
|
||||
const char *ArgS() const
|
||||
{
|
||||
return cmd->ArgS();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_CCOMMANDARGS_IMPL_H_
|
||||
+64
-48
@@ -1,29 +1,33 @@
|
||||
// vim: set ts=4 sw=4 tw=99 et:
|
||||
// =============================================================================
|
||||
// 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$
|
||||
*/
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include <sh_list.h>
|
||||
@@ -32,15 +36,10 @@
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "compat_wrappers.h"
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
|
||||
#else
|
||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#endif
|
||||
#else
|
||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#endif
|
||||
@@ -82,11 +81,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
|
||||
#else
|
||||
void LinkConCommandBase(ConCommandBase *pBase)
|
||||
#endif
|
||||
{
|
||||
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||
while (listener)
|
||||
@@ -108,19 +103,40 @@ public:
|
||||
listener = listener->next;
|
||||
}
|
||||
|
||||
while (iter != tracked_bases.end())
|
||||
if (pBase)
|
||||
{
|
||||
if ((*iter)->pBase == pBase)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
iter = tracked_bases.erase(iter);
|
||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
|
||||
delete pInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
while (iter != tracked_bases.end())
|
||||
{
|
||||
if ((*iter)->pBase == pBase)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
iter = tracked_bases.erase(iter);
|
||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true);
|
||||
delete pInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (iter != tracked_bases.end())
|
||||
{
|
||||
/* This is just god-awful! */
|
||||
if (FindCommandBase((*iter)->name) != (*iter)->pBase)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
iter = tracked_bases.erase(iter);
|
||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pInfo->name, false);
|
||||
delete pInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +146,7 @@ public:
|
||||
|
||||
info->pBase = pBase;
|
||||
info->cls = cls;
|
||||
ke::SafeStrcpy(info->name, sizeof(info->name), pBase->GetName());
|
||||
strncopy(info->name, pBase->GetName(), sizeof(info->name));
|
||||
|
||||
tracked_bases.push_back(info);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
class IConCommandTracker
|
||||
{
|
||||
public:
|
||||
virtual void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) = 0;
|
||||
virtual void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe) = 0;
|
||||
};
|
||||
|
||||
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||
|
||||
@@ -0,0 +1,551 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: 2006-08-13 06:34:30 -0500 (Sun, 13 Aug 2006) $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CONVAR_H
|
||||
#define CONVAR_H
|
||||
#if _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FORCEINLINE_CVAR FORCEINLINE
|
||||
#elif _LINUX
|
||||
#define FORCEINLINE_CVAR __inline__ FORCEINLINE
|
||||
#else
|
||||
#error "implement me"
|
||||
#endif
|
||||
|
||||
// The default, no flags at all
|
||||
#define FCVAR_NONE 0
|
||||
|
||||
// Command to ConVars and ConCommands
|
||||
// ConVar Systems
|
||||
#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc.
|
||||
#define FCVAR_LAUNCHER (1<<1) // defined by launcher
|
||||
#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL
|
||||
#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL
|
||||
#define FCVAR_MATERIAL_SYSTEM (1<<4) // Defined by the material system.
|
||||
#define FCVAR_DATACACHE (1<<19) // Defined by the datacache system.
|
||||
#define FCVAR_STUDIORENDER (1<<15) // Defined by the studiorender system.
|
||||
#define FCVAR_FILESYSTEM (1<<21) // Defined by the file system.
|
||||
#define FCVAR_PLUGIN (1<<18) // Defined by a 3rd party plugin.
|
||||
#define FCVAR_TOOLSYSTEM (1<<20) // Defined by an IToolSystem library
|
||||
#define FCVAR_SOUNDSYSTEM (1<<23) // Defined by the soundsystem library
|
||||
#define FCVAR_INPUTSYSTEM (1<<25) // Defined by the inputsystem dll
|
||||
#define FCVAR_NETWORKSYSTEM (1<<26) // Defined by the network system
|
||||
// NOTE!! if you add a cvar system, add it here too!!!!
|
||||
// the engine lacks a cvar flag, but needs it for xbox
|
||||
// an engine cvar is thus a cvar not marked with any other system
|
||||
#define FCVAR_NON_ENGINE ((FCVAR_LAUNCHER|FCVAR_GAMEDLL|FCVAR_CLIENTDLL|FCVAR_MATERIAL_SYSTEM|FCVAR_DATACACHE|FCVAR_STUDIORENDER|FCVAR_FILESYSTEM|FCVAR_PLUGIN|FCVAR_TOOLSYSTEM|FCVAR_SOUNDSYSTEM|FCVAR_INPUTSYSTEM|FCVAR_NETWORKSYSTEM))
|
||||
|
||||
// ConVar only
|
||||
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
|
||||
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
|
||||
#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc
|
||||
#define FCVAR_NOTIFY (1<<8) // notifies players when changed
|
||||
#define FCVAR_USERINFO (1<<9) // changes the client's info string
|
||||
#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats
|
||||
|
||||
#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
|
||||
#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
|
||||
#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar
|
||||
|
||||
// It's a ConVar that's shared between the client and the server.
|
||||
// At signon, the values of all such ConVars are sent from the server to the client (skipped for local
|
||||
// client, of course )
|
||||
// If a change is requested it must come from the console (i.e., no remote client changes)
|
||||
// If a value is changed while a server is active, it's replicated to all connected clients
|
||||
#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time
|
||||
#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file
|
||||
#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles
|
||||
|
||||
#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server
|
||||
|
||||
#define FCVAR_ARCHIVE_XBOX (1<<24) // cvar written to config.cfg on the Xbox
|
||||
|
||||
|
||||
// #define FCVAR_AVAILABLE (1<<27)
|
||||
// #define FCVAR_AVAILABLE (1<<28)
|
||||
// #define FCVAR_AVAILABLE (1<<29)
|
||||
// #define FCVAR_AVAILABLE (1<<30)
|
||||
// #define FCVAR_AVAILABLE (1<<31)
|
||||
|
||||
|
||||
class ConVar;
|
||||
class ConCommand;
|
||||
class ConCommandBase;
|
||||
|
||||
// Any executable that wants to use ConVars need to implement one of
|
||||
// these to hook up access to console variables.
|
||||
class IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
// Flags is a combination of FCVAR flags in cvar.h.
|
||||
// hOut is filled in with a handle to the variable.
|
||||
virtual bool RegisterConCommandBase( ConCommandBase *pVar )=0;
|
||||
};
|
||||
|
||||
|
||||
// You don't have to instantiate one of these, just call its
|
||||
// OneTimeInit function when your executable is initializing.
|
||||
class ConCommandBaseMgr
|
||||
{
|
||||
public:
|
||||
// Call this ONCE when the executable starts up.
|
||||
static void OneTimeInit( IConCommandBaseAccessor *pAccessor );
|
||||
#ifdef _XBOX
|
||||
static bool Fixup( ConCommandBase* pConCommandBase );
|
||||
#ifndef _RETAIL
|
||||
static void PublishCommands( bool bForce );
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
// Called when a ConVar changes value
|
||||
typedef void ( *FnChangeCallback )( ConVar *var, char const *pOldString );
|
||||
|
||||
// Called when a ConCommand needs to execute
|
||||
typedef void ( *FnCommandCallback )( void );
|
||||
|
||||
#define COMMAND_COMPLETION_MAXITEMS 64
|
||||
#define COMMAND_COMPLETION_ITEM_LENGTH 64
|
||||
|
||||
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
|
||||
typedef int ( *FnCommandCompletionCallback )( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The base console invoked command/cvar interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommandBase
|
||||
{
|
||||
friend class ConCommandBaseMgr;
|
||||
friend class CCvar;
|
||||
friend class ConVar;
|
||||
friend class ConCommand;
|
||||
|
||||
public:
|
||||
ConCommandBase( void );
|
||||
ConCommandBase( char const *pName, char const *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
virtual ~ConCommandBase( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
// Check flag
|
||||
virtual bool IsBitSet( int flag ) const;
|
||||
// Set flag
|
||||
virtual void AddFlags( int flags );
|
||||
|
||||
// Return name of cvar
|
||||
virtual char const *GetName( void ) const;
|
||||
|
||||
// Return help text for cvar
|
||||
virtual char const *GetHelpText( void ) const;
|
||||
|
||||
// Deal with next pointer
|
||||
const ConCommandBase *GetNext( void ) const;
|
||||
void SetNext( ConCommandBase *next );
|
||||
|
||||
virtual bool IsRegistered( void ) const;
|
||||
|
||||
// Global methods
|
||||
static ConCommandBase const *GetCommands( void );
|
||||
static void AddToList( ConCommandBase *var );
|
||||
static void RemoveFlaggedCommands( int flag );
|
||||
static void RevertFlaggedCvars( int flag );
|
||||
static ConCommandBase const *FindCommand( char const *name );
|
||||
|
||||
protected:
|
||||
virtual void Create( char const *pName, char const *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
// Used internally by OneTimeInit to initialize.
|
||||
virtual void Init();
|
||||
|
||||
// Internal copy routine ( uses new operator from correct module )
|
||||
char *CopyString( char const *from );
|
||||
|
||||
// Next ConVar in chain
|
||||
ConCommandBase *m_pNext;
|
||||
|
||||
private:
|
||||
// Has the cvar been added to the global list?
|
||||
bool m_bRegistered;
|
||||
|
||||
// Static data
|
||||
char const *m_pszName;
|
||||
char const *m_pszHelpString;
|
||||
|
||||
// ConVar flags
|
||||
int m_nFlags;
|
||||
|
||||
protected:
|
||||
|
||||
// ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through
|
||||
// all the console variables and registers them.
|
||||
static ConCommandBase *s_pConCommandBases;
|
||||
|
||||
// ConVars in this executable use this 'global' to access values.
|
||||
static IConCommandBaseAccessor *s_pAccessor;
|
||||
|
||||
public: // Hackalicous
|
||||
inline int GetFlags() const
|
||||
{
|
||||
return m_nFlags;
|
||||
}
|
||||
inline void SetFlags(int flags)
|
||||
{
|
||||
m_nFlags = flags;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The console invoked command
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommand : public ConCommandBase
|
||||
{
|
||||
friend class ConCommandBaseMgr;
|
||||
friend class CCvar;
|
||||
#ifdef _STATIC_LINKED
|
||||
friend class G_ConCommand;
|
||||
friend class C_ConCommand;
|
||||
friend class M_ConCommand;
|
||||
friend class S_ConCommand;
|
||||
friend class D_ConCommand;
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConCommand( void );
|
||||
ConCommand( char const *pName, FnCommandCallback callback,
|
||||
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
|
||||
virtual ~ConCommand( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
virtual int AutoCompleteSuggest( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
|
||||
|
||||
virtual bool CanAutoComplete( void );
|
||||
|
||||
// Invoke the function
|
||||
virtual void Dispatch( void );
|
||||
private:
|
||||
virtual void Create( char const *pName, FnCommandCallback callback,
|
||||
char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
|
||||
// Call this function when executing the command
|
||||
FnCommandCallback m_fnCommandCallback;
|
||||
|
||||
FnCommandCompletionCallback m_fnCompletionCallback;
|
||||
bool m_bHasCompletionCallback;
|
||||
public: // Hackalicous
|
||||
inline FnCommandCallback GetCallback() const
|
||||
{
|
||||
return m_fnCommandCallback;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A console variable
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar : public ConCommandBase
|
||||
{
|
||||
friend class ConCommandBaseMgr;
|
||||
friend class CCvar;
|
||||
friend class CDefaultCvar;
|
||||
#ifdef _STATIC_LINKED
|
||||
friend class G_ConVar;
|
||||
friend class C_ConVar;
|
||||
friend class M_ConVar;
|
||||
friend class S_ConVar;
|
||||
friend class D_ConVar;
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConVar( char const *pName, char const *pDefaultValue, int flags = 0);
|
||||
|
||||
ConVar( char const *pName, char const *pDefaultValue, int flags,
|
||||
char const *pHelpString );
|
||||
ConVar( char const *pName, char const *pDefaultValue, int flags,
|
||||
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
|
||||
ConVar( char const *pName, char const *pDefaultValue, int flags,
|
||||
char const *pHelpString, FnChangeCallback callback );
|
||||
ConVar( char const *pName, char const *pDefaultValue, int flags,
|
||||
char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
|
||||
FnChangeCallback callback );
|
||||
|
||||
virtual ~ConVar( void );
|
||||
|
||||
virtual bool IsBitSet( int flag ) const;
|
||||
virtual char const* GetHelpText( void ) const;
|
||||
virtual bool IsRegistered( void ) const;
|
||||
virtual char const *GetName( void ) const;
|
||||
virtual void AddFlags( int flags );
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
// Install a change callback (there shouldn't already be one....)
|
||||
void InstallChangeCallback( FnChangeCallback callback );
|
||||
|
||||
// Retrieve value
|
||||
FORCEINLINE_CVAR float GetFloat( void ) const;
|
||||
FORCEINLINE_CVAR int GetInt( void ) const;
|
||||
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
|
||||
FORCEINLINE_CVAR char const *GetString( void ) const;
|
||||
|
||||
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
|
||||
// from alloc/free across dll/exe boundaries.
|
||||
|
||||
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
|
||||
virtual void SetValue( char const *value );
|
||||
virtual void SetValue( float value );
|
||||
virtual void SetValue( int value );
|
||||
|
||||
// Reset to default value
|
||||
void Revert( void );
|
||||
|
||||
// True if it has a min/max setting
|
||||
bool GetMin( float& minVal ) const;
|
||||
bool GetMax( float& maxVal ) const;
|
||||
char const *GetDefault( void ) const;
|
||||
|
||||
static void RevertAll( void );
|
||||
private:
|
||||
// Called by CCvar when the value of a var is changing.
|
||||
virtual void InternalSetValue(char const *value);
|
||||
// For CVARs marked FCVAR_NEVER_AS_STRING
|
||||
virtual void InternalSetFloatValue( float fNewValue );
|
||||
virtual void InternalSetIntValue( int nValue );
|
||||
|
||||
virtual bool ClampValue( float& value );
|
||||
virtual void ChangeStringValue( char const *tempVal );
|
||||
|
||||
virtual void Create( char const *pName, char const *pDefaultValue, int flags = 0,
|
||||
char const *pHelpString = 0, bool bMin = false, float fMin = 0.0,
|
||||
bool bMax = false, float fMax = false, FnChangeCallback callback = 0 );
|
||||
|
||||
// Used internally by OneTimeInit to initialize.
|
||||
virtual void Init();
|
||||
|
||||
private:
|
||||
|
||||
// This either points to "this" or it points to the original declaration of a ConVar.
|
||||
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
|
||||
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
|
||||
ConVar *m_pParent;
|
||||
|
||||
// Static data
|
||||
char const *m_pszDefaultValue;
|
||||
|
||||
// Value
|
||||
// Dynamically allocated
|
||||
char *m_pszString;
|
||||
int m_StringLength;
|
||||
|
||||
// Values
|
||||
float m_fValue;
|
||||
int m_nValue;
|
||||
|
||||
// Min/Max values
|
||||
bool m_bHasMin;
|
||||
float m_fMinVal;
|
||||
bool m_bHasMax;
|
||||
float m_fMaxVal;
|
||||
|
||||
// Call this function when ConVar changes
|
||||
FnChangeCallback m_fnChangeCallback;
|
||||
public: // Hackalicous
|
||||
inline FnChangeCallback GetCallback() const
|
||||
{
|
||||
return m_fnChangeCallback;
|
||||
}
|
||||
inline void SetMin(bool set, float min=0.0)
|
||||
{
|
||||
m_bHasMin = set;
|
||||
m_fMinVal = min;
|
||||
}
|
||||
inline void SetMax(bool set, float max=0.0)
|
||||
{
|
||||
m_bHasMax = set;
|
||||
m_fMaxVal = max;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
|
||||
{
|
||||
return m_pParent->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
|
||||
{
|
||||
return m_pParent->m_nValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
// Output : char const *
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR char const *ConVar::GetString( void ) const
|
||||
{
|
||||
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
|
||||
{
|
||||
return "FCVAR_NEVER_AS_STRING";
|
||||
}
|
||||
|
||||
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
|
||||
}
|
||||
|
||||
|
||||
#ifdef _STATIC_LINKED
|
||||
// identifies subsystem via piggybacking constructors with flags
|
||||
class G_ConCommand : public ConCommand
|
||||
{
|
||||
public:
|
||||
G_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_GAMEDLL, completionFunc) {}
|
||||
};
|
||||
|
||||
class C_ConCommand : public ConCommand
|
||||
{
|
||||
public:
|
||||
C_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_CLIENTDLL, completionFunc) {}
|
||||
};
|
||||
|
||||
class M_ConCommand : public ConCommand
|
||||
{
|
||||
public:
|
||||
M_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_MATERIAL_SYSTEM, completionFunc) {}
|
||||
};
|
||||
|
||||
class S_ConCommand : public ConCommand
|
||||
{
|
||||
public:
|
||||
S_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_STUDIORENDER, completionFunc) {}
|
||||
};
|
||||
|
||||
class D_ConCommand : public ConCommand
|
||||
{
|
||||
public:
|
||||
D_ConCommand(char const *pName, FnCommandCallback callback, char const *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ) : ConCommand(pName, callback, pHelpString, flags|FCVAR_DATACACHE, completionFunc) {}
|
||||
};
|
||||
|
||||
typedef void ( *G_FnChangeCallback )( G_ConVar *var, char const *pOldString );
|
||||
typedef void ( *C_FnChangeCallback )( C_ConVar *var, char const *pOldString );
|
||||
typedef void ( *M_FnChangeCallback )( M_ConVar *var, char const *pOldString );
|
||||
typedef void ( *S_FnChangeCallback )( S_ConVar *var, char const *pOldString );
|
||||
typedef void ( *D_FnChangeCallback )( D_ConVar *var, char const *pOldString );
|
||||
|
||||
class G_ConVar : public ConVar
|
||||
{
|
||||
public:
|
||||
G_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL) {}
|
||||
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString ) {}
|
||||
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax) {}
|
||||
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, (FnChangeCallback)callback ) {}
|
||||
G_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, G_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_GAMEDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
|
||||
};
|
||||
|
||||
class C_ConVar : public ConVar
|
||||
{
|
||||
public:
|
||||
C_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL) {}
|
||||
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString ) {}
|
||||
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax) {}
|
||||
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, (FnChangeCallback)callback ) {}
|
||||
C_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, C_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_CLIENTDLL, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
|
||||
};
|
||||
|
||||
class M_ConVar : public ConVar
|
||||
{
|
||||
public:
|
||||
M_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM) {}
|
||||
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString ) {}
|
||||
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax) {}
|
||||
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, (FnChangeCallback)callback ) {}
|
||||
M_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_MATERIAL_SYSTEM, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
|
||||
};
|
||||
|
||||
class S_ConVar : public ConVar
|
||||
{
|
||||
public:
|
||||
S_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER) {}
|
||||
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString ) {}
|
||||
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax) {}
|
||||
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, (FnChangeCallback)callback ) {}
|
||||
S_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, S_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_STUDIORENDER, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
|
||||
};
|
||||
|
||||
class D_ConVar : public ConVar
|
||||
{
|
||||
public:
|
||||
D_ConVar( char const *pName, char const *pDefaultValue, int flags = 0) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE) {}
|
||||
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString ) {}
|
||||
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax) {}
|
||||
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, M_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, (FnChangeCallback)callback ) {}
|
||||
D_ConVar( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax, D_FnChangeCallback callback ) : ConVar(pName, pDefaultValue, flags|FCVAR_DATACACHE, pHelpString, bMin, fMin, bMax, fMax, (FnChangeCallback)callback ) {}
|
||||
};
|
||||
|
||||
// redirect these declarations to their specific subsystem
|
||||
#ifdef GAME_DLL
|
||||
#define ConCommand G_ConCommand
|
||||
#define ConVar G_ConVar
|
||||
#endif
|
||||
#ifdef CLIENT_DLL
|
||||
#define ConCommand C_ConCommand
|
||||
#define ConVar C_ConVar
|
||||
#endif
|
||||
#ifdef MATERIALSYSTEM_DLL
|
||||
#define ConCommand M_ConCommand
|
||||
#define ConVar M_ConVar
|
||||
#endif
|
||||
#ifdef STUDIORENDER_DLL
|
||||
#define ConCommand S_ConCommand
|
||||
#define ConVar S_ConVar
|
||||
#endif
|
||||
#ifdef DATACACHE_DLL
|
||||
#define ConCommand D_ConCommand
|
||||
#define ConVar D_ConVar
|
||||
#endif
|
||||
#endif // _STATIC_LINKED
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility to quicky generate a simple console command
|
||||
//-----------------------------------------------------------------------------
|
||||
#define CON_COMMAND( name, description ) \
|
||||
static void name(); \
|
||||
static ConCommand name##_command( #name, name, description ); \
|
||||
static void name()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility to quicky generate a simple console command
|
||||
//-----------------------------------------------------------------------------
|
||||
#define CON_COMMAND_F( name, description, flags ) \
|
||||
static void name(); \
|
||||
static ConCommand name##_command( #name, name, description, flags ); \
|
||||
static void name()
|
||||
|
||||
|
||||
#endif // CONVAR_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,718 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef CONVAR_H
|
||||
#define CONVAR_H
|
||||
|
||||
#if _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/iconvar.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utlstring.h"
|
||||
#include "icvar.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FORCEINLINE_CVAR FORCEINLINE
|
||||
#elif defined _LINUX || defined __APPLE__
|
||||
#define FORCEINLINE_CVAR inline
|
||||
#else
|
||||
#error "implement me"
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar;
|
||||
class CCommand;
|
||||
class ConCommand;
|
||||
class ConCommandBase;
|
||||
struct characterset_t;
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Any executable that wants to use ConVars need to implement one of
|
||||
// these to hook up access to console variables.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
// Flags is a combination of FCVAR flags in cvar.h.
|
||||
// hOut is filled in with a handle to the variable.
|
||||
virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method for console development
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( _X360 ) && !defined( _RETAIL )
|
||||
void ConVar_PublishToVXConsole();
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called when a ConCommand needs to execute
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef void ( *FnCommandCallbackV1_t )( void );
|
||||
typedef void ( *FnCommandCallback_t )( const CCommand &command );
|
||||
|
||||
#define COMMAND_COMPLETION_MAXITEMS 64
|
||||
#define COMMAND_COMPLETION_ITEM_LENGTH 64
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Interface version
|
||||
//-----------------------------------------------------------------------------
|
||||
class ICommandCallback
|
||||
{
|
||||
public:
|
||||
virtual void CommandCallback( const CCommand &command ) = 0;
|
||||
};
|
||||
|
||||
class ICommandCompletionCallback
|
||||
{
|
||||
public:
|
||||
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The base console invoked command/cvar interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommandBase
|
||||
{
|
||||
friend class CCvar;
|
||||
friend class ConVar;
|
||||
friend class ConCommand;
|
||||
friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor );
|
||||
friend void ConVar_PublishToVXConsole();
|
||||
|
||||
// FIXME: Remove when ConVar changes are done
|
||||
friend class CDefaultCvar;
|
||||
|
||||
public:
|
||||
ConCommandBase( void );
|
||||
ConCommandBase( const char *pName, const char *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
virtual ~ConCommandBase( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
// Check flag
|
||||
virtual bool IsFlagSet( int flag ) const;
|
||||
// Set flag
|
||||
virtual void AddFlags( int flags );
|
||||
// Remove flag
|
||||
virtual void RemoveFlags( int flags );
|
||||
// Get flags
|
||||
virtual int GetFlags( void ) const;
|
||||
|
||||
// Return name of cvar
|
||||
virtual const char *GetName( void ) const;
|
||||
|
||||
// Return help text for cvar
|
||||
virtual const char *GetHelpText( void ) const;
|
||||
|
||||
// Deal with next pointer
|
||||
const ConCommandBase *GetNext( void ) const;
|
||||
ConCommandBase *GetNext( void );
|
||||
|
||||
inline void SetNext(ConCommandBase *pBase)
|
||||
{
|
||||
m_pNext = pBase;
|
||||
}
|
||||
|
||||
virtual bool IsRegistered( void ) const;
|
||||
|
||||
// Returns the DLL identifier
|
||||
virtual CVarDLLIdentifier_t GetDLLIdentifier() const;
|
||||
|
||||
protected:
|
||||
virtual void Create( const char *pName, const char *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
// Used internally by OneTimeInit to initialize/shutdown
|
||||
virtual void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Internal copy routine ( uses new operator from correct module )
|
||||
char *CopyString( const char *from );
|
||||
|
||||
private:
|
||||
// Next ConVar in chain
|
||||
// Prior to register, it points to the next convar in the DLL.
|
||||
// Once registered, though, m_pNext is reset to point to the next
|
||||
// convar in the global list
|
||||
ConCommandBase *m_pNext;
|
||||
|
||||
// Has the cvar been added to the global list?
|
||||
bool m_bRegistered;
|
||||
|
||||
// Static data
|
||||
const char *m_pszName;
|
||||
const char *m_pszHelpString;
|
||||
|
||||
// ConVar flags
|
||||
int m_nFlags;
|
||||
|
||||
protected:
|
||||
// ConVars add themselves to this list for the executable.
|
||||
// Then ConVar_Register runs through all the console variables
|
||||
// and registers them into a global list stored in vstdlib.dll
|
||||
static ConCommandBase *s_pConCommandBases;
|
||||
|
||||
// ConVars in this executable use this 'global' to access values.
|
||||
static IConCommandBaseAccessor *s_pAccessor;
|
||||
public:
|
||||
inline void SetFlags(int flags)
|
||||
{
|
||||
m_nFlags = flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command tokenizer
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCommand
|
||||
{
|
||||
public:
|
||||
CCommand();
|
||||
CCommand( int nArgC, const char **ppArgV );
|
||||
bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL );
|
||||
void Reset();
|
||||
|
||||
int ArgC() const;
|
||||
const char **ArgV() const;
|
||||
const char *ArgS() const; // All args that occur after the 0th arg, in string form
|
||||
const char *GetCommandString() const; // The entire command in string form, including the 0th arg
|
||||
const char *operator[]( int nIndex ) const; // Gets at arguments
|
||||
const char *Arg( int nIndex ) const; // Gets at arguments
|
||||
|
||||
// Helper functions to parse arguments to commands.
|
||||
const char* FindArg( const char *pName ) const;
|
||||
int FindArgInt( const char *pName, int nDefaultVal ) const;
|
||||
|
||||
static int MaxCommandLength();
|
||||
static characterset_t* DefaultBreakSet();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
COMMAND_MAX_ARGC = 64,
|
||||
COMMAND_MAX_LENGTH = 512,
|
||||
};
|
||||
|
||||
int m_nArgc;
|
||||
int m_nArgv0Size;
|
||||
char m_pArgSBuffer[ COMMAND_MAX_LENGTH ];
|
||||
char m_pArgvBuffer[ COMMAND_MAX_LENGTH ];
|
||||
const char* m_ppArgv[ COMMAND_MAX_ARGC ];
|
||||
};
|
||||
|
||||
inline int CCommand::MaxCommandLength()
|
||||
{
|
||||
return COMMAND_MAX_LENGTH - 1;
|
||||
}
|
||||
|
||||
inline int CCommand::ArgC() const
|
||||
{
|
||||
return m_nArgc;
|
||||
}
|
||||
|
||||
inline const char **CCommand::ArgV() const
|
||||
{
|
||||
return m_nArgc ? (const char**)m_ppArgv : NULL;
|
||||
}
|
||||
|
||||
inline const char *CCommand::ArgS() const
|
||||
{
|
||||
return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : "";
|
||||
}
|
||||
|
||||
inline const char *CCommand::GetCommandString() const
|
||||
{
|
||||
return m_nArgc ? m_pArgSBuffer : "";
|
||||
}
|
||||
|
||||
inline const char *CCommand::Arg( int nIndex ) const
|
||||
{
|
||||
// FIXME: Many command handlers appear to not be particularly careful
|
||||
// about checking for valid argc range. For now, we're going to
|
||||
// do the extra check and return an empty string if it's out of range
|
||||
if ( nIndex < 0 || nIndex >= m_nArgc )
|
||||
return "";
|
||||
return m_ppArgv[nIndex];
|
||||
}
|
||||
|
||||
inline const char *CCommand::operator[]( int nIndex ) const
|
||||
{
|
||||
return Arg( nIndex );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The console invoked command
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommand : public ConCommandBase
|
||||
{
|
||||
friend class CCvar;
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConCommand( const char *pName, FnCommandCallbackV1_t callback,
|
||||
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
ConCommand( const char *pName, FnCommandCallback_t callback,
|
||||
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
ConCommand( const char *pName, ICommandCallback *pCallback,
|
||||
const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 );
|
||||
|
||||
virtual ~ConCommand( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands );
|
||||
|
||||
virtual bool CanAutoComplete( void );
|
||||
|
||||
// Invoke the function
|
||||
virtual void Dispatch( const CCommand &command );
|
||||
|
||||
private:
|
||||
// NOTE: To maintain backward compat, we have to be very careful:
|
||||
// All public virtual methods must appear in the same order always
|
||||
// since engine code will be calling into this code, which *does not match*
|
||||
// in the mod code; it's using slightly different, but compatible versions
|
||||
// of this class. Also: Be very careful about adding new fields to this class.
|
||||
// Those fields will not exist in the version of this class that is instanced
|
||||
// in mod code.
|
||||
|
||||
// Call this function when executing the command
|
||||
union
|
||||
{
|
||||
FnCommandCallbackV1_t m_fnCommandCallbackV1;
|
||||
FnCommandCallback_t m_fnCommandCallback;
|
||||
ICommandCallback *m_pCommandCallback;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
FnCommandCompletionCallback m_fnCompletionCallback;
|
||||
ICommandCompletionCallback *m_pCommandCompletionCallback;
|
||||
};
|
||||
|
||||
bool m_bHasCompletionCallback : 1;
|
||||
bool m_bUsingNewCommandCallback : 1;
|
||||
bool m_bUsingCommandCallbackInterface : 1;
|
||||
public:
|
||||
inline FnCommandCallback_t GetCallback() const
|
||||
{
|
||||
return m_fnCommandCallback;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A console variable
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar : public ConCommandBase, public IConVar
|
||||
{
|
||||
friend class CCvar;
|
||||
friend class ConVarRef;
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags = 0);
|
||||
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, FnChangeCallback_t callback );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
|
||||
FnChangeCallback_t callback );
|
||||
|
||||
virtual ~ConVar( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
virtual bool IsFlagSet( int flag ) const;
|
||||
virtual void AddFlags( int flags );
|
||||
virtual int GetFlags( void ) const;
|
||||
virtual const char *GetName( void ) const;
|
||||
virtual const char* GetHelpText( void ) const;
|
||||
virtual bool IsRegistered( void ) const;
|
||||
|
||||
// Install a change callback (there shouldn't already be one....)
|
||||
void InstallChangeCallback( FnChangeCallback_t callback );
|
||||
|
||||
// Retrieve value
|
||||
FORCEINLINE_CVAR float GetFloat( void ) const;
|
||||
FORCEINLINE_CVAR int GetInt( void ) const;
|
||||
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
|
||||
FORCEINLINE_CVAR char const *GetString( void ) const;
|
||||
|
||||
// Used internally by OneTimeInit to initialize.
|
||||
virtual void Init();
|
||||
|
||||
virtual const char *GetBaseName( void ) const;
|
||||
virtual int GetSplitScreenPlayerSlot ( void ) const;
|
||||
|
||||
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
|
||||
// from alloc/free across dll/exe boundaries.
|
||||
|
||||
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
|
||||
virtual void SetValue( const char *value );
|
||||
virtual void SetValue( float value );
|
||||
virtual void SetValue( int value );
|
||||
#if SOURCE_ENGINE >= SE_NUCLEARDAWN
|
||||
virtual void SetValue( Color value );
|
||||
#endif
|
||||
|
||||
// Reset to default value
|
||||
void Revert( void );
|
||||
|
||||
// True if it has a min/max setting
|
||||
bool GetMin( float& minVal ) const;
|
||||
bool GetMax( float& maxVal ) const;
|
||||
const char *GetDefault( void ) const;
|
||||
|
||||
private:
|
||||
// Called by CCvar when the value of a var is changing.
|
||||
virtual void InternalSetValue(const char *value);
|
||||
// For CVARs marked FCVAR_NEVER_AS_STRING
|
||||
virtual void InternalSetFloatValue( float fNewValue );
|
||||
virtual void InternalSetIntValue( int nValue );
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD2
|
||||
virtual void InternalSetColorValue( Color value );
|
||||
#endif
|
||||
|
||||
virtual bool ClampValue( float& value );
|
||||
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
|
||||
|
||||
virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0,
|
||||
const char *pHelpString = 0, bool bMin = false, float fMin = 0.0,
|
||||
bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 );
|
||||
|
||||
private:
|
||||
|
||||
// This either points to "this" or it points to the original declaration of a ConVar.
|
||||
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
|
||||
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
|
||||
ConVar *m_pParent;
|
||||
|
||||
// Static data
|
||||
const char *m_pszDefaultValue;
|
||||
|
||||
// Value
|
||||
// Dynamically allocated
|
||||
char *m_pszString;
|
||||
int m_StringLength;
|
||||
|
||||
// Values
|
||||
float m_fValue;
|
||||
int m_nValue;
|
||||
|
||||
// Min/Max values
|
||||
bool m_bHasMin;
|
||||
float m_fMinVal;
|
||||
bool m_bHasMax;
|
||||
float m_fMaxVal;
|
||||
|
||||
// Call this function when ConVar changes
|
||||
FnChangeCallback_t m_fnChangeCallback;
|
||||
public:
|
||||
inline FnChangeCallback_t GetCallback() const
|
||||
{
|
||||
return m_fnChangeCallback;
|
||||
}
|
||||
inline void SetMin(bool set, float min=0.0)
|
||||
{
|
||||
m_bHasMin = set;
|
||||
m_fMinVal = min;
|
||||
}
|
||||
inline void SetMax(bool set, float max=0.0)
|
||||
{
|
||||
m_bHasMax = set;
|
||||
m_fMaxVal = max;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
|
||||
{
|
||||
return m_pParent->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
|
||||
{
|
||||
return m_pParent->m_nValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
// Output : const char *
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR const char *ConVar::GetString( void ) const
|
||||
{
|
||||
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
|
||||
return "FCVAR_NEVER_AS_STRING";
|
||||
|
||||
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to read/write convars that already exist (replaces the FindVar method)
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVarRef
|
||||
{
|
||||
public:
|
||||
ConVarRef( const char *pName );
|
||||
ConVarRef( const char *pName, bool bIgnoreMissing );
|
||||
ConVarRef( IConVar *pConVar );
|
||||
|
||||
void Init( const char *pName, bool bIgnoreMissing );
|
||||
bool IsValid() const;
|
||||
bool IsFlagSet( int nFlags ) const;
|
||||
IConVar *GetLinkedConVar();
|
||||
|
||||
// Get/Set value
|
||||
float GetFloat( void ) const;
|
||||
int GetInt( void ) const;
|
||||
bool GetBool() const { return !!GetInt(); }
|
||||
const char *GetString( void ) const;
|
||||
|
||||
void SetValue( const char *pValue );
|
||||
void SetValue( float flValue );
|
||||
void SetValue( int nValue );
|
||||
void SetValue( bool bValue );
|
||||
|
||||
const char *GetName() const;
|
||||
|
||||
const char *GetDefault() const;
|
||||
|
||||
private:
|
||||
// High-speed method to read convar data
|
||||
IConVar *m_pConVar;
|
||||
ConVar *m_pConVarState;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Did we find an existing convar of that name?
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const
|
||||
{
|
||||
return ( m_pConVar->IsFlagSet( nFlags ) != 0 );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar()
|
||||
{
|
||||
return m_pConVar;
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetName() const
|
||||
{
|
||||
return m_pConVar->GetName();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const
|
||||
{
|
||||
return m_pConVarState->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const
|
||||
{
|
||||
return m_pConVarState->m_nValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const
|
||||
{
|
||||
Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) );
|
||||
return m_pConVarState->m_pszString;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue )
|
||||
{
|
||||
m_pConVar->SetValue( pValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue )
|
||||
{
|
||||
m_pConVar->SetValue( flValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue )
|
||||
{
|
||||
m_pConVar->SetValue( nValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue )
|
||||
{
|
||||
m_pConVar->SetValue( bValue ? 1 : 0 );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const
|
||||
{
|
||||
return m_pConVarState->m_pszDefaultValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called by the framework to register ConCommands with the ICVar
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL );
|
||||
void ConVar_Unregister( );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConVar_PrintFlags( const ConCommandBase *var );
|
||||
void ConVar_PrintDescription( const ConCommandBase *pVar );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility class to quickly allow ConCommands to call member methods
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable : 4355 )
|
||||
#endif
|
||||
|
||||
template< class T >
|
||||
class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback
|
||||
{
|
||||
typedef ConCommand BaseClass;
|
||||
typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command );
|
||||
typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands );
|
||||
|
||||
public:
|
||||
CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0,
|
||||
int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) :
|
||||
BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
m_Func = callback;
|
||||
m_CompletionFunc = completionFunc;
|
||||
}
|
||||
|
||||
~CConCommandMemberAccessor()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void SetOwner( T* pOwner )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
}
|
||||
|
||||
virtual void CommandCallback( const CCommand &command )
|
||||
{
|
||||
Assert( m_pOwner && m_Func );
|
||||
(m_pOwner->*m_Func)( command );
|
||||
}
|
||||
|
||||
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands )
|
||||
{
|
||||
Assert( m_pOwner && m_CompletionFunc );
|
||||
return (m_pOwner->*m_CompletionFunc)( pPartial, commands );
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_pOwner;
|
||||
FnMemberCommandCallback_t m_Func;
|
||||
FnMemberCommandCompletionCallback_t m_CompletionFunc;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning ( default : 4355 )
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility macros to quicky generate a simple console command
|
||||
//-----------------------------------------------------------------------------
|
||||
#define CON_COMMAND( name, description ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_F( name, description, flags ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description, flags ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description, flags, completion ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_EXTERN( name, _funcname, description ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, _funcname, description ); \
|
||||
void _funcname( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, _funcname, description, flags ); \
|
||||
void _funcname( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
friend class CCommandMemberInitializer_##_funcname; \
|
||||
class CCommandMemberInitializer_##_funcname \
|
||||
{ \
|
||||
public: \
|
||||
CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \
|
||||
{ \
|
||||
m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \
|
||||
} \
|
||||
private: \
|
||||
CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \
|
||||
}; \
|
||||
\
|
||||
CCommandMemberInitializer_##_funcname m_##_funcname##_register; \
|
||||
|
||||
|
||||
#endif // CONVAR_H
|
||||
@@ -0,0 +1,709 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef CONVAR_H
|
||||
#define CONVAR_H
|
||||
|
||||
#if _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/iconvar.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utlstring.h"
|
||||
#include "icvar.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FORCEINLINE_CVAR FORCEINLINE
|
||||
#elif defined _LINUX || defined __APPLE__
|
||||
#define FORCEINLINE_CVAR inline
|
||||
#else
|
||||
#error "implement me"
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar;
|
||||
class CCommand;
|
||||
class ConCommand;
|
||||
class ConCommandBase;
|
||||
struct characterset_t;
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Any executable that wants to use ConVars need to implement one of
|
||||
// these to hook up access to console variables.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
// Flags is a combination of FCVAR flags in cvar.h.
|
||||
// hOut is filled in with a handle to the variable.
|
||||
virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method for console development
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( _X360 ) && !defined( _RETAIL )
|
||||
void ConVar_PublishToVXConsole();
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called when a ConCommand needs to execute
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef void ( *FnCommandCallbackV1_t )( void );
|
||||
typedef void ( *FnCommandCallback_t )( const CCommand &command );
|
||||
|
||||
#define COMMAND_COMPLETION_MAXITEMS 64
|
||||
#define COMMAND_COMPLETION_ITEM_LENGTH 64
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Interface version
|
||||
//-----------------------------------------------------------------------------
|
||||
class ICommandCallback
|
||||
{
|
||||
public:
|
||||
virtual void CommandCallback( const CCommand &command ) = 0;
|
||||
};
|
||||
|
||||
class ICommandCompletionCallback
|
||||
{
|
||||
public:
|
||||
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The base console invoked command/cvar interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommandBase
|
||||
{
|
||||
friend class CCvar;
|
||||
friend class ConVar;
|
||||
friend class ConCommand;
|
||||
friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor );
|
||||
friend void ConVar_PublishToVXConsole();
|
||||
|
||||
// FIXME: Remove when ConVar changes are done
|
||||
friend class CDefaultCvar;
|
||||
|
||||
public:
|
||||
ConCommandBase( void );
|
||||
ConCommandBase( const char *pName, const char *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
virtual ~ConCommandBase( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
// Check flag
|
||||
virtual bool IsFlagSet( int flag ) const;
|
||||
// Set flag
|
||||
virtual void AddFlags( int flags );
|
||||
|
||||
// Return name of cvar
|
||||
virtual const char *GetName( void ) const;
|
||||
|
||||
// Return help text for cvar
|
||||
virtual const char *GetHelpText( void ) const;
|
||||
|
||||
// Deal with next pointer
|
||||
const ConCommandBase *GetNext( void ) const;
|
||||
ConCommandBase *GetNext( void );
|
||||
|
||||
void SetNext(ConCommandBase *pBase)
|
||||
{
|
||||
m_pNext = pBase;
|
||||
}
|
||||
|
||||
virtual bool IsRegistered( void ) const;
|
||||
|
||||
// Returns the DLL identifier
|
||||
virtual CVarDLLIdentifier_t GetDLLIdentifier() const;
|
||||
|
||||
protected:
|
||||
virtual void Create( const char *pName, const char *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
// Used internally by OneTimeInit to initialize/shutdown
|
||||
virtual void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Internal copy routine ( uses new operator from correct module )
|
||||
char *CopyString( const char *from );
|
||||
|
||||
private:
|
||||
// Next ConVar in chain
|
||||
// Prior to register, it points to the next convar in the DLL.
|
||||
// Once registered, though, m_pNext is reset to point to the next
|
||||
// convar in the global list
|
||||
ConCommandBase *m_pNext;
|
||||
|
||||
// Has the cvar been added to the global list?
|
||||
bool m_bRegistered;
|
||||
|
||||
// Static data
|
||||
const char *m_pszName;
|
||||
const char *m_pszHelpString;
|
||||
|
||||
// ConVar flags
|
||||
int m_nFlags;
|
||||
|
||||
protected:
|
||||
// ConVars add themselves to this list for the executable.
|
||||
// Then ConVar_Register runs through all the console variables
|
||||
// and registers them into a global list stored in vstdlib.dll
|
||||
static ConCommandBase *s_pConCommandBases;
|
||||
|
||||
// ConVars in this executable use this 'global' to access values.
|
||||
static IConCommandBaseAccessor *s_pAccessor;
|
||||
public: // Hackalicous
|
||||
inline int GetFlags() const
|
||||
{
|
||||
return m_nFlags;
|
||||
}
|
||||
inline void SetFlags(int flags)
|
||||
{
|
||||
m_nFlags = flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command tokenizer
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCommand
|
||||
{
|
||||
public:
|
||||
CCommand();
|
||||
CCommand( int nArgC, const char **ppArgV );
|
||||
bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL );
|
||||
void Reset();
|
||||
|
||||
int ArgC() const;
|
||||
const char **ArgV() const;
|
||||
const char *ArgS() const; // All args that occur after the 0th arg, in string form
|
||||
const char *GetCommandString() const; // The entire command in string form, including the 0th arg
|
||||
const char *operator[]( int nIndex ) const; // Gets at arguments
|
||||
const char *Arg( int nIndex ) const; // Gets at arguments
|
||||
|
||||
// Helper functions to parse arguments to commands.
|
||||
const char* FindArg( const char *pName ) const;
|
||||
int FindArgInt( const char *pName, int nDefaultVal ) const;
|
||||
|
||||
static int MaxCommandLength();
|
||||
static characterset_t* DefaultBreakSet();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
COMMAND_MAX_ARGC = 64,
|
||||
COMMAND_MAX_LENGTH = 512,
|
||||
};
|
||||
|
||||
int m_nArgc;
|
||||
int m_nArgv0Size;
|
||||
char m_pArgSBuffer[ COMMAND_MAX_LENGTH ];
|
||||
char m_pArgvBuffer[ COMMAND_MAX_LENGTH ];
|
||||
const char* m_ppArgv[ COMMAND_MAX_ARGC ];
|
||||
};
|
||||
|
||||
inline int CCommand::MaxCommandLength()
|
||||
{
|
||||
return COMMAND_MAX_LENGTH - 1;
|
||||
}
|
||||
|
||||
inline int CCommand::ArgC() const
|
||||
{
|
||||
return m_nArgc;
|
||||
}
|
||||
|
||||
inline const char **CCommand::ArgV() const
|
||||
{
|
||||
return m_nArgc ? (const char**)m_ppArgv : NULL;
|
||||
}
|
||||
|
||||
inline const char *CCommand::ArgS() const
|
||||
{
|
||||
return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : "";
|
||||
}
|
||||
|
||||
inline const char *CCommand::GetCommandString() const
|
||||
{
|
||||
return m_nArgc ? m_pArgSBuffer : "";
|
||||
}
|
||||
|
||||
inline const char *CCommand::Arg( int nIndex ) const
|
||||
{
|
||||
// FIXME: Many command handlers appear to not be particularly careful
|
||||
// about checking for valid argc range. For now, we're going to
|
||||
// do the extra check and return an empty string if it's out of range
|
||||
if ( nIndex < 0 || nIndex >= m_nArgc )
|
||||
return "";
|
||||
return m_ppArgv[nIndex];
|
||||
}
|
||||
|
||||
inline const char *CCommand::operator[]( int nIndex ) const
|
||||
{
|
||||
return Arg( nIndex );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The console invoked command
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommand : public ConCommandBase
|
||||
{
|
||||
friend class CCvar;
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConCommand( const char *pName, FnCommandCallbackV1_t callback,
|
||||
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
ConCommand( const char *pName, FnCommandCallback_t callback,
|
||||
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
ConCommand( const char *pName, ICommandCallback *pCallback,
|
||||
const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 );
|
||||
|
||||
virtual ~ConCommand( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands );
|
||||
|
||||
virtual bool CanAutoComplete( void );
|
||||
|
||||
// Invoke the function
|
||||
virtual void Dispatch( const CCommand &command );
|
||||
|
||||
private:
|
||||
// NOTE: To maintain backward compat, we have to be very careful:
|
||||
// All public virtual methods must appear in the same order always
|
||||
// since engine code will be calling into this code, which *does not match*
|
||||
// in the mod code; it's using slightly different, but compatible versions
|
||||
// of this class. Also: Be very careful about adding new fields to this class.
|
||||
// Those fields will not exist in the version of this class that is instanced
|
||||
// in mod code.
|
||||
|
||||
// Call this function when executing the command
|
||||
union
|
||||
{
|
||||
FnCommandCallbackV1_t m_fnCommandCallbackV1;
|
||||
FnCommandCallback_t m_fnCommandCallback;
|
||||
ICommandCallback *m_pCommandCallback;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
FnCommandCompletionCallback m_fnCompletionCallback;
|
||||
ICommandCompletionCallback *m_pCommandCompletionCallback;
|
||||
};
|
||||
|
||||
bool m_bHasCompletionCallback : 1;
|
||||
bool m_bUsingNewCommandCallback : 1;
|
||||
bool m_bUsingCommandCallbackInterface : 1;
|
||||
public: // Hackalicous
|
||||
inline FnCommandCallback_t GetCallback() const
|
||||
{
|
||||
return m_fnCommandCallback;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A console variable
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar : public ConCommandBase, public IConVar
|
||||
{
|
||||
friend class CCvar;
|
||||
friend class ConVarRef;
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags = 0);
|
||||
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, FnChangeCallback_t callback );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
|
||||
FnChangeCallback_t callback );
|
||||
|
||||
virtual ~ConVar( void );
|
||||
|
||||
virtual bool IsFlagSet( int flag ) const;
|
||||
virtual const char* GetHelpText( void ) const;
|
||||
virtual bool IsRegistered( void ) const;
|
||||
virtual const char *GetName( void ) const;
|
||||
virtual void AddFlags( int flags );
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
// Install a change callback (there shouldn't already be one....)
|
||||
void InstallChangeCallback( FnChangeCallback_t callback );
|
||||
|
||||
// Retrieve value
|
||||
FORCEINLINE_CVAR float GetFloat( void ) const;
|
||||
FORCEINLINE_CVAR int GetInt( void ) const;
|
||||
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
|
||||
FORCEINLINE_CVAR char const *GetString( void ) const;
|
||||
|
||||
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
|
||||
// from alloc/free across dll/exe boundaries.
|
||||
|
||||
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
|
||||
virtual void SetValue( const char *value );
|
||||
virtual void SetValue( float value );
|
||||
virtual void SetValue( int value );
|
||||
|
||||
// Reset to default value
|
||||
void Revert( void );
|
||||
|
||||
// True if it has a min/max setting
|
||||
bool GetMin( float& minVal ) const;
|
||||
bool GetMax( float& maxVal ) const;
|
||||
const char *GetDefault( void ) const;
|
||||
|
||||
private:
|
||||
// Called by CCvar when the value of a var is changing.
|
||||
virtual void InternalSetValue(const char *value);
|
||||
// For CVARs marked FCVAR_NEVER_AS_STRING
|
||||
virtual void InternalSetFloatValue( float fNewValue );
|
||||
virtual void InternalSetIntValue( int nValue );
|
||||
|
||||
virtual bool ClampValue( float& value );
|
||||
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
|
||||
|
||||
virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0,
|
||||
const char *pHelpString = 0, bool bMin = false, float fMin = 0.0,
|
||||
bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 );
|
||||
|
||||
// Used internally by OneTimeInit to initialize.
|
||||
virtual void Init();
|
||||
|
||||
private:
|
||||
|
||||
// This either points to "this" or it points to the original declaration of a ConVar.
|
||||
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
|
||||
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
|
||||
ConVar *m_pParent;
|
||||
|
||||
// Static data
|
||||
const char *m_pszDefaultValue;
|
||||
|
||||
// Value
|
||||
// Dynamically allocated
|
||||
char *m_pszString;
|
||||
int m_StringLength;
|
||||
|
||||
// Values
|
||||
float m_fValue;
|
||||
int m_nValue;
|
||||
|
||||
// Min/Max values
|
||||
bool m_bHasMin;
|
||||
float m_fMinVal;
|
||||
bool m_bHasMax;
|
||||
float m_fMaxVal;
|
||||
|
||||
// Call this function when ConVar changes
|
||||
FnChangeCallback_t m_fnChangeCallback;
|
||||
public: // Hackalicous
|
||||
inline FnChangeCallback_t GetCallback() const
|
||||
{
|
||||
return m_fnChangeCallback;
|
||||
}
|
||||
inline void SetMin(bool set, float min=0.0)
|
||||
{
|
||||
m_bHasMin = set;
|
||||
m_fMinVal = min;
|
||||
}
|
||||
inline void SetMax(bool set, float max=0.0)
|
||||
{
|
||||
m_bHasMax = set;
|
||||
m_fMaxVal = max;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
|
||||
{
|
||||
return m_pParent->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
|
||||
{
|
||||
return m_pParent->m_nValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
// Output : const char *
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR const char *ConVar::GetString( void ) const
|
||||
{
|
||||
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
|
||||
return "FCVAR_NEVER_AS_STRING";
|
||||
|
||||
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to read/write convars that already exist (replaces the FindVar method)
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVarRef
|
||||
{
|
||||
public:
|
||||
ConVarRef( const char *pName );
|
||||
ConVarRef( const char *pName, bool bIgnoreMissing );
|
||||
ConVarRef( IConVar *pConVar );
|
||||
|
||||
void Init( const char *pName, bool bIgnoreMissing );
|
||||
bool IsValid() const;
|
||||
bool IsFlagSet( int nFlags ) const;
|
||||
IConVar *GetLinkedConVar();
|
||||
|
||||
// Get/Set value
|
||||
float GetFloat( void ) const;
|
||||
int GetInt( void ) const;
|
||||
bool GetBool() const { return !!GetInt(); }
|
||||
const char *GetString( void ) const;
|
||||
|
||||
void SetValue( const char *pValue );
|
||||
void SetValue( float flValue );
|
||||
void SetValue( int nValue );
|
||||
void SetValue( bool bValue );
|
||||
|
||||
const char *GetName() const;
|
||||
|
||||
const char *GetDefault() const;
|
||||
|
||||
private:
|
||||
// High-speed method to read convar data
|
||||
IConVar *m_pConVar;
|
||||
ConVar *m_pConVarState;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Did we find an existing convar of that name?
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const
|
||||
{
|
||||
return ( m_pConVar->IsFlagSet( nFlags ) != 0 );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar()
|
||||
{
|
||||
return m_pConVar;
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetName() const
|
||||
{
|
||||
return m_pConVar->GetName();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const
|
||||
{
|
||||
return m_pConVarState->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const
|
||||
{
|
||||
return m_pConVarState->m_nValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const
|
||||
{
|
||||
Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) );
|
||||
return m_pConVarState->m_pszString;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue )
|
||||
{
|
||||
m_pConVar->SetValue( pValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue )
|
||||
{
|
||||
m_pConVar->SetValue( flValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue )
|
||||
{
|
||||
m_pConVar->SetValue( nValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue )
|
||||
{
|
||||
m_pConVar->SetValue( bValue ? 1 : 0 );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const
|
||||
{
|
||||
return m_pConVarState->m_pszDefaultValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called by the framework to register ConCommands with the ICVar
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL );
|
||||
void ConVar_Unregister( );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConVar_PrintFlags( const ConCommandBase *var );
|
||||
void ConVar_PrintDescription( const ConCommandBase *pVar );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility class to quickly allow ConCommands to call member methods
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined _MSC_VER
|
||||
#pragma warning (disable : 4355 )
|
||||
#endif
|
||||
|
||||
template< class T >
|
||||
class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback
|
||||
{
|
||||
typedef ConCommand BaseClass;
|
||||
typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command );
|
||||
typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands );
|
||||
|
||||
public:
|
||||
CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0,
|
||||
int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) :
|
||||
BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
m_Func = callback;
|
||||
m_CompletionFunc = completionFunc;
|
||||
}
|
||||
|
||||
~CConCommandMemberAccessor()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void SetOwner( T* pOwner )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
}
|
||||
|
||||
virtual void CommandCallback( const CCommand &command )
|
||||
{
|
||||
Assert( m_pOwner && m_Func );
|
||||
(m_pOwner->*m_Func)( command );
|
||||
}
|
||||
|
||||
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands )
|
||||
{
|
||||
Assert( m_pOwner && m_CompletionFunc );
|
||||
return (m_pOwner->*m_CompletionFunc)( pPartial, commands );
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_pOwner;
|
||||
FnMemberCommandCallback_t m_Func;
|
||||
FnMemberCommandCompletionCallback_t m_CompletionFunc;
|
||||
};
|
||||
|
||||
#if defined _MSC_VER
|
||||
#pragma warning ( default : 4355 )
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility macros to quicky generate a simple console command
|
||||
//-----------------------------------------------------------------------------
|
||||
#define CON_COMMAND( name, description ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_F( name, description, flags ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description, flags ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description, flags, completion ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_EXTERN( name, _funcname, description ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, _funcname, description ); \
|
||||
void _funcname( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, _funcname, description, flags ); \
|
||||
void _funcname( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
friend class CCommandMemberInitializer_##_funcname; \
|
||||
class CCommandMemberInitializer_##_funcname \
|
||||
{ \
|
||||
public: \
|
||||
CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \
|
||||
{ \
|
||||
m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \
|
||||
} \
|
||||
private: \
|
||||
CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \
|
||||
}; \
|
||||
\
|
||||
CCommandMemberInitializer_##_funcname m_##_funcname##_register; \
|
||||
|
||||
|
||||
#endif // CONVAR_H
|
||||
File diff suppressed because it is too large
Load Diff
+75
-89
@@ -1,95 +1,81 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import os
|
||||
|
||||
for cxx in builder.targets:
|
||||
binary = SM.Library(builder, cxx, 'sourcemod.logic')
|
||||
binary.compiler.cxxincludes += [
|
||||
builder.sourcePath,
|
||||
os.path.join(builder.sourcePath, 'core', 'logic'),
|
||||
os.path.join(builder.sourcePath, 'public'),
|
||||
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||
os.path.join(SM.mms_root, 'core', 'sourcehook')
|
||||
]
|
||||
binary.compiler.defines += [
|
||||
'SM_DEFAULT_THREADER',
|
||||
'SM_LOGIC'
|
||||
]
|
||||
binary = SM.Library(builder, 'sourcemod.logic')
|
||||
binary.compiler.cxxincludes += [
|
||||
os.path.join(builder.sourcePath, 'core', 'logic'),
|
||||
os.path.join(builder.sourcePath, 'public'),
|
||||
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||
os.path.join(SM.mms_root, 'core', 'sourcehook')
|
||||
]
|
||||
binary.compiler.defines += [
|
||||
'SM_DEFAULT_THREADER',
|
||||
'SM_LOGIC'
|
||||
]
|
||||
|
||||
if builder.target_platform == 'linux':
|
||||
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||
elif builder.target_platform == 'mac':
|
||||
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
||||
binary.compiler.postlink += ['-framework', 'CoreServices']
|
||||
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||
elif binary.compiler.target.platform == 'mac':
|
||||
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
||||
binary.compiler.postlink += ['-framework', 'CoreServices']
|
||||
if binary.compiler.vendor == 'gcc' or binary.compiler.vendor == 'clang':
|
||||
binary.compiler.cxxflags += ['-fno-rtti']
|
||||
elif binary.compiler.vendor == 'msvc':
|
||||
binary.compiler.cxxflags += ['/GR-']
|
||||
|
||||
if binary.compiler.family == 'gcc' or binary.compiler.family == 'clang':
|
||||
binary.compiler.cxxflags += ['-fno-rtti']
|
||||
elif binary.compiler.family == 'msvc':
|
||||
binary.compiler.cxxflags += ['/GR-']
|
||||
binary.sources += [
|
||||
'common_logic.cpp',
|
||||
'smn_adt_array.cpp',
|
||||
'smn_sorting.cpp',
|
||||
'smn_maplists.cpp',
|
||||
'ADTFactory.cpp',
|
||||
'smn_adt_stack.cpp',
|
||||
'thread/ThreadWorker.cpp',
|
||||
'thread/BaseWorker.cpp',
|
||||
'ThreadSupport.cpp',
|
||||
'smn_float.cpp',
|
||||
'TextParsers.cpp',
|
||||
'smn_textparse.cpp',
|
||||
'smn_adt_trie.cpp',
|
||||
'Profiler.cpp',
|
||||
'smn_functions.cpp',
|
||||
'smn_timers.cpp',
|
||||
'smn_players.cpp',
|
||||
'MemoryUtils.cpp',
|
||||
'smn_admin.cpp',
|
||||
'smn_banning.cpp',
|
||||
'smn_filesystem.cpp',
|
||||
'stringutil.cpp',
|
||||
'Translator.cpp',
|
||||
'PhraseCollection.cpp',
|
||||
'smn_lang.cpp',
|
||||
'smn_string.cpp',
|
||||
'smn_handles.cpp',
|
||||
'smn_datapacks.cpp',
|
||||
'smn_gameconfigs.cpp',
|
||||
'smn_fakenatives.cpp',
|
||||
'GameConfigs.cpp',
|
||||
'sm_crc32.cpp',
|
||||
'smn_profiler.cpp',
|
||||
'ShareSys.cpp',
|
||||
'PluginSys.cpp',
|
||||
'HandleSys.cpp',
|
||||
'NativeOwner.cpp',
|
||||
'NativeInvoker.cpp',
|
||||
'ExtensionSys.cpp',
|
||||
'DebugReporter.cpp',
|
||||
'Database.cpp',
|
||||
'smn_database.cpp',
|
||||
'ForwardSys.cpp',
|
||||
'AdminCache.cpp',
|
||||
'sm_trie.cpp',
|
||||
'smn_console.cpp',
|
||||
]
|
||||
if builder.target_platform == 'windows':
|
||||
binary.sources += ['thread/WinThreads.cpp']
|
||||
else:
|
||||
binary.sources += ['thread/PosixThreads.cpp']
|
||||
|
||||
binary.sources += [
|
||||
'common_logic.cpp',
|
||||
'smn_adt_array.cpp',
|
||||
'smn_sorting.cpp',
|
||||
'smn_maplists.cpp',
|
||||
'ADTFactory.cpp',
|
||||
'smn_adt_stack.cpp',
|
||||
'BaseWorker.cpp',
|
||||
'ThreadSupport.cpp',
|
||||
'smn_float.cpp',
|
||||
'TextParsers.cpp',
|
||||
'smn_textparse.cpp',
|
||||
'smn_adt_trie.cpp',
|
||||
'smn_functions.cpp',
|
||||
'smn_timers.cpp',
|
||||
'smn_players.cpp',
|
||||
'MemoryUtils.cpp',
|
||||
'smn_admin.cpp',
|
||||
'smn_banning.cpp',
|
||||
'smn_filesystem.cpp',
|
||||
'stringutil.cpp',
|
||||
'Translator.cpp',
|
||||
'PhraseCollection.cpp',
|
||||
'smn_lang.cpp',
|
||||
'smn_string.cpp',
|
||||
'smn_handles.cpp',
|
||||
'smn_datapacks.cpp',
|
||||
'smn_gameconfigs.cpp',
|
||||
'smn_fakenatives.cpp',
|
||||
'GameConfigs.cpp',
|
||||
'sm_crc32.cpp',
|
||||
'smn_profiler.cpp',
|
||||
'ShareSys.cpp',
|
||||
'PluginSys.cpp',
|
||||
'HandleSys.cpp',
|
||||
'NativeOwner.cpp',
|
||||
'ExtensionSys.cpp',
|
||||
'DebugReporter.cpp',
|
||||
'Database.cpp',
|
||||
'smn_database.cpp',
|
||||
'ForwardSys.cpp',
|
||||
'AdminCache.cpp',
|
||||
'sm_trie.cpp',
|
||||
'smn_console.cpp',
|
||||
'ProfileTools.cpp',
|
||||
'Logger.cpp',
|
||||
'smn_core.cpp',
|
||||
'smn_menus.cpp',
|
||||
'sprintf.cpp',
|
||||
'LibrarySys.cpp',
|
||||
'RootConsoleMenu.cpp',
|
||||
'CDataPack.cpp',
|
||||
'frame_tasks.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'FrameIterator.cpp',
|
||||
'DatabaseConfBuilder.cpp',
|
||||
'LumpManager.cpp',
|
||||
'smn_entitylump.cpp',
|
||||
'NativeInvoker.cpp',
|
||||
]
|
||||
|
||||
if binary.compiler.target.arch == 'x86_64':
|
||||
binary.sources += ['PseudoAddrManager.cpp']
|
||||
|
||||
SM.binaries += [builder.Add(binary)]
|
||||
SM.binaries += [builder.Add(binary)]
|
||||
|
||||
+40
-131
@@ -39,19 +39,15 @@
|
||||
#include "AdminCache.h"
|
||||
#include "Translator.h"
|
||||
#include "common_logic.h"
|
||||
#include "stringutil.h"
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/IVEngineServerBridge.h>
|
||||
|
||||
#define LEVEL_STATE_NONE 0
|
||||
#define LEVEL_STATE_LEVELS 1
|
||||
#define LEVEL_STATE_FLAGS 2
|
||||
|
||||
AdminCache g_Admins;
|
||||
char g_ReverseFlags[AdminFlags_TOTAL];
|
||||
char g_ReverseFlags[26];
|
||||
AdminFlag g_FlagLetters[26];
|
||||
bool g_FlagCharSet[26];
|
||||
bool g_FlagSet[26];
|
||||
|
||||
/* Default flags */
|
||||
AdminFlag g_DefaultFlags[26] =
|
||||
@@ -75,9 +71,9 @@ public:
|
||||
memcpy(g_FlagLetters, g_DefaultFlags, sizeof(AdminFlag) * 26);
|
||||
for (unsigned int i=0; i<20; i++)
|
||||
{
|
||||
g_FlagCharSet[i] = true;
|
||||
g_FlagSet[i] = true;
|
||||
}
|
||||
g_FlagCharSet[25] = true;
|
||||
g_FlagSet[25] = true;
|
||||
}
|
||||
}
|
||||
private:
|
||||
@@ -107,7 +103,7 @@ private:
|
||||
{
|
||||
m_LevelState = LEVEL_STATE_NONE;
|
||||
m_IgnoreLevel = 0;
|
||||
memset(g_FlagCharSet, 0, sizeof(g_FlagCharSet));
|
||||
memset(g_FlagSet, 0, sizeof(g_FlagSet));
|
||||
}
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
{
|
||||
@@ -167,7 +163,7 @@ private:
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
g_FlagCharSet[c] = true;
|
||||
g_FlagSet[c] = true;
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
@@ -202,11 +198,11 @@ private:
|
||||
|
||||
if (!m_bFileNameLogged)
|
||||
{
|
||||
logger->LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
|
||||
smcore.LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
|
||||
m_bFileNameLogged = true;
|
||||
}
|
||||
|
||||
logger->LogError("[SM] (Line %d): %s", states ? states->line : 0, buffer);
|
||||
smcore.LogError("[SM] (Line %d): %s", states ? states->line : 0, buffer);
|
||||
}
|
||||
private:
|
||||
bool m_bFileNameLogged;
|
||||
@@ -271,21 +267,6 @@ void AdminCache::OnSourceModStartup(bool late)
|
||||
NameFlag("custom4", Admin_Custom4);
|
||||
NameFlag("custom5", Admin_Custom5);
|
||||
NameFlag("custom6", Admin_Custom6);
|
||||
|
||||
auto sm_dump_admcache = [this] (int client, const ICommandArgs *args) -> bool {
|
||||
char buffer[PLATFORM_MAX_PATH];
|
||||
g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer), "data/admin_cache_dump.txt");
|
||||
|
||||
if (!DumpCache(buffer)) {
|
||||
bridge->ConsolePrint("Could not open file for writing: %s", buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bridge->ConsolePrint("Admin cache dumped to: %s", buffer);
|
||||
return true;
|
||||
};
|
||||
|
||||
bridge->DefineCommand("sm_dump_admcache", "Dumps the admin cache for debugging", sm_dump_admcache);
|
||||
}
|
||||
|
||||
void AdminCache::OnSourceModAllInitialized()
|
||||
@@ -346,7 +327,7 @@ void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits
|
||||
return;
|
||||
|
||||
map->insert(cmd, flags);
|
||||
bridge->UpdateAdminCmdFlags(cmd, type, flags, false);
|
||||
smcore.UpdateAdminCmdFlags(cmd, type, flags, false);
|
||||
}
|
||||
|
||||
bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags)
|
||||
@@ -375,13 +356,13 @@ void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
|
||||
void AdminCache::_UnsetCommandGroupOverride(const char *group)
|
||||
{
|
||||
m_CmdGrpOverrides.remove(group);
|
||||
bridge->UpdateAdminCmdFlags(group, Override_CommandGroup, 0, true);
|
||||
smcore.UpdateAdminCmdFlags(group, Override_CommandGroup, 0, true);
|
||||
}
|
||||
|
||||
void AdminCache::_UnsetCommandOverride(const char *cmd)
|
||||
{
|
||||
m_CmdOverrides.remove(cmd);
|
||||
bridge->UpdateAdminCmdFlags(cmd, Override_Command, 0, true);
|
||||
smcore.UpdateAdminCmdFlags(cmd, Override_Command, 0, true);
|
||||
}
|
||||
|
||||
void AdminCache::DumpCommandOverrideCache(OverrideType type)
|
||||
@@ -1000,6 +981,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
|
||||
{
|
||||
List<IAdminListener *>::iterator iter;
|
||||
IAdminListener *pListener;
|
||||
cell_t result;
|
||||
|
||||
if (part == AdminCache_Overrides)
|
||||
{
|
||||
@@ -1013,7 +995,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
|
||||
pListener->OnRebuildOverrideCache();
|
||||
}
|
||||
m_pCacheFwd->PushCell(part);
|
||||
m_pCacheFwd->Execute();
|
||||
m_pCacheFwd->Execute(&result);
|
||||
}
|
||||
} else if (part == AdminCache_Groups || part == AdminCache_Admins) {
|
||||
if (part == AdminCache_Groups)
|
||||
@@ -1027,7 +1009,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
|
||||
pListener->OnRebuildGroupCache();
|
||||
}
|
||||
m_pCacheFwd->PushCell(part);
|
||||
m_pCacheFwd->Execute();
|
||||
m_pCacheFwd->Execute(&result);
|
||||
}
|
||||
}
|
||||
InvalidateAdminCache(true);
|
||||
@@ -1039,7 +1021,7 @@ void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
|
||||
pListener->OnRebuildAdminCache((part == AdminCache_Groups));
|
||||
}
|
||||
m_pCacheFwd->PushCell(AdminCache_Admins);
|
||||
m_pCacheFwd->Execute();
|
||||
m_pCacheFwd->Execute(&result);
|
||||
playerhelpers->RecheckAnyAdmins();
|
||||
}
|
||||
}
|
||||
@@ -1074,65 +1056,6 @@ bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts Steam2 id, Steam3 id, or SteamId64 to unified, legacy
|
||||
* admin identity format. (account id part of Steam2 format)
|
||||
*/
|
||||
bool AdminCache::GetUnifiedSteamIdentity(const char *ident, char *out, size_t maxlen)
|
||||
{
|
||||
int len = strlen(ident);
|
||||
if (!strcmp(ident, "BOT"))
|
||||
{
|
||||
// Bots
|
||||
strncopy(out, ident, maxlen);
|
||||
return true;
|
||||
}
|
||||
else if (len >= 11 && !strncmp(ident, "STEAM_", 6) && ident[8] != '_')
|
||||
{
|
||||
// non-bot/lan Steam2 Id, strip off the STEAM_* part
|
||||
ke::SafeStrcpy(out, maxlen, &ident[8]);
|
||||
return true;
|
||||
}
|
||||
else if (len >= 7 && !strncmp(ident, "[U:", 3) && ident[len-1] == ']')
|
||||
{
|
||||
// Steam3 Id, replicate the Steam2 Post-"STEAM_" part
|
||||
uint32_t accountId = strtoul(&ident[5], nullptr, 10);
|
||||
ke::SafeSprintf(out, maxlen, "%u:%u", accountId & 1, accountId >> 1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 64-bit CSteamID, replicate the Steam2 Post-"STEAM_" part
|
||||
|
||||
// some constants from steamclientpublic.h
|
||||
static const uint32_t k_EAccountTypeIndividual = 1;
|
||||
static const int k_EUniverseInvalid = 0;
|
||||
static const int k_EUniverseMax = 5;
|
||||
static const unsigned int k_unSteamUserWebInstance = 4;
|
||||
|
||||
uint64_t steamId = strtoull(ident, nullptr, 10);
|
||||
if (steamId > 0)
|
||||
{
|
||||
// Make some attempt at being sure it's a valid id rather than other number,
|
||||
// even though we're only going to use the lower 32 bits.
|
||||
uint32_t accountId = steamId & 0xFFFFFFFF;
|
||||
uint32_t accountType = (steamId >> 52) & 0xF;
|
||||
int universe = steamId >> 56;
|
||||
uint32_t accountInstance = (steamId >> 32) & 0xFFFFF;
|
||||
if (accountId > 0
|
||||
&& universe > k_EUniverseInvalid && universe < k_EUniverseMax
|
||||
&& accountType == k_EAccountTypeIndividual && accountInstance <= k_unSteamUserWebInstance
|
||||
)
|
||||
{
|
||||
ke::SafeSprintf(out, maxlen, "%u:%u", accountId & 1, accountId >> 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
|
||||
{
|
||||
if (ident[0] == '\0')
|
||||
@@ -1150,14 +1073,10 @@ bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ide
|
||||
if (!m_AuthTables.retrieve(auth, &method))
|
||||
return false;
|
||||
|
||||
/* If the auth type is steam, the id could be in a number of formats. Unify it. */
|
||||
char steamIdent[16];
|
||||
if (strcmp(auth, "steam") == 0)
|
||||
/* If the id was a steam id strip off the STEAM_*: part */
|
||||
if (strcmp(auth, "steam") == 0 && strncmp(ident, "STEAM_", 6) == 0)
|
||||
{
|
||||
if (!GetUnifiedSteamIdentity(ident, steamIdent, sizeof(steamIdent)))
|
||||
return false;
|
||||
|
||||
ident = steamIdent;
|
||||
ident += 8;
|
||||
}
|
||||
|
||||
if (method->identities.contains(ident))
|
||||
@@ -1178,14 +1097,10 @@ AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
|
||||
if (!m_AuthTables.retrieve(auth, &method))
|
||||
return INVALID_ADMIN_ID;
|
||||
|
||||
/* If the auth type is steam, the id could be in a number of formats. Unify it. */
|
||||
char steamIdent[16];
|
||||
if (strcmp(auth, "steam") == 0)
|
||||
/* If the id was a steam id strip off the STEAM_*: part */
|
||||
if (strcmp(auth, "steam") == 0 && strncmp(identity, "STEAM_", 6) == 0)
|
||||
{
|
||||
if (!GetUnifiedSteamIdentity(identity, steamIdent, sizeof(steamIdent)))
|
||||
return INVALID_ADMIN_ID;
|
||||
|
||||
identity = steamIdent;
|
||||
identity += 8;
|
||||
}
|
||||
|
||||
AdminId id;
|
||||
@@ -1534,7 +1449,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
|
||||
}
|
||||
|
||||
/** Fourth, if the targeted admin is immune from targeting admin. */
|
||||
int mode = bridge->GetImmunityMode();
|
||||
int mode = smcore.GetImmunityMode();
|
||||
switch (mode)
|
||||
{
|
||||
case 1:
|
||||
@@ -1581,7 +1496,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
|
||||
{
|
||||
id = grp_table[i];
|
||||
num = GetGroupImmunityCount(id);
|
||||
for (unsigned int j=0; j<num; j++)
|
||||
for (unsigned int j=0; j<num; i++)
|
||||
{
|
||||
other = GetGroupImmunity(id, j);
|
||||
for (unsigned int k=0; k<pUser->grp_count; k++)
|
||||
@@ -1602,7 +1517,7 @@ bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
|
||||
{
|
||||
if (c < 'a'
|
||||
|| c > 'z'
|
||||
|| !g_FlagCharSet[(unsigned)c - (unsigned)'a'])
|
||||
|| !g_FlagSet[(unsigned)c - (unsigned)'a'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1617,13 +1532,17 @@ bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
|
||||
|
||||
bool AdminCache::FindFlagChar(AdminFlag flag, char *c)
|
||||
{
|
||||
char flagchar = g_ReverseFlags[flag];
|
||||
if (c)
|
||||
if (!g_FlagSet[flag])
|
||||
{
|
||||
*c = flagchar;
|
||||
return false;
|
||||
}
|
||||
|
||||
return flagchar != '?';
|
||||
if (c)
|
||||
{
|
||||
*c = g_ReverseFlags[flag];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
|
||||
@@ -1671,7 +1590,7 @@ bool AdminCache::CanAdminUseCommand(int client, const char *cmd)
|
||||
cmd++;
|
||||
}
|
||||
|
||||
if (!bridge->LookForCommandAdminFlags(cmd, &bits))
|
||||
if (!smcore.LookForCommandAdminFlags(cmd, &bits))
|
||||
{
|
||||
if (!GetCommandOverride(cmd, otype, &bits))
|
||||
{
|
||||
@@ -1746,7 +1665,7 @@ bool AdminCache::CheckAccess(int client, const char *cmd, FlagBits flags, bool o
|
||||
bool found_command = false;
|
||||
if (!override_only)
|
||||
{
|
||||
found_command = bridge->LookForCommandAdminFlags(cmd, &bits);
|
||||
found_command = smcore.LookForCommandAdminFlags(cmd, &bits);
|
||||
}
|
||||
|
||||
if (!found_command)
|
||||
@@ -1783,7 +1702,7 @@ void iterator_group_grp_override(FILE *fp, const char *key, OverrideRule rule)
|
||||
fprintf(fp, "\t\t\t\"@%s\"\t\t\"%s\"\n", key, str);
|
||||
}
|
||||
|
||||
bool AdminCache::DumpCache(const char *filename)
|
||||
void AdminCache::DumpCache(FILE *fp)
|
||||
{
|
||||
int *itable;
|
||||
AdminId aid;
|
||||
@@ -1792,12 +1711,6 @@ bool AdminCache::DumpCache(const char *filename)
|
||||
unsigned int num;
|
||||
AdminUser *pAdmin;
|
||||
AdminGroup *pGroup;
|
||||
|
||||
FILE *fp;
|
||||
if ((fp = fopen(filename, "wt")) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(fp, "\"Groups\"\n{\n");
|
||||
|
||||
@@ -1843,13 +1756,13 @@ bool AdminCache::DumpCache(const char *filename)
|
||||
fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
|
||||
if (pGroup->pCmdGrpTable != NULL)
|
||||
{
|
||||
for (OverrideMap::iterator iter = pGroup->pCmdGrpTable->iter(); !iter.empty(); iter.next())
|
||||
iterator_group_grp_override(fp, iter->key.c_str(), iter->value);
|
||||
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
||||
iterator_group_grp_override(fp, iter->key.chars(), iter->value);
|
||||
}
|
||||
if (pGroup->pCmdTable != NULL)
|
||||
{
|
||||
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
||||
iterator_group_basic_override(fp, iter->key.c_str(), iter->value);
|
||||
iterator_group_basic_override(fp, iter->key.chars(), iter->value);
|
||||
}
|
||||
fprintf(fp, "\t\t}\n");
|
||||
|
||||
@@ -1924,14 +1837,10 @@ bool AdminCache::DumpCache(const char *filename)
|
||||
|
||||
fprintf(fp, "\"Overrides\"\n{\n");
|
||||
for (FlagMap::iterator iter = m_CmdGrpOverrides.iter(); !iter.empty(); iter.next())
|
||||
iterator_glob_grp_override(fp, iter->key.c_str(), iter->value);
|
||||
iterator_glob_grp_override(fp, iter->key.chars(), iter->value);
|
||||
for (FlagMap::iterator iter = m_CmdOverrides.iter(); !iter.empty(); iter.next())
|
||||
iterator_glob_basic_override(fp, iter->key.c_str(), iter->value);
|
||||
iterator_glob_basic_override(fp, iter->key.chars(), iter->value);
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AdminGroup *AdminCache::GetGroup(GroupId gid)
|
||||
|
||||
@@ -82,10 +82,6 @@ struct AuthMethod
|
||||
{
|
||||
return strcmp(name, method->name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct UserAuth
|
||||
@@ -187,7 +183,7 @@ public: //IAdminSystem
|
||||
bool IsValidAdmin(AdminId id);
|
||||
bool CheckClientCommandAccess(int client, const char *cmd, FlagBits cmdflags);
|
||||
public:
|
||||
bool DumpCache(const char *filename);
|
||||
void DumpCache(FILE *fp);
|
||||
AdminGroup *GetGroup(GroupId gid);
|
||||
AdminUser *GetUser(AdminId id);
|
||||
const char *GetString(int idx);
|
||||
@@ -202,7 +198,6 @@ private:
|
||||
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;
|
||||
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "CDataPack.h"
|
||||
|
||||
CDataPack::CDataPack()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
CDataPack::~CDataPack()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void CDataPack::Initialize()
|
||||
{
|
||||
position = 0;
|
||||
|
||||
do
|
||||
{
|
||||
} while (this->RemoveItem());
|
||||
|
||||
elements.clear();
|
||||
}
|
||||
|
||||
void CDataPack::ResetSize()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
size_t CDataPack::CreateMemory(size_t size, void **addr)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::Raw;
|
||||
val.pData.vval = new uint8_t[size + sizeof(size)];
|
||||
reinterpret_cast<size_t *>(val.pData.vval)[0] = size;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
|
||||
return position++;
|
||||
}
|
||||
|
||||
void CDataPack::PackCell(cell_t cell)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::Cell;
|
||||
val.pData.cval = cell;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
position++;
|
||||
}
|
||||
|
||||
void CDataPack::PackFunction(cell_t function)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::Function;
|
||||
val.pData.cval = function;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
position++;
|
||||
}
|
||||
|
||||
void CDataPack::PackFloat(float floatval)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::Float;
|
||||
val.pData.fval = floatval;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
position++;
|
||||
}
|
||||
|
||||
void CDataPack::PackString(const char *string)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::String;
|
||||
std::string *sval = new std::string(string);
|
||||
val.pData.sval = sval;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
position++;
|
||||
}
|
||||
|
||||
void CDataPack::PackCellArray(cell_t const *vals, cell_t count)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::CellArray;
|
||||
|
||||
val.pData.aval = new cell_t [count + 1];
|
||||
memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count);
|
||||
val.pData.aval[0] = count;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
position++;
|
||||
}
|
||||
|
||||
void CDataPack::PackFloatArray(cell_t const *vals, cell_t count)
|
||||
{
|
||||
InternalPack val;
|
||||
val.type = CDataPackType::FloatArray;
|
||||
|
||||
val.pData.aval = new cell_t [count + 1];
|
||||
memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count);
|
||||
val.pData.aval[0] = count;
|
||||
elements.emplace(elements.begin() + position, val);
|
||||
position++;
|
||||
}
|
||||
|
||||
void CDataPack::Reset() const
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
size_t CDataPack::GetPosition() const
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
bool CDataPack::SetPosition(size_t pos) const
|
||||
{
|
||||
if (pos > elements.size())
|
||||
return false;
|
||||
|
||||
position = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
cell_t CDataPack::ReadCell() const
|
||||
{
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::Cell)
|
||||
return 0;
|
||||
|
||||
return elements[position++].pData.cval;
|
||||
}
|
||||
|
||||
cell_t CDataPack::ReadFunction() const
|
||||
{
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::Function)
|
||||
return 0;
|
||||
|
||||
return elements[position++].pData.cval;
|
||||
}
|
||||
|
||||
float CDataPack::ReadFloat() const
|
||||
{
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::Float)
|
||||
return 0;
|
||||
|
||||
return elements[position++].pData.fval;
|
||||
}
|
||||
|
||||
bool CDataPack::IsReadable(size_t bytes) const
|
||||
{
|
||||
return (position < elements.size());
|
||||
}
|
||||
|
||||
const char *CDataPack::ReadString(size_t *len) const
|
||||
{
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::String)
|
||||
{
|
||||
if (len)
|
||||
*len = 0;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string &val = *elements[position++].pData.sval;
|
||||
if (len)
|
||||
*len = val.size();
|
||||
|
||||
return val.c_str();
|
||||
}
|
||||
|
||||
cell_t *CDataPack::ReadCellArray(cell_t *size) const
|
||||
{
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::CellArray)
|
||||
{
|
||||
if(size)
|
||||
*size = 0;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cell_t *val = elements[position].pData.aval;
|
||||
cell_t *ptr = &(val[1]);
|
||||
++position;
|
||||
|
||||
if (size)
|
||||
*size = val[0];
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
cell_t *CDataPack::ReadFloatArray(cell_t *size) const
|
||||
{
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::FloatArray)
|
||||
{
|
||||
if(size)
|
||||
*size = 0;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cell_t *val = elements[position].pData.aval;
|
||||
cell_t *ptr = &(val[1]);
|
||||
++position;
|
||||
|
||||
if (size)
|
||||
*size = val[0];
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *CDataPack::ReadMemory(size_t *size) const
|
||||
{
|
||||
void *ptr = nullptr;
|
||||
if (!IsReadable() || elements[position].type != CDataPackType::Raw)
|
||||
return ptr;
|
||||
|
||||
size_t *val = reinterpret_cast<size_t *>(elements[position].pData.vval);
|
||||
ptr = &(val[1]);
|
||||
++position;
|
||||
|
||||
if (size)
|
||||
*size = val[0]; /* Egor!!!! */
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool CDataPack::RemoveItem(size_t pos)
|
||||
{
|
||||
if (!elements.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pos == static_cast<size_t>(-1))
|
||||
{
|
||||
pos = position;
|
||||
}
|
||||
|
||||
if (pos >= elements.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pos < position) // we're deleting under us, step back
|
||||
{
|
||||
--position;
|
||||
}
|
||||
|
||||
switch (elements[pos].type)
|
||||
{
|
||||
case CDataPackType::Raw:
|
||||
{
|
||||
delete [] elements[pos].pData.vval;
|
||||
break;
|
||||
}
|
||||
|
||||
case CDataPackType::String:
|
||||
{
|
||||
delete elements[pos].pData.sval;
|
||||
break;
|
||||
}
|
||||
|
||||
case CDataPackType::CellArray:
|
||||
case CDataPackType::FloatArray:
|
||||
{
|
||||
delete [] elements[pos].pData.aval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
elements.erase(elements.begin() + pos);
|
||||
return true;
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
#define _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
|
||||
#include <ISourceMod.h>
|
||||
#include <amtl/am-vector.h>
|
||||
#include <amtl/am-string.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
enum CDataPackType {
|
||||
Raw,
|
||||
Cell,
|
||||
Float,
|
||||
String,
|
||||
Function,
|
||||
CellArray,
|
||||
FloatArray,
|
||||
};
|
||||
|
||||
class CDataPack
|
||||
{
|
||||
public:
|
||||
CDataPack();
|
||||
~CDataPack();
|
||||
|
||||
public: // Originally IDataReader
|
||||
/**
|
||||
* @brief Resets the position in the data stream to the beginning.
|
||||
*/
|
||||
void Reset() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current stream position.
|
||||
*
|
||||
* @return Index into the stream.
|
||||
*/
|
||||
size_t GetPosition() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the current stream position.
|
||||
*
|
||||
* @param pos Index to set the stream at.
|
||||
* @return True if succeeded, false if out of bounds.
|
||||
*/
|
||||
bool SetPosition(size_t pos) const;
|
||||
|
||||
/**
|
||||
* @brief Reads one cell from the data stream.
|
||||
*
|
||||
* @return A cell read from the current position.
|
||||
*/
|
||||
cell_t ReadCell() const;
|
||||
|
||||
/**
|
||||
* @brief Reads one float from the data stream.
|
||||
*
|
||||
* @return A float read from the current position.
|
||||
*/
|
||||
float ReadFloat() const;
|
||||
|
||||
/**
|
||||
* @brief Reads an array of values from the data stream.
|
||||
*
|
||||
* @param len The size of the array stored at this position to return.
|
||||
* @return A cell array read from the current position.
|
||||
*/
|
||||
cell_t *ReadCellArray(cell_t *len) const;
|
||||
/**
|
||||
* @brief Reads an array of values from the data stream.
|
||||
*
|
||||
* @param len The size of the array stored at this position to return.
|
||||
* @return A cell array read from the current position.
|
||||
*/
|
||||
cell_t *ReadFloatArray(cell_t *len) const;
|
||||
|
||||
/**
|
||||
* @brief Returns whether or not a specified number of bytes from the current stream
|
||||
* position to the end can be read.
|
||||
*
|
||||
* @param bytes Number of bytes to simulate reading.
|
||||
* @return True if can be read, false otherwise.
|
||||
*/
|
||||
bool IsReadable(size_t bytes = 0) const;
|
||||
|
||||
/**
|
||||
* @brief Reads a string from the data stream.
|
||||
*
|
||||
* @param len Optional pointer to store the string length.
|
||||
* @return Pointer to the string, or NULL if out of bounds.
|
||||
*/
|
||||
const char *ReadString(size_t *len) const;
|
||||
|
||||
/**
|
||||
* @brief Reads the current position as a generic data type.
|
||||
*
|
||||
* @param size Optional pointer to store the size of the data type.
|
||||
* @return Pointer to the data, or NULL if out of bounds.
|
||||
*/
|
||||
void *ReadMemory(size_t *size) const;
|
||||
|
||||
/**
|
||||
* @brief Reads a function pointer from the data stream.
|
||||
*
|
||||
* @return A function pointer read from the current position.
|
||||
*/
|
||||
cell_t ReadFunction() const;
|
||||
|
||||
public: // Originally IDataPack
|
||||
/**
|
||||
* @brief Resets the used size of the stream back to zero.
|
||||
*/
|
||||
void ResetSize();
|
||||
|
||||
/**
|
||||
* @brief Packs one cell into the data stream.
|
||||
*
|
||||
* @param cell Cell value to write.
|
||||
*/
|
||||
void PackCell(cell_t cell);
|
||||
|
||||
/**
|
||||
* @brief Packs one float into the data stream.
|
||||
*
|
||||
* @param val Float value to write.
|
||||
*/
|
||||
void PackFloat(float val);
|
||||
|
||||
/**
|
||||
* @brief Packs one string into the data stream.
|
||||
* The length is recorded as well for buffer overrun protection.
|
||||
*
|
||||
* @param string String to write.
|
||||
*/
|
||||
void PackString(const char *string);
|
||||
|
||||
/**
|
||||
* @brief Packs an array of cells into the data stream.
|
||||
*
|
||||
* @param vals Cells to write.
|
||||
* @param count Number of cells.
|
||||
*/
|
||||
void PackCellArray(cell_t const *vals, cell_t count);
|
||||
/**
|
||||
* @brief Packs an array of cells into the data stream.
|
||||
*
|
||||
* @param vals Cells to write.
|
||||
* @param count Number of cells.
|
||||
*/
|
||||
void PackFloatArray(cell_t const *vals, cell_t count);
|
||||
|
||||
/**
|
||||
* @brief Creates a generic block of memory in the stream.
|
||||
*
|
||||
* Note that the pointer it returns can be invalidated on further
|
||||
* writing, since the stream size may grow. You may need to double back
|
||||
* and fetch the pointer again.
|
||||
*
|
||||
* @param size Size of the memory to create in the stream.
|
||||
* @param addr Optional pointer to store the relocated memory address.
|
||||
* @return Current position of the stream beforehand.
|
||||
*/
|
||||
size_t CreateMemory(size_t size, void **addr);
|
||||
|
||||
/**
|
||||
* @brief Packs one function pointer into the data stream.
|
||||
*
|
||||
* @param function The function pointer to write.
|
||||
*/
|
||||
void PackFunction(cell_t function);
|
||||
|
||||
public:
|
||||
void Initialize();
|
||||
inline size_t GetCapacity() const { return this->elements.size(); };
|
||||
inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; };
|
||||
bool RemoveItem(size_t pos = -1);
|
||||
|
||||
private:
|
||||
typedef union {
|
||||
cell_t cval;
|
||||
float fval;
|
||||
uint8_t *vval;
|
||||
std::string *sval;
|
||||
cell_t *aval;
|
||||
} InternalPackValue;
|
||||
|
||||
typedef struct {
|
||||
InternalPackValue pData;
|
||||
CDataPackType type;
|
||||
} InternalPack;
|
||||
|
||||
std::vector<InternalPack> elements;
|
||||
mutable size_t position;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_
|
||||
+11
-54
@@ -34,12 +34,10 @@
|
||||
|
||||
#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 +49,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 +154,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 +182,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;
|
||||
|
||||
+254
-92
@@ -34,23 +34,20 @@
|
||||
#include "HandleSys.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;
|
||||
|
||||
#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_ParseLevel(0),
|
||||
m_ParseState(0),
|
||||
m_pDefault(NULL)
|
||||
{
|
||||
}
|
||||
@@ -67,29 +64,38 @@ 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_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.
|
||||
*/
|
||||
ke::AutoLock lock(&m_ConfigLock);
|
||||
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
|
||||
{
|
||||
smcore.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
||||
if (err != SMCError_Custom)
|
||||
{
|
||||
const char *txt = textparsers->GetSMCErrorString(err);
|
||||
smcore.LogError("[SM] Line %d: %s", states.line, txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModShutdown()
|
||||
@@ -99,6 +105,7 @@ void DBManager::OnSourceModShutdown()
|
||||
g_PluginSys.RemovePluginsListener(this);
|
||||
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
|
||||
ClearConfigs();
|
||||
}
|
||||
|
||||
unsigned int DBManager::GetInterfaceVersion()
|
||||
@@ -126,10 +133,136 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
}
|
||||
}
|
||||
|
||||
void DBManager::ReadSMC_ParseStart()
|
||||
{
|
||||
ClearConfigs();
|
||||
m_ParseLevel = 0;
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
m_DefDriver.clear();
|
||||
}
|
||||
|
||||
void DBManager::ClearConfigs()
|
||||
{
|
||||
List<ConfDbInfo *>::iterator iter;
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
delete (*iter);
|
||||
m_confs.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 = 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 = value;
|
||||
}
|
||||
} else if (strcmp(key, "database") == 0) {
|
||||
s_CurInfo.database = value;
|
||||
} else if (strcmp(key, "host") == 0) {
|
||||
s_CurInfo.host = value;
|
||||
} else if (strcmp(key, "user") == 0) {
|
||||
s_CurInfo.user = value;
|
||||
} else if (strcmp(key, "pass") == 0) {
|
||||
s_CurInfo.pass = 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;
|
||||
}
|
||||
|
||||
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
m_ParseLevel--;
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||
{
|
||||
ConfDbInfo *cdb = new ConfDbInfo();
|
||||
|
||||
cdb->name = s_CurInfo.name;
|
||||
cdb->driver = s_CurInfo.driver;
|
||||
cdb->host = s_CurInfo.host;
|
||||
cdb->user = s_CurInfo.user;
|
||||
cdb->pass = s_CurInfo.pass;
|
||||
cdb->database = s_CurInfo.database;
|
||||
cdb->realDriver = s_CurInfo.realDriver;
|
||||
cdb->info.maxTimeout = s_CurInfo.info.maxTimeout;
|
||||
cdb->info.port = s_CurInfo.info.port;
|
||||
|
||||
cdb->info.driver = cdb->driver.c_str();
|
||||
cdb->info.database = cdb->database.c_str();
|
||||
cdb->info.host = cdb->host.c_str();
|
||||
cdb->info.user = cdb->user.c_str();
|
||||
cdb->info.pass = cdb->pass.c_str();
|
||||
|
||||
/* Save it.. */
|
||||
m_confs.push_back(cdb);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -148,12 +281,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);
|
||||
@@ -177,6 +309,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
||||
*pdb = NULL;
|
||||
|
||||
g_pSM->Format(error, maxlength, "Driver \"%s\" not found", dname);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -189,7 +322,7 @@ void DBManager::AddDriver(IDBDriver *pDriver)
|
||||
*/
|
||||
KillWorkerThread();
|
||||
|
||||
m_drivers.push_back(pDriver);
|
||||
m_drivers.push_back(pDriver);
|
||||
}
|
||||
|
||||
void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
@@ -209,11 +342,14 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
}
|
||||
}
|
||||
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
for (auto conf : list) {
|
||||
if (conf->realDriver == pDriver)
|
||||
/* Make sure NOTHING references this! */
|
||||
List<ConfDbInfo *>::iterator iter;
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
ConfDbInfo &db = *(*iter);
|
||||
if (db.realDriver == pDriver)
|
||||
{
|
||||
conf->realDriver = NULL;
|
||||
db.realDriver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,11 +388,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 +453,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 (conf.name == name)
|
||||
{
|
||||
return &conf;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||
@@ -376,12 +514,13 @@ void DBManager::KillWorkerThread()
|
||||
if (m_Worker)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Lock);
|
||||
ke::AutoLock lock(&m_QueueEvent);
|
||||
m_Terminate = true;
|
||||
m_QueueEvent.notify_all();
|
||||
m_QueueEvent.Notify();
|
||||
}
|
||||
m_Worker->join();
|
||||
m_Worker = nullptr;
|
||||
m_Worker->Join();
|
||||
m_Worker = NULL;
|
||||
s_OneTimeThreaderErrorMsg = false;
|
||||
m_Terminate = false;
|
||||
}
|
||||
}
|
||||
@@ -397,17 +536,25 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
|
||||
|
||||
if (!m_Worker)
|
||||
{
|
||||
m_Worker = ke::NewThread("SM Database Worker", [this]() -> void {
|
||||
Run();
|
||||
});
|
||||
m_Worker = new ke::Thread(this, "SM SQL Worker");
|
||||
if (!m_Worker->Succeeded())
|
||||
{
|
||||
if (!s_OneTimeThreaderErrorMsg)
|
||||
{
|
||||
smcore.LogError("[SM] Unable to create db threader (error unknown)");
|
||||
s_OneTimeThreaderErrorMsg = true;
|
||||
}
|
||||
m_Worker = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add to the queue */
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Lock);
|
||||
ke::AutoLock lock(&m_QueueEvent);
|
||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
||||
queue.push(op);
|
||||
m_QueueEvent.notify_one();
|
||||
m_QueueEvent.Notify();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -438,7 +585,7 @@ void DBManager::Run()
|
||||
|
||||
void DBManager::ThreadMain()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_Lock);
|
||||
ke::AutoLock lock(&m_QueueEvent);
|
||||
|
||||
while (true) {
|
||||
// The lock has been acquired. Grab everything we can out of the
|
||||
@@ -446,43 +593,46 @@ void DBManager::ThreadMain()
|
||||
// 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.
|
||||
while (true)
|
||||
{
|
||||
std::lock_guard<std::mutex> think_lock(m_ThinkLock);
|
||||
m_ThinkQueue.push(op);
|
||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
|
||||
if (queue.empty())
|
||||
break;
|
||||
|
||||
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.
|
||||
{
|
||||
ke::AutoUnlock unlock(&m_QueueEvent);
|
||||
op->RunThreadPart();
|
||||
|
||||
ke::AutoLock lock(&m_ThinkLock);
|
||||
m_ThinkQueue.push(op);
|
||||
}
|
||||
|
||||
|
||||
if (!m_Terminate)
|
||||
{
|
||||
ke::AutoUnlock unlock(&m_QueueEvent);
|
||||
#ifdef _WIN32
|
||||
Sleep(20);
|
||||
#else
|
||||
usleep(20000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (m_Terminate)
|
||||
return;
|
||||
|
||||
lock.lock();
|
||||
// Release the lock and wait for a signal.
|
||||
m_QueueEvent.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +647,7 @@ void DBManager::RunFrame()
|
||||
/* Dump one thing per-frame so the server stays sane. */
|
||||
IDBThreadOperation *op;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ThinkLock);
|
||||
ke::AutoLock lock(&m_ThinkLock);
|
||||
op = m_ThinkQueue.first();
|
||||
m_ThinkQueue.pop();
|
||||
}
|
||||
@@ -542,7 +692,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 +718,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 +728,23 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
||||
}
|
||||
}
|
||||
|
||||
std::string DBManager::GetDefaultDriverName()
|
||||
void DBManager::LockConfig()
|
||||
{
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
return list.GetDefaultDriver();
|
||||
m_ConfigLock.Lock();
|
||||
}
|
||||
|
||||
void DBManager::UnlockConfig()
|
||||
{
|
||||
m_ConfigLock.Unlock();
|
||||
}
|
||||
|
||||
const char *DBManager::GetDefaultDriverName()
|
||||
{
|
||||
return m_DefDriver.c_str();
|
||||
}
|
||||
|
||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||
{
|
||||
g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver);
|
||||
}
|
||||
|
||||
|
||||
+40
-16
@@ -32,28 +32,41 @@
|
||||
#ifndef _INCLUDE_DATABASE_MANAGER_H_
|
||||
#define _INCLUDE_DATABASE_MANAGER_H_
|
||||
|
||||
#include <IDBDriver.h>
|
||||
#include "common_logic.h"
|
||||
#include <sh_vector.h>
|
||||
#include <am-string.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
#include <ITextParsers.h>
|
||||
#include <IThreader.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <am-thread-utils.h>
|
||||
#include "sm_simple_prioqueue.h"
|
||||
#include <am-refcounting.h>
|
||||
#include "DatabaseConfBuilder.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct ConfDbInfo
|
||||
{
|
||||
ConfDbInfo() : realDriver(NULL)
|
||||
{
|
||||
}
|
||||
String name;
|
||||
String driver;
|
||||
String host;
|
||||
String user;
|
||||
String pass;
|
||||
String database;
|
||||
IDBDriver *realDriver;
|
||||
DatabaseInfo info;
|
||||
};
|
||||
|
||||
class DBManager :
|
||||
public IDBManager,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch,
|
||||
public IPluginsListener
|
||||
public ITextListener_SMC,
|
||||
public IPluginsListener,
|
||||
public ke::IRunnable
|
||||
{
|
||||
public:
|
||||
DBManager();
|
||||
@@ -71,7 +84,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,16 +91,25 @@ 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: //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: //ke::IRunnable
|
||||
void Run();
|
||||
void ThreadMain();
|
||||
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()
|
||||
{
|
||||
@@ -104,16 +125,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;
|
||||
ke::AutoPtr<ke::Thread> m_Worker;
|
||||
ke::ConditionVariable m_QueueEvent;
|
||||
ke::Mutex m_ConfigLock;
|
||||
ke::Mutex m_ThinkLock;
|
||||
bool m_Terminate;
|
||||
|
||||
DatabaseConfBuilder m_Builder;
|
||||
List<ConfDbInfo *> m_confs;
|
||||
HandleType_t m_DriverType;
|
||||
HandleType_t m_DatabaseType;
|
||||
String m_DefDriver;
|
||||
char m_Filename[PLATFORM_MAX_PATH];
|
||||
unsigned int m_ParseLevel;
|
||||
unsigned int m_ParseState;
|
||||
IDBDriver *m_pDefault;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2018 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 "DatabaseConfBuilder.h"
|
||||
#include <bridge/include/ILogger.h>
|
||||
|
||||
#define DBPARSE_LEVEL_NONE 0
|
||||
#define DBPARSE_LEVEL_MAIN 1
|
||||
#define DBPARSE_LEVEL_DATABASE 2
|
||||
|
||||
DatabaseConfBuilder::DatabaseConfBuilder()
|
||||
: m_ParseList(),
|
||||
m_InfoList()
|
||||
{
|
||||
}
|
||||
|
||||
void DatabaseConfBuilder::SetPath(char *str)
|
||||
{
|
||||
m_Filename = str;
|
||||
}
|
||||
|
||||
DatabaseConfBuilder::~DatabaseConfBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
ConfDbInfoList &DatabaseConfBuilder::GetConfigList()
|
||||
{
|
||||
return m_InfoList;
|
||||
}
|
||||
|
||||
void DatabaseConfBuilder::StartParse()
|
||||
{
|
||||
SMCError err;
|
||||
SMCStates states = {0, 0};
|
||||
if ((err = textparsers->ParseFile_SMC(m_Filename.c_str(), this, &states)) != SMCError_Okay)
|
||||
{
|
||||
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.c_str());
|
||||
if (err != SMCError_Custom)
|
||||
{
|
||||
const char *txt = textparsers->GetSMCErrorString(err);
|
||||
logger->LogError("[SM] Line %d: %s", states.line, txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseConfBuilder::ReadSMC_ParseStart()
|
||||
{
|
||||
m_ParseLevel = 0;
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
|
||||
m_ParseList.clear();
|
||||
}
|
||||
|
||||
SMCResult DatabaseConfBuilder::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) {
|
||||
m_ParseCurrent = new ConfDbInfo();
|
||||
m_ParseCurrent->name = name;
|
||||
m_ParseState = DBPARSE_LEVEL_DATABASE;
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
m_ParseLevel++;
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
SMCResult DatabaseConfBuilder::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_ParseList.SetDefaultDriver(value);
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
if (strcmp(key, "driver") == 0)
|
||||
{
|
||||
if (strcmp(value, "default") != 0)
|
||||
{
|
||||
m_ParseCurrent->driver = value;
|
||||
}
|
||||
} else if (strcmp(key, "database") == 0) {
|
||||
m_ParseCurrent->database = value;
|
||||
} else if (strcmp(key, "host") == 0) {
|
||||
m_ParseCurrent->host = value;
|
||||
} else if (strcmp(key, "user") == 0) {
|
||||
m_ParseCurrent->user = value;
|
||||
} else if (strcmp(key, "pass") == 0) {
|
||||
m_ParseCurrent->pass = value;
|
||||
} else if (strcmp(key, "timeout") == 0) {
|
||||
m_ParseCurrent->info.maxTimeout = atoi(value);
|
||||
} else if (strcmp(key, "port") == 0) {
|
||||
m_ParseCurrent->info.port = atoi(value);
|
||||
}
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
m_ParseLevel--;
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||
{
|
||||
m_ParseCurrent->info.driver = m_ParseCurrent->driver.c_str();
|
||||
m_ParseCurrent->info.database = m_ParseCurrent->database.c_str();
|
||||
m_ParseCurrent->info.host = m_ParseCurrent->host.c_str();
|
||||
m_ParseCurrent->info.user = m_ParseCurrent->user.c_str();
|
||||
m_ParseCurrent->info.pass = m_ParseCurrent->pass.c_str();
|
||||
|
||||
/* Save it.. */
|
||||
m_ParseCurrent->AddRef();
|
||||
m_ParseList.push_back(m_ParseCurrent);
|
||||
m_ParseCurrent = nullptr;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||
{
|
||||
m_InfoList.clear();
|
||||
m_InfoList = m_ParseList;
|
||||
m_ParseList.clear();
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2018 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_DATABASE_CONF_BUILDER_H_
|
||||
#define _INCLUDE_DATABASE_CONF_BUILDER_H_
|
||||
|
||||
#include <IDBDriver.h>
|
||||
#include <ITextParsers.h>
|
||||
#include "common_logic.h"
|
||||
|
||||
#include <am-vector.h>
|
||||
#include <am-string.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <am-refcounting-threadsafe.h>
|
||||
|
||||
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
|
||||
{
|
||||
public:
|
||||
ConfDbInfo() : realDriver(NULL)
|
||||
{
|
||||
}
|
||||
std::string name;
|
||||
std::string driver;
|
||||
std::string host;
|
||||
std::string user;
|
||||
std::string pass;
|
||||
std::string database;
|
||||
IDBDriver *realDriver;
|
||||
DatabaseInfo info;
|
||||
};
|
||||
|
||||
class ConfDbInfoList : public std::vector<ke::RefPtr<ConfDbInfo>>
|
||||
{
|
||||
/* Allow internal usage of ConfDbInfoList */
|
||||
friend class DBManager;
|
||||
friend class DatabaseConfBuilder;
|
||||
private:
|
||||
std::string& GetDefaultDriver() {
|
||||
return m_DefDriver;
|
||||
}
|
||||
|
||||
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name) {
|
||||
for (size_t i = 0; i < this->size(); i++)
|
||||
{
|
||||
ke::RefPtr<ConfDbInfo> current = this->at(i);
|
||||
/* If we run into the default configuration, then we'll save it
|
||||
* for the next call to GetDefaultConfiguration */
|
||||
if (strcmp(current->name.c_str(), "default") == 0)
|
||||
{
|
||||
m_DefaultConfig = current;
|
||||
}
|
||||
if (strcmp(current->name.c_str(), name) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ke::RefPtr<ConfDbInfo> GetDefaultConfiguration() {
|
||||
return m_DefaultConfig;
|
||||
}
|
||||
void SetDefaultDriver(const char *input) {
|
||||
m_DefDriver = std::string(input);
|
||||
}
|
||||
private:
|
||||
ke::RefPtr<ConfDbInfo> m_DefaultConfig;
|
||||
std::string m_DefDriver;
|
||||
};
|
||||
|
||||
|
||||
class DatabaseConfBuilder : public ITextListener_SMC
|
||||
{
|
||||
public:
|
||||
DatabaseConfBuilder();
|
||||
~DatabaseConfBuilder();
|
||||
void StartParse();
|
||||
void SetPath(char* path);
|
||||
ConfDbInfoList &GetConfigList();
|
||||
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);
|
||||
|
||||
private:
|
||||
unsigned int m_ParseLevel;
|
||||
unsigned int m_ParseState;
|
||||
ConfDbInfo *m_ParseCurrent;
|
||||
ConfDbInfoList m_ParseList;
|
||||
private:
|
||||
std::string m_Filename;
|
||||
ConfDbInfoList m_InfoList;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
|
||||
+65
-111
@@ -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,9 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <ISourceMod.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <stdarg.h>
|
||||
#include "DebugReporter.h"
|
||||
#include "Logger.h"
|
||||
|
||||
DebugReport g_DbgReporter;
|
||||
|
||||
@@ -48,10 +46,10 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, msg);
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), msg, ap);
|
||||
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_Logger.LogMessage("[SM] %s", buffer);
|
||||
smcore.Log("[SM] %s", buffer);
|
||||
}
|
||||
|
||||
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
||||
@@ -66,19 +64,19 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c
|
||||
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);
|
||||
smcore.FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||
|
||||
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||
|
||||
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)
|
||||
{
|
||||
smcore.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||
} else {
|
||||
smcore.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
smcore.LogError("[SM] %s", buffer);
|
||||
|
||||
if (func_idx != -1)
|
||||
{
|
||||
@@ -88,7 +86,7 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
|
||||
sp_public_t *function;
|
||||
if (ctx->GetRuntime()->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
|
||||
smcore.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +98,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, message);
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
||||
smcore.FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||
va_end(ap);
|
||||
|
||||
const char *plname = pluginsys->FindPluginByContext(pContext->GetContext())->GetFilename();
|
||||
@@ -108,18 +106,18 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||
smcore.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||
} else {
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||
smcore.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
smcore.LogError("[SM] %s", buffer);
|
||||
|
||||
IPluginDebugInfo *pDebug;
|
||||
if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL)
|
||||
{
|
||||
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",
|
||||
smcore.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
||||
smcore.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
||||
_GetPluginIndex(pContext));
|
||||
return;
|
||||
}
|
||||
@@ -127,9 +125,54 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
const char *name;
|
||||
if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE)
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
|
||||
smcore.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
|
||||
} else {
|
||||
g_Logger.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
|
||||
smcore.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
||||
{
|
||||
const char *lastname;
|
||||
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
int n_err = error->GetErrorCode();
|
||||
|
||||
if (n_err != SP_ERROR_NATIVE)
|
||||
{
|
||||
smcore.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)
|
||||
{
|
||||
smcore.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
|
||||
} else {
|
||||
smcore.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!error->DebugInfoAvailable())
|
||||
{
|
||||
smcore.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
||||
smcore.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;
|
||||
smcore.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
|
||||
while (error->GetTraceInfo(&stk_info))
|
||||
{
|
||||
smcore.LogError("[SM] [%d] Line %d, %s::%s()",
|
||||
i++,
|
||||
stk_info.line,
|
||||
stk_info.filename,
|
||||
stk_info.function);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,92 +198,3 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
||||
return 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;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
|
||||
#include "sp_vm_api.h"
|
||||
#include "common_logic.h"
|
||||
#include <am-vector.h>
|
||||
#include <am-string.h>
|
||||
|
||||
class DebugReport :
|
||||
public SMGlobalClass,
|
||||
@@ -44,15 +42,12 @@ 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);
|
||||
};
|
||||
|
||||
+155
-143
@@ -30,25 +30,18 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ExtensionSys.h"
|
||||
#include <ILibrarySys.h>
|
||||
#include <ISourceMod.h>
|
||||
#include "common_logic.h"
|
||||
#include "PluginSys.h"
|
||||
#include <am-utility.h>
|
||||
#include <am-string.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
|
||||
CExtensionManager g_Extensions;
|
||||
IdentityType_t g_ExtType;
|
||||
|
||||
void CExtension::Initialize(const char *filename, const char *path, bool bRequired)
|
||||
void CExtension::Initialize(const char *filename, const char *path)
|
||||
{
|
||||
m_bRequired = bRequired;
|
||||
m_pAPI = NULL;
|
||||
m_pIdentToken = NULL;
|
||||
unload_code = 0;
|
||||
@@ -66,7 +59,7 @@ CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filena
|
||||
m_pAPI = pAPI;
|
||||
}
|
||||
|
||||
CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
||||
CLocalExtension::CLocalExtension(const char *filename)
|
||||
{
|
||||
m_PlId = 0;
|
||||
m_pLib = NULL;
|
||||
@@ -76,69 +69,74 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
||||
/* Special case for new bintools binary */
|
||||
if (strcmp(filename, "bintools.ext") == 0)
|
||||
{
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
goto normal;
|
||||
}
|
||||
else
|
||||
|
||||
/* Zeroth, see if there is an engine specific build in the new place. */
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s.%s." PLATFORM_LIB_EXT,
|
||||
filename,
|
||||
smcore.gamesuffix);
|
||||
|
||||
if (libsys->IsPathFile(path))
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
|
||||
if (strcmp(smcore.gamesuffix, "2.tf2") == 0
|
||||
|| strcmp(smcore.gamesuffix, "2.dods") == 0
|
||||
|| strcmp(smcore.gamesuffix, "2.hl2dm") == 0
|
||||
)
|
||||
{
|
||||
/* Zeroth, see if there is an engine specific build in the new place. */
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/" PLATFORM_ARCH_FOLDER "%s.%s." PLATFORM_LIB_EXT,
|
||||
filename,
|
||||
bridge->gamesuffix);
|
||||
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
|
||||
if (!libsys->IsPathFile(path))
|
||||
if (libsys->IsPathFile(path))
|
||||
{
|
||||
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
|
||||
if (strcmp(bridge->gamesuffix, "2.tf2") == 0
|
||||
|| strcmp(bridge->gamesuffix, "2.dods") == 0
|
||||
|| strcmp(bridge->gamesuffix, "2.hl2dm") == 0
|
||||
)
|
||||
{
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/" PLATFORM_ARCH_FOLDER "%s.2.ep2v." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
}
|
||||
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
|
||||
{
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/" PLATFORM_ARCH_FOLDER "%s.2.l4d2." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
}
|
||||
|
||||
//Try further
|
||||
if (!libsys->IsPathFile(path))
|
||||
{
|
||||
/* First see if there is an engine specific build! */
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/" PLATFORM_ARCH_FOLDER "auto.%s/%s." PLATFORM_LIB_EXT,
|
||||
filename,
|
||||
bridge->gamesuffix);
|
||||
|
||||
/* Try the "normal" version */
|
||||
if (!libsys->IsPathFile(path))
|
||||
{
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
}
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
Initialize(filename, path, bRequired);
|
||||
else if (strcmp(smcore.gamesuffix, "2.nd") == 0)
|
||||
{
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
|
||||
if (libsys->IsPathFile(path))
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
/* First see if there is an engine specific build! */
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
|
||||
filename,
|
||||
smcore.gamesuffix);
|
||||
|
||||
/* Try the "normal" version */
|
||||
if (!libsys->IsPathFile(path))
|
||||
{
|
||||
normal:
|
||||
g_pSM->BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
}
|
||||
|
||||
found:
|
||||
Initialize(filename, path);
|
||||
}
|
||||
|
||||
bool CRemoteExtension::Load(char *error, size_t maxlength)
|
||||
@@ -174,7 +172,7 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
ke::SafeStrcpy(error, maxlength, "Unable to find extension entry point");
|
||||
snprintf(error, maxlength, "Unable to find extension entry point");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -193,7 +191,7 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
|
||||
if (m_pAPI->IsMetamodExtension())
|
||||
{
|
||||
bool ok;
|
||||
m_PlId = bridge->LoadMMSPlugin(m_Path.c_str(), &ok, error, maxlength);
|
||||
m_PlId = smcore.LoadMMSPlugin(m_Path.c_str(), &ok, error, maxlength);
|
||||
|
||||
if (!m_PlId || !ok)
|
||||
{
|
||||
@@ -210,7 +208,7 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
if (m_PlId)
|
||||
{
|
||||
bridge->UnloadMMSPlugin(m_PlId);
|
||||
smcore.UnloadMMSPlugin(m_PlId);
|
||||
m_PlId = 0;
|
||||
}
|
||||
}
|
||||
@@ -231,7 +229,7 @@ void CLocalExtension::Unload()
|
||||
{
|
||||
if (m_pAPI != NULL && m_PlId)
|
||||
{
|
||||
bridge->UnloadMMSPlugin(m_PlId);
|
||||
smcore.UnloadMMSPlugin(m_PlId);
|
||||
m_PlId = 0;
|
||||
}
|
||||
|
||||
@@ -240,13 +238,11 @@ void CLocalExtension::Unload()
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
}
|
||||
|
||||
m_bFullyLoaded = false;
|
||||
}
|
||||
|
||||
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
||||
{
|
||||
ke::SafeStrcpy(error, maxlength, "Remote extensions do not support reloading");
|
||||
snprintf(error, maxlength, "Remote extensions do not support reloading");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -280,13 +276,13 @@ bool CExtension::PerformAPICheck(char *error, size_t maxlength)
|
||||
{
|
||||
if (!m_pAPI)
|
||||
{
|
||||
ke::SafeStrcpy(error, maxlength, "No IExtensionInterface instance provided");
|
||||
snprintf(error, maxlength, "No IExtensionInterface instance provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
|
||||
{
|
||||
ke::SafeSprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
|
||||
snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -296,17 +292,18 @@ bool CExtension::PerformAPICheck(char *error, size_t maxlength)
|
||||
bool CExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
CreateIdentity();
|
||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !bridge->IsMapLoading()))
|
||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !smcore.IsMapLoading()))
|
||||
{
|
||||
g_ShareSys.RemoveInterfaces(this);
|
||||
DestroyIdentity();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if we're past load time */
|
||||
if (!bridge->IsMapLoading())
|
||||
else
|
||||
{
|
||||
MarkAllLoaded();
|
||||
/* Check if we're past load time */
|
||||
if (!smcore.IsMapLoading())
|
||||
{
|
||||
m_pAPI->OnExtensionsAllLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -395,6 +392,11 @@ void CExtension::AddDependency(const IfaceInfo *pInfo)
|
||||
}
|
||||
}
|
||||
|
||||
bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
|
||||
{
|
||||
return (i1.iface == i2.iface) && (i1.owner == i2.owner);
|
||||
}
|
||||
|
||||
void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
|
||||
{
|
||||
IfaceInfo info;
|
||||
@@ -416,20 +418,65 @@ void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
|
||||
m_ChildDeps.push_back(info);
|
||||
}
|
||||
|
||||
// note: dependency iteration deprecated since 1.10
|
||||
ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
|
||||
{
|
||||
return nullptr;
|
||||
List<IfaceInfo>::iterator iter = m_Deps.begin();
|
||||
|
||||
if (iter == m_Deps.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pOwner)
|
||||
{
|
||||
*pOwner = (*iter).owner;
|
||||
}
|
||||
if (pInterface)
|
||||
{
|
||||
*pInterface = (*iter).iface;
|
||||
}
|
||||
|
||||
List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
|
||||
|
||||
return (ITERATOR *)pIter;
|
||||
}
|
||||
|
||||
bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
|
||||
{
|
||||
return false;
|
||||
List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
|
||||
List<IfaceInfo>::iterator _iter;
|
||||
|
||||
if (_iter == m_Deps.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_iter++;
|
||||
|
||||
if (pOwner)
|
||||
{
|
||||
*pOwner = (*_iter).owner;
|
||||
}
|
||||
if (pInterface)
|
||||
{
|
||||
*pInterface = (*_iter).iface;
|
||||
}
|
||||
|
||||
*pIter = _iter;
|
||||
|
||||
if (_iter == m_Deps.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CExtension::FreeDependencyIterator(ITERATOR *iter)
|
||||
{
|
||||
List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
|
||||
|
||||
delete pIter;
|
||||
}
|
||||
|
||||
void CExtension::AddInterface(SMInterface *pInterface)
|
||||
@@ -443,7 +490,7 @@ bool CExtension::IsRunning(char *error, size_t maxlength)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
ke::SafeStrcpy(error, maxlength, m_Error.c_str());
|
||||
snprintf(error, maxlength, "%s", m_Error.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -456,11 +503,6 @@ void CExtension::AddLibrary(const char *library)
|
||||
m_Libraries.push_back(library);
|
||||
}
|
||||
|
||||
bool CExtension::IsRequired()
|
||||
{
|
||||
return m_bRequired;
|
||||
}
|
||||
|
||||
/*********************
|
||||
* EXTENSION MANAGER *
|
||||
*********************/
|
||||
@@ -469,7 +511,7 @@ void CExtensionManager::OnSourceModAllInitialized()
|
||||
{
|
||||
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
|
||||
pluginsys->AddPluginsListener(this);
|
||||
rootmenu->AddRootConsoleCommand3("exts", "Manage extensions", this);
|
||||
rootmenu->AddRootConsoleCommand("exts", "Manage extensions", this);
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
@@ -496,7 +538,7 @@ void CExtensionManager::TryAutoload()
|
||||
|
||||
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
|
||||
|
||||
std::unique_ptr<IDirectory> pDir(libsys->OpenDirectory(path));
|
||||
ke::AutoPtr<IDirectory> pDir(libsys->OpenDirectory(path));
|
||||
if (!pDir)
|
||||
return;
|
||||
|
||||
@@ -525,7 +567,7 @@ void CExtensionManager::TryAutoload()
|
||||
}
|
||||
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
len = ke::SafeStrcpy(file, sizeof(file), lfile);
|
||||
len = smcore.Format(file, sizeof(file), "%s", lfile);
|
||||
strcpy(&file[len - 9], ".ext");
|
||||
|
||||
LoadAutoExtension(file);
|
||||
@@ -541,7 +583,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
|
||||
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||
{
|
||||
char path2[PLATFORM_MAX_PATH];
|
||||
ke::SafeStrcpy(path2, sizeof(path2), path);
|
||||
smcore.Format(path2, sizeof(path2), "%s", path);
|
||||
path2[strlen(path) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
|
||||
return LoadAutoExtension(path2, bErrorOnMissing);
|
||||
}
|
||||
@@ -553,7 +595,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
|
||||
}
|
||||
|
||||
char error[256];
|
||||
CExtension *p = new CLocalExtension(path, bErrorOnMissing);
|
||||
CExtension *p = new CLocalExtension(path);
|
||||
|
||||
/* We put us in the list beforehand so extensions that check for each other
|
||||
* won't recursively load each other.
|
||||
@@ -564,7 +606,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
|
||||
{
|
||||
if (bErrorOnMissing || libsys->IsPathFile(p->GetPath()))
|
||||
{
|
||||
logger->LogError("[SM] Unable to load extension \"%s\": %s", path, error);
|
||||
smcore.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
|
||||
}
|
||||
|
||||
p->SetError(error);
|
||||
@@ -628,18 +670,12 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
||||
|
||||
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
||||
{
|
||||
if (strstr(file, "..") != NULL)
|
||||
{
|
||||
ke::SafeStrcpy(error, maxlength, "Cannot load extensions outside the \"extensions\" folder.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove platform extension if it's there. Compat hack. */
|
||||
const char *ext = libsys->GetFileExtension(file);
|
||||
if (ext && strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||
{
|
||||
char path2[PLATFORM_MAX_PATH];
|
||||
ke::SafeStrcpy(path2, sizeof(path2), file);
|
||||
smcore.Format(path2, sizeof(path2), "%s", file);
|
||||
path2[strlen(file) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
|
||||
return LoadExtension(path2, error, maxlength);
|
||||
}
|
||||
@@ -892,18 +928,17 @@ void CExtensionManager::AddDependency(IExtension *pSource, const char *file, boo
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *command)
|
||||
void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||
{
|
||||
int argcount = command->ArgC();
|
||||
int argcount = smcore.Argc(command);
|
||||
if (argcount >= 3)
|
||||
{
|
||||
const char *cmd = command->Arg(2);
|
||||
const char *cmd = smcore.Arg(command, 2);
|
||||
if (strcmp(cmd, "list") == 0)
|
||||
{
|
||||
List<CExtension *>::iterator iter;
|
||||
CExtension *pExt;
|
||||
unsigned int num = 1;
|
||||
|
||||
switch (m_Libs.size())
|
||||
{
|
||||
case 1:
|
||||
@@ -922,7 +957,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (iter = m_Libs.begin(); iter != m_Libs.end(); iter++,num++)
|
||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
|
||||
{
|
||||
pExt = (*iter);
|
||||
if (pExt->IsLoaded())
|
||||
@@ -940,15 +975,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
const char *descr = pAPI->GetExtensionDescription();
|
||||
rootmenu->ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
|
||||
}
|
||||
}
|
||||
else if(pExt->IsRequired() || libsys->PathExists(pExt->GetPath()))
|
||||
{
|
||||
} else {
|
||||
rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
rootmenu->ConsolePrint("[%02d] <OPTIONAL> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -960,11 +989,11 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filename = command->Arg(3);
|
||||
const char *filename = smcore.Arg(command, 3);
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
char error[256];
|
||||
|
||||
ke::SafeSprintf(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "",
|
||||
smcore.Format(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "",
|
||||
!strstr(filename, "." PLATFORM_LIB_EXT) ? "." PLATFORM_LIB_EXT : "");
|
||||
|
||||
if (FindExtensionByFile(path) != NULL)
|
||||
@@ -991,7 +1020,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
return;
|
||||
}
|
||||
|
||||
const char *sId = command->Arg(3);
|
||||
const char *sId = smcore.Arg(command, 3);
|
||||
unsigned int id = atoi(sId);
|
||||
if (id <= 0)
|
||||
{
|
||||
@@ -1076,7 +1105,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
return;
|
||||
}
|
||||
|
||||
const char *arg = command->Arg(3);
|
||||
const char *arg = smcore.Arg(command, 3);
|
||||
unsigned int num = atoi(arg);
|
||||
CExtension *pExt = FindByOrder(num);
|
||||
|
||||
@@ -1088,11 +1117,11 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
|
||||
if (argcount > 4 && pExt->unload_code)
|
||||
{
|
||||
const char *unload = command->Arg(4);
|
||||
const char *unload = smcore.Arg(command, 4);
|
||||
if (pExt->unload_code == (unsigned)atoi(unload))
|
||||
{
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
ke::SafeStrcpy(filename, PLATFORM_MAX_PATH, pExt->GetFilename());
|
||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||
UnloadExtension(pExt);
|
||||
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
|
||||
}
|
||||
@@ -1107,7 +1136,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
|| (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
|
||||
{
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
ke::SafeStrcpy(filename, PLATFORM_MAX_PATH, pExt->GetFilename());
|
||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||
UnloadExtension(pExt);
|
||||
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
|
||||
return;
|
||||
@@ -1142,7 +1171,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
/* Will our dependent care? */
|
||||
if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
|
||||
{
|
||||
rootmenu->ConsolePrint(" -> %s", pOther->GetFilename());
|
||||
rootmenu->ConsolePrint(" -> %s", pExt->GetFilename());
|
||||
/* Add to plugin unload list */
|
||||
List<CPlugin *>::iterator p_iter;
|
||||
for (p_iter=pOther->m_Dependents.begin();
|
||||
@@ -1177,6 +1206,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
|
||||
}
|
||||
}
|
||||
srand(static_cast<int>(time(NULL)));
|
||||
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
||||
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
||||
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
||||
@@ -1192,7 +1222,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
return;
|
||||
}
|
||||
|
||||
const char *arg = command->Arg(3);
|
||||
const char *arg = smcore.Arg(command, 3);
|
||||
unsigned int num = atoi(arg);
|
||||
CExtension *pExt = FindByOrder(num);
|
||||
|
||||
@@ -1207,7 +1237,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
char error[255];
|
||||
|
||||
ke::SafeStrcpy(filename, PLATFORM_MAX_PATH, pExt->GetFilename());
|
||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||
|
||||
if (pExt->Reload(error, sizeof(error)))
|
||||
{
|
||||
@@ -1330,24 +1360,6 @@ void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount,
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::CallOnCoreMapEnd()
|
||||
{
|
||||
IExtensionInterface *pAPI;
|
||||
List<CExtension *>::iterator iter;
|
||||
|
||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
||||
{
|
||||
if ((pAPI = (*iter)->GetAPI()) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pAPI->GetExtensionVersion() > 7)
|
||||
{
|
||||
pAPI->OnCoreMapEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CVector<IExtension *> *CExtensionManager::ListExtensions()
|
||||
{
|
||||
CVector<IExtension *> *list = new CVector<IExtension *>();
|
||||
@@ -1369,7 +1381,7 @@ bool CLocalExtension::IsSameFile(const char *file)
|
||||
|
||||
bool CRemoteExtension::IsSameFile(const char *file)
|
||||
{
|
||||
/* Check full path and name passed in from LoadExternal */
|
||||
return strcmp(file, m_Path.c_str()) == 0 || strcmp(file, m_File.c_str()) == 0;
|
||||
/* :TODO: this could be better, but no one uses this API anyway. */
|
||||
return strcmp(file, m_Path.c_str()) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
#include <bridge/include/IExtensionBridge.h>
|
||||
|
||||
class CPlayer;
|
||||
|
||||
@@ -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();
|
||||
@@ -164,7 +161,7 @@ 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);
|
||||
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
||||
@@ -176,7 +173,6 @@ public:
|
||||
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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user