Compare commits
417
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
313c555e2e | ||
|
|
e5fed0051b | ||
|
|
c2a86c77fd | ||
|
|
8c534e770b | ||
|
|
2c86e8099a | ||
|
|
03eeb23ab3 | ||
|
|
a9c85d8842 | ||
|
|
850ee60a18 | ||
|
|
7cd130904b | ||
|
|
19019d3a4b | ||
|
|
b31375f087 | ||
|
|
1d999c3984 | ||
|
|
fdcbdb6918 | ||
|
|
d42a8c7c1e | ||
|
|
11d3cf94f7 | ||
|
|
0e4b1ca4cf | ||
|
|
1bcc5b8a44 | ||
|
|
7df2f8e045 | ||
|
|
9f3584a056 | ||
|
|
4e73713fab | ||
|
|
e07c120cab | ||
|
|
e3734803f0 | ||
|
|
7c757ac119 | ||
|
|
c5425def7f | ||
|
|
e60c672485 | ||
|
|
908ffdb523 | ||
|
|
d56dc62e03 | ||
|
|
f08f1ef0d6 | ||
|
|
5cb2d68fd7 | ||
|
|
96d0959db1 | ||
|
|
5a6b2c8ebf | ||
|
|
343f64f6b7 | ||
|
|
f9ad35badf | ||
|
|
60b6a8dfb0 | ||
|
|
00f3970036 | ||
|
|
7d78c141e7 | ||
|
|
123ad7aab1 | ||
|
|
ee51162c3f | ||
|
|
af93d819c6 | ||
|
|
d426d1f04f | ||
|
|
6cac489fce | ||
|
|
5c507cc35c | ||
|
|
dbec0b165c | ||
|
|
4e8b66bf99 | ||
|
|
8dcbe14ea0 | ||
|
|
06dcb991e8 | ||
|
|
e262064fd8 | ||
|
|
a80b9c5c0f | ||
|
|
638aae0040 | ||
|
|
35ac74c7a7 | ||
|
|
7bb9da2a26 | ||
|
|
b5b9b8388c | ||
|
|
e7e92d4e40 | ||
|
|
33e869a4e5 | ||
|
|
0bc9aa46e6 | ||
|
|
80ad76a563 | ||
|
|
7e29f22f8f | ||
|
|
a9eb3a0d45 | ||
|
|
ab6b45b81c | ||
|
|
385eae892c | ||
|
|
5f309f45f8 | ||
|
|
a2e5e2a442 | ||
|
|
b42e5ac922 | ||
|
|
544204654d | ||
|
|
5c971fd51b | ||
|
|
6507d947cc | ||
|
|
30415e299e | ||
|
|
8eeea2aba1 | ||
|
|
bb1431cd3b | ||
|
|
a2aec9b42e | ||
|
|
ef74b51c8b | ||
|
|
e74aa099bc | ||
|
|
8140cb2d6b | ||
|
|
d981e252d2 | ||
|
|
e6a04abc9e | ||
|
|
c90477a720 | ||
|
|
11c8084ccd | ||
|
|
7747beb4cf | ||
|
|
9fa7421122 | ||
|
|
f2ca671d1f | ||
|
|
d4da21b07f | ||
|
|
4b2d8b53fa | ||
|
|
7bfd5e521e | ||
|
|
060c832f89 | ||
|
|
8c9fd3746b | ||
|
|
314184beea | ||
|
|
17462cbe5a | ||
|
|
ae4e043c3e | ||
|
|
6def79ff23 | ||
|
|
1ba7024a3a | ||
|
|
44aaaf8b10 | ||
|
|
62754333cd | ||
|
|
8938a29904 | ||
|
|
2c6ef5825f | ||
|
|
b090aa36bf | ||
|
|
cb1dae5aab | ||
|
|
c9e824632f | ||
|
|
0436fb0ab3 | ||
|
|
767c5cf468 | ||
|
|
f01ad5317a | ||
|
|
fac3138ff5 | ||
|
|
ab9e86910c | ||
|
|
e88e9342ef | ||
|
|
e3a01b0e1a | ||
|
|
07d928dbad | ||
|
|
a402b3cceb | ||
|
|
99dbe06d8a | ||
|
|
29694ec13b | ||
|
|
1e8db957bf | ||
|
|
0656696251 | ||
|
|
af04c964fe | ||
|
|
bc81361319 | ||
|
|
853bcf703a | ||
|
|
c81248004a | ||
|
|
79787cb868 | ||
|
|
20aae06f12 | ||
|
|
a20eb08dc6 | ||
|
|
8d60a46358 | ||
|
|
4c376cbcb7 | ||
|
|
d83c498a8f | ||
|
|
531b053096 | ||
|
|
0dafe04899 | ||
|
|
7170a8f11c | ||
|
|
2ef874dbc9 | ||
|
|
cb8541548b | ||
|
|
46e3de8d24 | ||
|
|
5addaffa56 | ||
|
|
f40ae82df4 | ||
|
|
6ebf04b75d | ||
|
|
e93dd7af3f | ||
|
|
4dc2383fe3 | ||
|
|
5f827089d3 | ||
|
|
8a7f8c5cbd | ||
|
|
dae8aba554 | ||
|
|
b9029dedff | ||
|
|
1a375bcc17 | ||
|
|
eaccec3e4a | ||
|
|
5fff988a8f | ||
|
|
1a1bb54c4f | ||
|
|
97f2fc9d7f | ||
|
|
2e1235a585 | ||
|
|
426c1a090f | ||
|
|
50b4ad4e11 | ||
|
|
a330d0a1bf | ||
|
|
4e6774befb | ||
|
|
b1b993989a | ||
|
|
2e59202ea4 | ||
|
|
4a6d29c9e2 | ||
|
|
e746fdf1fb | ||
|
|
cac7793f15 | ||
|
|
e0c95674c8 | ||
|
|
bc42cef765 | ||
|
|
680a198fa2 | ||
|
|
38f7be7664 | ||
|
|
94f5b5d06c | ||
|
|
f66a904c31 | ||
|
|
8e0039aaec | ||
|
|
dd1e5997f3 | ||
|
|
bc6e920213 | ||
|
|
a28c3cac9b | ||
|
|
6670b93cc6 | ||
|
|
8826663186 | ||
|
|
c5087d7a39 | ||
|
|
5ba9816377 | ||
|
|
4eecc80b9a | ||
|
|
008fbf78a5 | ||
|
|
48150e0c7a | ||
|
|
d8fd60b562 | ||
|
|
178658912e | ||
|
|
5539484f92 | ||
|
|
a9a1939f75 | ||
|
|
850f96b986 | ||
|
|
693e584dcd | ||
|
|
397b70add0 | ||
|
|
a0eb6a9550 | ||
|
|
6bd49ff415 | ||
|
|
43cdc65708 | ||
|
|
cd6886319c | ||
|
|
6e839a95c6 | ||
|
|
2dcee81f22 | ||
|
|
a253d35bcd | ||
|
|
02e9d214b4 | ||
|
|
30a2160839 | ||
|
|
d57d7e7401 | ||
|
|
1f5b735dbd | ||
|
|
d5a26adc49 | ||
|
|
221d34f809 | ||
|
|
8922ed0c5d | ||
|
|
27b1817b10 | ||
|
|
3a488f7041 | ||
|
|
8f7a1641fc | ||
|
|
b0799d3336 | ||
|
|
2130c60fd9 | ||
|
|
ecb707e38d | ||
|
|
7e94bfb307 | ||
|
|
51bba0b894 | ||
|
|
775d4f04f2 | ||
|
|
4320d7b17a | ||
|
|
174bf307a2 | ||
|
|
f8349e846a | ||
|
|
ef7d3abefd | ||
|
|
b77e8c50ac | ||
|
|
0d6179299c | ||
|
|
515df38b72 | ||
|
|
c5e69900f9 | ||
|
|
2d5bc4007f | ||
|
|
3a315e88c2 | ||
|
|
6c5a3fdaf2 | ||
|
|
02f188899e | ||
|
|
aab8c6ac9f | ||
|
|
5d391fda07 | ||
|
|
8538233985 | ||
|
|
3b4a343274 | ||
|
|
f90b7ade76 | ||
|
|
83a29cf82b | ||
|
|
89bd4d7329 | ||
|
|
ed662dc8cf | ||
|
|
6574dd8273 | ||
|
|
63f8ea89ca | ||
|
|
34c8220e5d | ||
|
|
3595525f12 | ||
|
|
4989666d72 | ||
|
|
f7fda0023c | ||
|
|
13be211e9a | ||
|
|
f6b39720ec | ||
|
|
764e38a58f | ||
|
|
e34e9b9869 | ||
|
|
721f348684 | ||
|
|
9ddcd335af | ||
|
|
eda9a42ee2 | ||
|
|
22a964d89a | ||
|
|
855ece1d3b | ||
|
|
568da23c96 | ||
|
|
4015f9c1c9 | ||
|
|
21740d9a26 | ||
|
|
05aa3fd39d | ||
|
|
3100e23b87 | ||
|
|
da3e868df5 | ||
|
|
63e0e2bc82 | ||
|
|
a35ecde538 | ||
|
|
81ad870def | ||
|
|
24f1c89b96 | ||
|
|
a761194917 | ||
|
|
9321229321 | ||
|
|
e5ebd65176 | ||
|
|
5f7b22d2a4 | ||
|
|
52da989762 | ||
|
|
625c7a98f2 | ||
|
|
278998f7d0 | ||
|
|
c29e185d2a | ||
|
|
5c66a78763 | ||
|
|
5e3a189642 | ||
|
|
7b89f5fab3 | ||
|
|
b0e7407552 | ||
|
|
407c24cb14 | ||
|
|
65cb76e2f6 | ||
|
|
678ad74bf4 | ||
|
|
12e20eecf7 | ||
|
|
a5ae01a2f4 | ||
|
|
614c7d8332 | ||
|
|
9121472061 | ||
|
|
54fd778830 | ||
|
|
37c2a83523 | ||
|
|
28a5d4b342 | ||
|
|
0dcfdf3d7e | ||
|
|
0f7f9dad97 | ||
|
|
4276301499 | ||
|
|
d41ffaad7e | ||
|
|
5c0ae11a46 | ||
|
|
7424deefb9 | ||
|
|
c92354debb | ||
|
|
50eca8e60c | ||
|
|
c570150318 | ||
|
|
3bafc1e2f4 | ||
|
|
e28bf30b7d | ||
|
|
7becdc48d3 | ||
|
|
7a3d4e70bf | ||
|
|
6e73aba250 | ||
|
|
5797411b2b | ||
|
|
d2c4257c36 | ||
|
|
b057580a62 | ||
|
|
a1ad9e1acf | ||
|
|
a877a4475b | ||
|
|
441259e36a | ||
|
|
ab8bbbd118 | ||
|
|
39d604ae6c | ||
|
|
a7cb35c2af | ||
|
|
ff558b32e5 | ||
|
|
6b588fff61 | ||
|
|
3f3f1b8914 | ||
|
|
05e48ef866 | ||
|
|
6e1f095186 | ||
|
|
852703ccca | ||
|
|
01203a5a44 | ||
|
|
96ae65a96c | ||
|
|
9df93b0708 | ||
|
|
f307e44b79 | ||
|
|
dc8a22a76a | ||
|
|
8579e873ca | ||
|
|
addfb3c8a1 | ||
|
|
358bcca3a2 | ||
|
|
b209279589 | ||
|
|
5479084039 | ||
|
|
95ab60c4eb | ||
|
|
2111e90540 | ||
|
|
dc9c52bfd6 | ||
|
|
f5461df28c | ||
|
|
e5afdb4181 | ||
|
|
250dc1b206 | ||
|
|
f5f26e2dfe | ||
|
|
f7c54e9027 | ||
|
|
1ce828b6c8 | ||
|
|
c471e41dc7 | ||
|
|
afc9310704 | ||
|
|
bf898dd45f | ||
|
|
7d6eb2bd81 | ||
|
|
547ac5b026 | ||
|
|
7328ce657b | ||
|
|
14c9ac8fdb | ||
|
|
93cd78a6c5 | ||
|
|
b62f332611 | ||
|
|
47f135534d | ||
|
|
bb095097a2 | ||
|
|
c873e1aafb | ||
|
|
455bb14589 | ||
|
|
e786ff54f7 | ||
|
|
af3c10b173 | ||
|
|
351ac171d2 | ||
|
|
96c74651db | ||
|
|
329d587214 | ||
|
|
4e3df76358 | ||
|
|
161084e6f8 | ||
|
|
b38c9824fe | ||
|
|
4e4c2a7bb0 | ||
|
|
1c30b88069 | ||
|
|
31f6c0cb18 | ||
|
|
9cb693d8a3 | ||
|
|
896e92264f | ||
|
|
f32b210ec9 | ||
|
|
8f7ecf66a4 | ||
|
|
581068c09b | ||
|
|
0f5f1a814e | ||
|
|
18f9d65938 | ||
|
|
589fc96bc9 | ||
|
|
5787fca029 | ||
|
|
09ea982bbd | ||
|
|
e3569edb65 | ||
|
|
3db7116620 | ||
|
|
83672a6ce0 | ||
|
|
90fec5c6df | ||
|
|
257535daf2 | ||
|
|
eb0878be2b | ||
|
|
f229badbfc | ||
|
|
9a6866d14a | ||
|
|
8991b557ab | ||
|
|
be60a55aa3 | ||
|
|
10795fbed5 | ||
|
|
9d7e720f33 | ||
|
|
7605940994 | ||
|
|
94ff26bdf1 | ||
|
|
2a06680252 | ||
|
|
38a069b97a | ||
|
|
4b58b9f673 | ||
|
|
ffc23a1a1e | ||
|
|
cab60f7385 | ||
|
|
92ce0fe814 | ||
|
|
79d594aca3 | ||
|
|
a343410793 | ||
|
|
3332da3489 | ||
|
|
1a65b308d1 | ||
|
|
f9309c83d2 | ||
|
|
636161e183 | ||
|
|
897878f8ae | ||
|
|
7650cee459 | ||
|
|
30c764e4b3 | ||
|
|
dc92335fbe | ||
|
|
8c625ca87d | ||
|
|
536750b428 | ||
|
|
11e7bb10f1 | ||
|
|
f7cd28cfd3 | ||
|
|
83c7bdf872 | ||
|
|
97383028e5 | ||
|
|
4a6d263dad | ||
|
|
549e881ba4 | ||
|
|
c72ea03a86 | ||
|
|
9fed0724f7 | ||
|
|
ed96da1afc | ||
|
|
da3146e294 | ||
|
|
5aa0cdfd45 | ||
|
|
0be7813398 | ||
|
|
de84f47503 | ||
|
|
115e3d4392 | ||
|
|
9f101ce67f | ||
|
|
9295bc4fbb | ||
|
|
9e083ec668 | ||
|
|
68c8857410 | ||
|
|
9323d1094f | ||
|
|
dc2967b2e7 | ||
|
|
6d85c09e69 | ||
|
|
6a8177145d | ||
|
|
baf686c6c4 | ||
|
|
34c5eed867 | ||
|
|
59840685a4 | ||
|
|
c4e33cab8c | ||
|
|
bf0741e48a | ||
|
|
51b5bbac0d | ||
|
|
03699a4a9e | ||
|
|
57a38636fc | ||
|
|
a5f99c57e1 | ||
|
|
1b0c7bc1b8 | ||
|
|
d84fd76070 | ||
|
|
677697a168 | ||
|
|
0fd4fa7066 | ||
|
|
0932d78d26 | ||
|
|
106f807b68 | ||
|
|
c3e6428ff7 | ||
|
|
78cb89938d |
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
# Check for updates to GitHub Actions every week
|
||||
interval: "weekly"
|
||||
@@ -3,14 +3,16 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04, ubuntu-latest, windows-latest]
|
||||
os: [ubuntu-20.04, ubuntu-latest, windows-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
@@ -19,10 +21,10 @@ jobs:
|
||||
os_short: linux
|
||||
compiler_cc: clang
|
||||
compiler_cxx: clang++
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
os_short: linux
|
||||
compiler_cc: clang-3.9
|
||||
compiler_cxx: clang++-3.9
|
||||
compiler_cc: clang-8
|
||||
compiler_cxx: clang++-8
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: ${{ matrix.os_short }}-${{ matrix.compiler_cc }}
|
||||
@@ -32,15 +34,15 @@ jobs:
|
||||
DEPENDENCIES_FOLDER: dependencies
|
||||
DEPENDENCIES_ROOT: ${{ github.workspace }}/dependencies
|
||||
MYSQL_VERSION: '5.5'
|
||||
MMSOURCE_VERSION: '1.10'
|
||||
MMSOURCE_VERSION: '1.12'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
path: sourcemod
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: hl2sdk-mysql-mmsource
|
||||
with:
|
||||
@@ -51,7 +53,7 @@ jobs:
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-
|
||||
|
||||
# Setup Python for AMBuild
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.8
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
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
|
||||
@@ -3,6 +3,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
paths:
|
||||
- 'plugins/include/*'
|
||||
- 'sourcepawn/**'
|
||||
@@ -26,12 +27,12 @@ jobs:
|
||||
env:
|
||||
ARCH: x86,x86_64
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
# Setup Python for AMBuild
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v5
|
||||
name: Setup Python 3.8
|
||||
with:
|
||||
python-version: 3.8
|
||||
@@ -40,9 +41,9 @@ jobs:
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install git+https://github.com/alliedmodders/ambuild
|
||||
|
||||
- name: Build only for x64 on macOS
|
||||
- name: Build universal x64/arm64 on macOS
|
||||
if: startsWith(runner.os, 'macOS')
|
||||
run: echo "ARCH=x86_64" >> $GITHUB_ENV
|
||||
run: echo "ARCH=x86_64,arm64" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
@@ -72,7 +73,7 @@ jobs:
|
||||
echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV
|
||||
|
||||
- name: Archive tooling
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
|
||||
path: build/package
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
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
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
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
|
||||
|
||||
+5
-1
@@ -28,7 +28,6 @@ LIB-Debug/
|
||||
[Tt]humbs.db
|
||||
|
||||
# AMBuild build directories
|
||||
build/
|
||||
obj-*/
|
||||
*~
|
||||
*.rej
|
||||
@@ -37,3 +36,8 @@ obj-*/
|
||||
*.swp
|
||||
*.gdb_history
|
||||
objdir
|
||||
# Not standardized, but common name for build directories
|
||||
build*/
|
||||
|
||||
.vs/*
|
||||
.vscode/*
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
[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
|
||||
|
||||
+156
-242
@@ -1,70 +1,7 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import collections
|
||||
import os, sys
|
||||
import traceback
|
||||
|
||||
class SDK(object):
|
||||
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
||||
self.folder = 'hl2sdk-' + dir
|
||||
self.envvar = sdk
|
||||
self.ext = ext
|
||||
self.code = aDef
|
||||
self.define = name
|
||||
self.platform = platform
|
||||
self.name = dir
|
||||
self.path = None # Actual path
|
||||
self.platformSpec = platform
|
||||
|
||||
# By default, nothing supports x64.
|
||||
if type(platform) is list:
|
||||
self.platformSpec = {p: ['x86'] for p in platform}
|
||||
else:
|
||||
self.platformSpec = platform
|
||||
|
||||
def shouldBuild(self, targets):
|
||||
for cxx in targets:
|
||||
if cxx.target.platform in self.platformSpec:
|
||||
if cxx.target.arch in self.platformSpec[cxx.target.platform]:
|
||||
return True
|
||||
return False
|
||||
|
||||
WinOnly = ['windows']
|
||||
WinLinux = ['windows', 'linux']
|
||||
WinLinuxMac = ['windows', 'linux', 'mac']
|
||||
CSGO = {
|
||||
'windows': ['x86'],
|
||||
'linux': ['x86', 'x86_64'],
|
||||
'mac': ['x86_64']
|
||||
}
|
||||
|
||||
SDKMap = {
|
||||
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
||||
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
||||
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
|
||||
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
|
||||
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
|
||||
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
|
||||
'tf2': SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'),
|
||||
'l4d': SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
|
||||
'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
|
||||
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
|
||||
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
|
||||
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'),
|
||||
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
|
||||
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
||||
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
|
||||
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
|
||||
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinOnly, 'blade'),
|
||||
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
||||
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
|
||||
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
|
||||
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
|
||||
}
|
||||
|
||||
# Stable sorting for command equivalence in AMBuild.
|
||||
PossibleSDKs = collections.OrderedDict()
|
||||
for key in sorted(SDKMap.keys()):
|
||||
PossibleSDKs[key] = SDKMap[key]
|
||||
import subprocess
|
||||
|
||||
def ResolveEnvPath(env, folder):
|
||||
if env in os.environ:
|
||||
@@ -95,9 +32,15 @@ def SetArchFlags(compiler):
|
||||
if compiler.target.arch == 'x86_64':
|
||||
compiler.defines += ['WIN64']
|
||||
|
||||
SdkHelpers = builder.Eval('hl2sdk-manifests/SdkHelpers.ambuild', {
|
||||
'Project': 'sourcemod'
|
||||
})
|
||||
|
||||
class SMConfig(object):
|
||||
def __init__(self):
|
||||
self.sdk_manifests = []
|
||||
self.sdks = {}
|
||||
self.sdk_targets = []
|
||||
self.binaries = []
|
||||
self.spvm = []
|
||||
self.extensions = []
|
||||
@@ -105,12 +48,14 @@ class SMConfig(object):
|
||||
self.mms_root = None
|
||||
self.mysql_root = {}
|
||||
self.spcomp = None
|
||||
self.spcomp_bins = None
|
||||
self.spcomp_bins = []
|
||||
self.smx_files = {}
|
||||
self.versionlib = None
|
||||
self.all_targets = []
|
||||
self.target_archs = set()
|
||||
|
||||
self.enable_asan = getattr(builder.options, 'enable_asan', False)
|
||||
self.asan_libs = {}
|
||||
self.libsafetyhook = {}
|
||||
|
||||
if builder.options.targets:
|
||||
target_archs = builder.options.targets.split(',')
|
||||
@@ -152,41 +97,38 @@ class SMConfig(object):
|
||||
import re
|
||||
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
||||
productContents = fp.read()
|
||||
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||
m = re.match(r'(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||
if m == None:
|
||||
self.productVersion = '1.0.0'
|
||||
else:
|
||||
major, minor, release = m.groups()
|
||||
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
|
||||
|
||||
def findSdkPath(self, sdk_name):
|
||||
dir_name = 'hl2sdk-{}'.format(sdk_name)
|
||||
if builder.options.hl2sdk_root:
|
||||
sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
|
||||
if os.path.exists(sdk_path):
|
||||
return sdk_path
|
||||
return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
|
||||
|
||||
def shouldIncludeSdk(self, sdk):
|
||||
return not sdk.get('source2', False)
|
||||
|
||||
def detectSDKs(self):
|
||||
sdk_list = builder.options.sdks.split(',')
|
||||
use_none = sdk_list[0] == 'none'
|
||||
use_all = sdk_list[0] == 'all'
|
||||
use_present = sdk_list[0] == 'present'
|
||||
sdk_list = [s for s in builder.options.sdks.split(',') if s]
|
||||
SdkHelpers.sdk_filter = self.shouldIncludeSdk
|
||||
SdkHelpers.find_sdk_path = self.findSdkPath
|
||||
SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
|
||||
|
||||
for sdk_name in PossibleSDKs:
|
||||
sdk = PossibleSDKs[sdk_name]
|
||||
if sdk.shouldBuild(self.all_targets):
|
||||
if builder.options.hl2sdk_root:
|
||||
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
||||
else:
|
||||
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
||||
if sdk_path is None or not os.path.isdir(sdk_path):
|
||||
if use_all or sdk_name in sdk_list:
|
||||
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
||||
continue
|
||||
if use_all or use_present or sdk_name in sdk_list:
|
||||
sdk.path = Normalize(sdk_path)
|
||||
self.sdks[sdk_name] = sdk
|
||||
|
||||
if len(self.sdks) < 1 and len(sdk_list) and not use_none:
|
||||
raise Exception('No applicable SDKs were found, nothing to do')
|
||||
self.sdks = SdkHelpers.sdks
|
||||
self.sdk_manifests = SdkHelpers.sdk_manifests
|
||||
self.sdk_targets = SdkHelpers.sdk_targets
|
||||
|
||||
if builder.options.mms_path:
|
||||
self.mms_root = builder.options.mms_path
|
||||
else:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
|
||||
if not self.mms_root:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||
if not self.mms_root:
|
||||
@@ -224,7 +166,14 @@ class SMConfig(object):
|
||||
def configure(self):
|
||||
builder.AddConfigureFile('pushbuild.txt')
|
||||
|
||||
if not set(self.target_archs).issubset(['x86', 'x86_64']):
|
||||
allowed_archs = ['x86_64']
|
||||
if builder.host.platform == 'mac':
|
||||
if getattr(builder.options, 'scripting_only', False):
|
||||
allowed_archs += ['arm64']
|
||||
else:
|
||||
allowed_archs += ['x86']
|
||||
|
||||
if not set(self.target_archs).issubset(allowed_archs):
|
||||
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
|
||||
|
||||
for cxx in self.all_targets:
|
||||
@@ -232,14 +181,14 @@ class SMConfig(object):
|
||||
|
||||
def configure_cxx(self, cxx):
|
||||
if cxx.family == 'msvc':
|
||||
if cxx.version < 1900:
|
||||
raise Exception('Only MSVC 2015 and later are supported, c++14 support is required.')
|
||||
if cxx.family == 'gcc':
|
||||
if cxx.version < 'gcc-4.9':
|
||||
raise Exception('Only GCC versions 4.9 or greater are supported, c++14 support is required.')
|
||||
if cxx.family == 'clang':
|
||||
if cxx.version < 'clang-3.4':
|
||||
raise Exception('Only clang versions 3.4 or greater are supported, c++14 support is required.')
|
||||
if cxx.version < 1914 and builder.options.generator != 'vs':
|
||||
raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
|
||||
elif cxx.family == 'gcc':
|
||||
if cxx.version < 'gcc-9':
|
||||
raise Exception('Only GCC versions 9 or later are supported, full C++17 support is required.')
|
||||
elif cxx.family == 'clang':
|
||||
if cxx.version < 'clang-5':
|
||||
raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.')
|
||||
|
||||
if cxx.like('gcc'):
|
||||
self.configure_gcc(cxx)
|
||||
@@ -294,19 +243,18 @@ class SMConfig(object):
|
||||
'-Wno-unused',
|
||||
'-Wno-switch',
|
||||
'-Wno-array-bounds',
|
||||
'-msse',
|
||||
'-fvisibility=hidden',
|
||||
]
|
||||
if cxx.target.arch in ['x86', 'x86_64']:
|
||||
cxx.cflags += ['-msse']
|
||||
|
||||
if cxx.version == 'apple-clang-6.0' or cxx.version == 'clang-3.4':
|
||||
cxx.cxxflags += ['-std=c++1y']
|
||||
else:
|
||||
cxx.cxxflags += ['-std=c++14']
|
||||
cxx.cxxflags += ['-std=c++17']
|
||||
|
||||
cxx.cxxflags += [
|
||||
'-fno-threadsafe-statics',
|
||||
'-Wno-non-virtual-dtor',
|
||||
'-Wno-overloaded-virtual',
|
||||
'-Wno-register',
|
||||
'-fvisibility-inlines-hidden',
|
||||
]
|
||||
|
||||
@@ -336,6 +284,11 @@ class SMConfig(object):
|
||||
cxx.cxxflags += ['-Wno-deprecated']
|
||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||
|
||||
if self.enable_asan:
|
||||
if not have_clang:
|
||||
raise Exception('--enable-asan only supported when using Clang')
|
||||
self.configure_asan(cxx)
|
||||
|
||||
# Work around SDK warnings.
|
||||
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
|
||||
cxx.cflags += [
|
||||
@@ -348,12 +301,18 @@ class SMConfig(object):
|
||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||
|
||||
if builder.options.opt == '1':
|
||||
cxx.cflags += ['-O3']
|
||||
if self.enable_asan:
|
||||
cxx.cflags += ['-O1']
|
||||
else:
|
||||
cxx.cflags += ['-O3']
|
||||
|
||||
# Don't omit the frame pointer.
|
||||
cxx.cflags += ['-fno-omit-frame-pointer']
|
||||
|
||||
def configure_msvc(self, cxx):
|
||||
if self.enable_asan:
|
||||
raise Exception('--enable-asan only supported when using Clang')
|
||||
|
||||
if builder.options.debug == '1':
|
||||
cxx.cflags += ['/MTd']
|
||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||
@@ -372,6 +331,7 @@ class SMConfig(object):
|
||||
'/EHsc',
|
||||
'/GR-',
|
||||
'/TP',
|
||||
'/std:c++17',
|
||||
]
|
||||
cxx.linkflags += [
|
||||
'kernel32.lib',
|
||||
@@ -399,8 +359,31 @@ class SMConfig(object):
|
||||
# Don't omit the frame pointer.
|
||||
cxx.cflags += ['/Oy-']
|
||||
|
||||
def configure_asan(self, cxx):
|
||||
if cxx.target.platform != 'linux':
|
||||
raise Exception('--enable-asan only supported on Linux')
|
||||
cxx.cflags += ['-fsanitize=address']
|
||||
cxx.linkflags += ['-fsanitize=address']
|
||||
if cxx.target.arch == 'x86':
|
||||
libclang_rt = 'libclang_rt.asan-i386.so'
|
||||
else:
|
||||
libclang_rt = 'libclang_rt.asan-x86_64.so'
|
||||
|
||||
try:
|
||||
argv = cxx.cxx_argv + ['--print-file-name', libclang_rt]
|
||||
output = subprocess.check_output(argv)
|
||||
output = output.decode('utf-8')
|
||||
output = output.strip()
|
||||
except:
|
||||
raise Exception('Could not find {}'.format(libclang_rt))
|
||||
|
||||
print('ASAN library for {}: {}'.format(cxx.target.arch, output))
|
||||
print('You will need to LD_PRELOAD this into srcds.')
|
||||
|
||||
self.asan_libs[cxx.target.arch] = os.path.dirname(output)
|
||||
|
||||
def configure_linux(self, cxx):
|
||||
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||
cxx.linkflags += ['-lm']
|
||||
if cxx.family == 'gcc':
|
||||
cxx.linkflags += ['-static-libgcc']
|
||||
@@ -410,9 +393,9 @@ class SMConfig(object):
|
||||
|
||||
def configure_mac(self, cxx):
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.7']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.15']
|
||||
cxx.linkflags += [
|
||||
'-mmacosx-version-min=10.7',
|
||||
'-mmacosx-version-min=10.15',
|
||||
'-stdlib=libc++',
|
||||
'-lc++',
|
||||
]
|
||||
@@ -447,7 +430,7 @@ class SMConfig(object):
|
||||
'-current_version', self.productVersion
|
||||
]
|
||||
if self.use_auto_versioning():
|
||||
binary.compiler.linkflags += [self.versionlib[binary.compiler.target.arch]]
|
||||
binary.compiler.postlink += [self.versionlib[binary.compiler.target.arch]]
|
||||
binary.compiler.sourcedeps += SM.generated_headers
|
||||
return binary
|
||||
|
||||
@@ -456,6 +439,14 @@ class SMConfig(object):
|
||||
self.AddVersioning(binary)
|
||||
if binary.compiler.like('msvc'):
|
||||
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
||||
self.AddCxxCompat(binary)
|
||||
|
||||
# Dumb clang behavior means we have to manually find libclang_rt.
|
||||
if self.enable_asan:
|
||||
binary.compiler.linkflags += [
|
||||
'-shared-libsan',
|
||||
'-Wl,-rpath={}'.format(self.asan_libs[binary.compiler.target.arch]),
|
||||
]
|
||||
return binary
|
||||
|
||||
def ProgramBuilder(self, compiler, name):
|
||||
@@ -463,6 +454,8 @@ class SMConfig(object):
|
||||
self.AddVersioning(binary)
|
||||
if '-static-libgcc' in binary.compiler.linkflags:
|
||||
binary.compiler.linkflags.remove('-static-libgcc')
|
||||
if self.enable_asan:
|
||||
binary.compiler.linkflags.append('-static-libsan')
|
||||
if '-lgcc_eh' in binary.compiler.linkflags:
|
||||
binary.compiler.linkflags.remove('-lgcc_eh')
|
||||
if binary.compiler.like('gcc'):
|
||||
@@ -506,6 +499,12 @@ class SMConfig(object):
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return binary
|
||||
|
||||
def AddCxxCompat(self, binary):
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.sources += [
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
|
||||
]
|
||||
|
||||
def ConfigureForHL2(self, context, binary, sdk):
|
||||
compiler = binary.compiler
|
||||
SetArchFlags(compiler)
|
||||
@@ -515,137 +514,24 @@ class SMConfig(object):
|
||||
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||
]
|
||||
|
||||
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
||||
compiler.defines += defines
|
||||
for other_sdk in self.sdk_manifests:
|
||||
compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
|
||||
|
||||
paths = [
|
||||
['public'],
|
||||
['public', 'engine'],
|
||||
['public', 'mathlib'],
|
||||
['public', 'vstdlib'],
|
||||
['public', 'tier0'],
|
||||
['public', 'tier1']
|
||||
]
|
||||
if sdk.name == 'episode1' or sdk.name == 'darkm':
|
||||
paths.append(['public', 'dlls'])
|
||||
paths.append(['game_shared'])
|
||||
else:
|
||||
paths.append(['public', 'game', 'server'])
|
||||
paths.append(['public', 'toolframework'])
|
||||
paths.append(['game', 'shared'])
|
||||
paths.append(['common'])
|
||||
|
||||
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
|
||||
|
||||
if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
|
||||
# The 2013 SDK already has these in public/tier0/basetypes.h
|
||||
compiler.defines.remove('stricmp=strcasecmp')
|
||||
compiler.defines.remove('_stricmp=strcasecmp')
|
||||
compiler.defines.remove('_snprintf=snprintf')
|
||||
compiler.defines.remove('_vsnprintf=vsnprintf')
|
||||
|
||||
if compiler.like('msvc'):
|
||||
compiler.defines += ['COMPILER_MSVC']
|
||||
if compiler.target.arch == 'x86':
|
||||
compiler.defines += ['COMPILER_MSVC32']
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
compiler.defines += ['COMPILER_MSVC64']
|
||||
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
||||
else:
|
||||
compiler.defines += ['COMPILER_GCC']
|
||||
|
||||
if compiler.target.arch == 'x86_64':
|
||||
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
|
||||
|
||||
# For everything after Swarm, this needs to be defined for entity networking
|
||||
# to work properly with sendprop value changes.
|
||||
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
||||
compiler.defines += ['NETWORK_VARS_ENABLED']
|
||||
|
||||
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
|
||||
if compiler.target.platform in ['linux', 'mac']:
|
||||
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||
|
||||
if compiler.target.platform == 'linux':
|
||||
if sdk.name in ['csgo', 'blade']:
|
||||
compiler.linkflags.remove('-static-libstdc++')
|
||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||
|
||||
for path in paths:
|
||||
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||
|
||||
if compiler.target.platform == 'linux':
|
||||
if sdk.name == 'episode1':
|
||||
lib_folder = os.path.join(sdk.path, 'linux_sdk')
|
||||
elif sdk.name in ['sdk2013', 'bms']:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
|
||||
else:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
||||
elif compiler.target.platform == 'mac':
|
||||
if sdk.name in ['sdk2013', 'bms']:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
|
||||
else:
|
||||
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
||||
|
||||
if compiler.target.platform in ['linux', 'mac']:
|
||||
if sdk.name in ['sdk2013', 'bms'] or compiler.target.arch == 'x86_64':
|
||||
compiler.postlink += [
|
||||
os.path.join(lib_folder, 'tier1.a'),
|
||||
os.path.join(lib_folder, 'mathlib.a')
|
||||
]
|
||||
else:
|
||||
compiler.postlink += [
|
||||
os.path.join(lib_folder, 'tier1_i486.a'),
|
||||
os.path.join(lib_folder, 'mathlib_i486.a')
|
||||
]
|
||||
|
||||
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
||||
if compiler.target.arch == 'x86_64':
|
||||
compiler.postlink += [os.path.join(lib_folder, 'interfaces.a')]
|
||||
else:
|
||||
compiler.postlink += [os.path.join(lib_folder, 'interfaces_i486.a')]
|
||||
|
||||
dynamic_libs = []
|
||||
if compiler.target.platform == 'linux':
|
||||
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
|
||||
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
||||
elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'blade']:
|
||||
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
|
||||
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
|
||||
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
||||
else:
|
||||
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
||||
elif compiler.target.platform == 'mac':
|
||||
compiler.linkflags.append('-liconv')
|
||||
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
||||
elif compiler.target.platform == 'windows':
|
||||
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
|
||||
libs.append('interfaces')
|
||||
for lib in libs:
|
||||
if compiler.target.arch == 'x86':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'public', 'win64', lib) + '.lib'
|
||||
compiler.linkflags.append(lib_path)
|
||||
|
||||
for library in dynamic_libs:
|
||||
source_path = os.path.join(lib_folder, library)
|
||||
output_path = os.path.join(binary.localFolder, library)
|
||||
|
||||
# Ensure the output path exists.
|
||||
context.AddFolder(binary.localFolder)
|
||||
output = context.AddSymlink(source_path, output_path)
|
||||
|
||||
compiler.weaklinkdeps += [output]
|
||||
compiler.linkflags[0:0] = [library]
|
||||
SdkHelpers.configureCxx(context, binary, sdk)
|
||||
|
||||
return binary
|
||||
|
||||
def AddCDetour(self, binary):
|
||||
public_path = os.path.join(builder.sourcePath, 'public')
|
||||
binary.sources += [ os.path.join(public_path, 'CDetour', 'detours.cpp') ]
|
||||
binary.compiler.cxxincludes += [ os.path.join(public_path, 'safetyhook', 'include') ]
|
||||
|
||||
for task in self.libsafetyhook:
|
||||
if task.target.arch == binary.compiler.target.arch:
|
||||
binary.compiler.linkflags += [task.binary]
|
||||
return
|
||||
raise Exception('No suitable build of safetyhook was found.')
|
||||
|
||||
def HL2Library(self, context, compiler, name, sdk):
|
||||
binary = self.Library(context, compiler, name)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
@@ -653,13 +539,15 @@ class SMConfig(object):
|
||||
|
||||
def HL2Config(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
|
||||
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||
self.AddCxxCompat(binary)
|
||||
self.AddVersioning(binary)
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2ExtConfig(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
|
||||
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||
self.AddCxxCompat(binary)
|
||||
self.AddVersioning(binary)
|
||||
self.ConfigureForHL2(context, binary, sdk)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
@@ -692,7 +580,19 @@ if SM.use_auto_versioning():
|
||||
{ 'SM': SM }
|
||||
)
|
||||
|
||||
class SafetyHookShim(object):
|
||||
def __init__(self):
|
||||
self.all_targets = {}
|
||||
self.libsafetyhook = {}
|
||||
|
||||
SafetyHook = SafetyHookShim()
|
||||
SafetyHook.all_targets = SM.all_targets
|
||||
builder.Build('public/safetyhook/AMBuilder', {'SafetyHook': SafetyHook })
|
||||
SM.libsafetyhook = SafetyHook.libsafetyhook
|
||||
|
||||
class SPRoot(object):
|
||||
def __init__(self):
|
||||
self.generated_headers = SM.generated_headers
|
||||
# SourcePawn's build scripts are always one-offs, and attach the current target
|
||||
# to the builder, so we have to provide a shim to our StaticLibrary() method.
|
||||
def StaticLibrary(self, builder, name):
|
||||
@@ -720,11 +620,24 @@ SP = builder.Build('sourcepawn/AMBuildScript', {
|
||||
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||
'external_build': SP_build_parts,
|
||||
})
|
||||
if len(SP.spcomp) > 1:
|
||||
SM.spcomp = SP.spcomp['x86']
|
||||
else:
|
||||
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
|
||||
SM.spcomp_bins = list(SP.spcomp.values())
|
||||
|
||||
def IsBetterDefaultSpcomp(spcomp, other):
|
||||
if other is None:
|
||||
return True
|
||||
if spcomp.target.arch == 'universal':
|
||||
return True
|
||||
if other.target.arch == 'universal':
|
||||
return False
|
||||
return spcomp.target.arch == 'x86'
|
||||
|
||||
for spcomp in SP.spcomp:
|
||||
if IsBetterDefaultSpcomp(spcomp, SM.spcomp):
|
||||
SM.spcomp = spcomp
|
||||
SM.spcomp_bins.append(spcomp)
|
||||
|
||||
# If we have a universal binary, ignore all other spcomps.
|
||||
if SM.spcomp.target.arch == 'universal':
|
||||
SM.spcomp_bins = [SM.spcomp]
|
||||
|
||||
if not getattr(builder.options, 'scripting_only', False):
|
||||
for cxx in SM.all_targets:
|
||||
@@ -746,6 +659,7 @@ else:
|
||||
'extensions/clientprefs/AMBuilder',
|
||||
'extensions/curl/AMBuilder',
|
||||
'extensions/cstrike/AMBuilder',
|
||||
'extensions/dhooks/AMBuilder',
|
||||
'extensions/geoip/AMBuilder',
|
||||
'extensions/mysql/AMBuilder',
|
||||
'extensions/pgsql/AMBuilder',
|
||||
|
||||
@@ -16,6 +16,7 @@ Development
|
||||
- [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
|
||||
-------
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ 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 ..
|
||||
@@ -12,5 +13,5 @@ build_script:
|
||||
- cmd: call "%VS140COMNTOOLS%/vsvars32.bat"
|
||||
- cmd: mkdir build
|
||||
- cmd: cd build
|
||||
- cmd: c:\python27\python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
|
||||
- cmd: python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
|
||||
- cmd: ambuild
|
||||
|
||||
@@ -86,9 +86,6 @@ public:
|
||||
const char *gamesuffix;
|
||||
/* Data */
|
||||
ServerGlobals *serverGlobals;
|
||||
void * serverFactory;
|
||||
void * engineFactory;
|
||||
void * matchmakingDSFactory;
|
||||
SMGlobalClass * listeners;
|
||||
|
||||
// ConVar functions.
|
||||
@@ -115,6 +112,8 @@ public:
|
||||
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;
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
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;
|
||||
@@ -56,6 +57,7 @@ public:
|
||||
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
|
||||
|
||||
@@ -73,6 +73,9 @@ struct sm_logic_t
|
||||
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;
|
||||
|
||||
@@ -53,24 +53,6 @@
|
||||
* 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
|
||||
|
||||
+35
-1
@@ -1,4 +1,38 @@
|
||||
"Languages"
|
||||
{
|
||||
"en" "English"
|
||||
"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)
|
||||
|
||||
}
|
||||
|
||||
+19
-17
@@ -1,30 +1,30 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
try:
|
||||
from ambuild2 import run, util
|
||||
from ambuild2 import run, util
|
||||
except:
|
||||
try:
|
||||
import ambuild
|
||||
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
|
||||
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
|
||||
except:
|
||||
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
||||
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
||||
sys.exit(1)
|
||||
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)
|
||||
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')
|
||||
help='Root search folder for HL2SDKs')
|
||||
parser.options.add_argument('--mysql-path', type=str, dest='mysql_path', default=None,
|
||||
help='Path to MySQL 5')
|
||||
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')
|
||||
help='Path to 64-bit MySQL 5')
|
||||
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||
help='Path to Metamod:Source')
|
||||
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
@@ -37,11 +37,13 @@ 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')
|
||||
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).")
|
||||
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.")
|
||||
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()
|
||||
|
||||
+114
-140
@@ -4,164 +4,138 @@ import os
|
||||
project = builder.LibraryProject('sourcemod')
|
||||
|
||||
project.sources += [
|
||||
'MenuStyle_Valve.cpp',
|
||||
'logic_bridge.cpp',
|
||||
'smn_entities.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'smn_events.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'ChatTriggers.cpp',
|
||||
'smn_player.cpp',
|
||||
'sourcemod.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'NextMap.cpp',
|
||||
'ConCmdManager.cpp',
|
||||
'ConVarManager.cpp',
|
||||
'ConsoleDetours.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'EventManager.cpp',
|
||||
'GameHooks.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'Logger.cpp',
|
||||
'MenuManager.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'MenuStyle_Valve.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'NextMap.cpp',
|
||||
'PlayerManager.cpp',
|
||||
'TimerSys.cpp',
|
||||
'UserMessages.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'logic_bridge.cpp',
|
||||
'pb_handle.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'smn_commandline.cpp',
|
||||
'smn_console.cpp',
|
||||
'smn_entities.cpp',
|
||||
'smn_events.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'Logger.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'smn_console.cpp',
|
||||
'UserMessages.cpp',
|
||||
'MenuManager.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'smn_player.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_vector.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'sourcemod.cpp',
|
||||
'EventManager.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'ConsoleDetours.cpp',
|
||||
'smn_commandline.cpp',
|
||||
'GameHooks.cpp',
|
||||
]
|
||||
|
||||
for sdk_name in SM.sdks:
|
||||
sdk = SM.sdks[sdk_name]
|
||||
for cxx in builder.targets:
|
||||
if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]:
|
||||
continue
|
||||
# SDK name to shipping gamedir
|
||||
pb_gamedir_map = {
|
||||
'csgo': 'csgo',
|
||||
'blade': 'berimbau',
|
||||
'mcv': 'vietnam',
|
||||
}
|
||||
|
||||
binary_name = 'sourcemod.' + sdk.ext
|
||||
# SDK name to source code gamedir
|
||||
pb_gamesrcdir_map = {
|
||||
'csgo': 'cstrike15',
|
||||
'blade': 'berimbau',
|
||||
'mcv': 'vietnam',
|
||||
}
|
||||
|
||||
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
|
||||
SM.ConfigureForExtension(builder, binary.compiler)
|
||||
for sdk_target in SM.sdk_targets:
|
||||
sdk = sdk_target.sdk
|
||||
cxx = sdk_target.cxx
|
||||
|
||||
compiler = binary.compiler
|
||||
binary_name = 'sourcemod.' + sdk['extension']
|
||||
needs_protobuf = sdk['name'] in ['csgo', 'blade', 'mcv']
|
||||
|
||||
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
|
||||
SM.ConfigureForExtension(builder, binary.compiler)
|
||||
|
||||
compiler = binary.compiler
|
||||
compiler.cxxincludes += [
|
||||
builder.sourcePath
|
||||
]
|
||||
|
||||
if needs_protobuf:
|
||||
compiler.cxxincludes += [
|
||||
builder.sourcePath
|
||||
os.path.join(sdk['path'], 'common', 'protobuf-2.5.0', 'src'),
|
||||
os.path.join(sdk['path'], 'public', 'engine', 'protobuf'),
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf')
|
||||
]
|
||||
|
||||
if compiler.like('msvc'):
|
||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||
if cxx.target.platform == 'linux':
|
||||
compiler.postlink += ['-lpthread', '-lrt']
|
||||
|
||||
if needs_protobuf:
|
||||
if compiler.target.platform == 'linux':
|
||||
if compiler.target.arch == 'x86':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'linux32', 'release', 'libprotobuf.a')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'linux64', 'release', 'libprotobuf.a')
|
||||
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
||||
elif compiler.target.platform == 'mac':
|
||||
if compiler.target.arch == 'x86':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_path = os.path.join(sdk['path'], 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||
elif compiler.target.platform == 'windows':
|
||||
msvc_ver = compiler.version
|
||||
vs_year = ''
|
||||
platform = ''
|
||||
if compiler.target.arch == 'x86':
|
||||
platform = 'win32'
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
platform = 'win64'
|
||||
|
||||
if 1900 <= msvc_ver < 2000:
|
||||
vs_year = '2015'
|
||||
else:
|
||||
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
||||
|
||||
if 'DEBUG' in compiler.defines:
|
||||
lib_path = os.path.join(sdk['path'], 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
else:
|
||||
lib_path = os.path.join(sdk['path'], 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
compiler.linkflags.insert(0, lib_path)
|
||||
|
||||
if needs_protobuf:
|
||||
binary.sources += ['smn_protobuf.cpp']
|
||||
else:
|
||||
binary.sources += ['smn_bitbuffer.cpp']
|
||||
|
||||
if sdk['name'] != 'blade':
|
||||
binary.sources += [
|
||||
'vprof_tool.cpp',
|
||||
]
|
||||
|
||||
pb_includes = []
|
||||
if sdk.name == 'csgo':
|
||||
pb_includes = [
|
||||
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')
|
||||
]
|
||||
elif sdk.name == 'blade':
|
||||
pb_includes = [
|
||||
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', 'berimbau', 'protobuf')
|
||||
]
|
||||
compiler.cxxincludes += pb_includes
|
||||
|
||||
if compiler.like('msvc'):
|
||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||
if cxx.target.platform == 'linux':
|
||||
compiler.postlink += ['-lpthread', '-lrt']
|
||||
|
||||
if sdk.name in ['csgo', 'blade']:
|
||||
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-libcxx.a')
|
||||
elif compiler.target.arch == 'x86_64':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf-libcxx.a')
|
||||
elif compiler.target.platform == 'windows':
|
||||
msvc_ver = compiler.version
|
||||
vs_year = ''
|
||||
if 1900 <= msvc_ver < 2000:
|
||||
vs_year = '2015'
|
||||
else:
|
||||
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
||||
|
||||
if 'DEBUG' in compiler.defines:
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
else:
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||
compiler.linkflags.insert(0, lib_path)
|
||||
|
||||
if sdk.name in ['csgo', 'blade']:
|
||||
binary.sources += ['smn_protobuf.cpp']
|
||||
else:
|
||||
binary.sources += ['smn_bitbuffer.cpp']
|
||||
|
||||
if sdk.name != 'blade':
|
||||
if needs_protobuf:
|
||||
binary.sources += [
|
||||
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessages.pb.cc'),
|
||||
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessage_helpers.cpp'),
|
||||
]
|
||||
if sdk['name'] == 'mcv':
|
||||
binary.sources += [
|
||||
'vprof_tool.cpp',
|
||||
]
|
||||
|
||||
pb_sources = []
|
||||
if sdk.name == 'csgo':
|
||||
pb_sources = [
|
||||
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'),
|
||||
]
|
||||
elif sdk.name == 'blade':
|
||||
pb_sources = [
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessage_helpers.cpp'),
|
||||
]
|
||||
if len(pb_sources):
|
||||
binary.sources += pb_sources
|
||||
binary.compiler.cxxdefines += ['PROTOBUF_ENABLE']
|
||||
|
||||
if cxx.target.platform == 'mac' and sdk.name in ['csgo']:
|
||||
# We need a proxy library since the game uses libstdc++.
|
||||
pb_binary = SM.HL2Library(builder, cxx, 'pbproxy.' + sdk.ext, sdk)
|
||||
pb_binary.sources += pb_sources
|
||||
pb_binary.sources += ['pb_proxy.cpp']
|
||||
pb_binary.compiler.cxxincludes += pb_includes
|
||||
|
||||
# Switch from libc++ to libstdc++.
|
||||
pb_binary.compiler.cxxflags.remove('-stdlib=libc++')
|
||||
pb_binary.compiler.linkflags.remove('-lc++')
|
||||
pb_binary.compiler.linkflags.remove('-stdlib=libc++')
|
||||
pb_binary.compiler.cxxflags.append('-stdlib=libstdc++')
|
||||
pb_binary.compiler.linkflags.append('-lstdc++')
|
||||
pb_binary.compiler.linkflags.append('-stdlib=libstdc++')
|
||||
if '-std=c++1y' in pb_binary.compiler.cxxflags:
|
||||
pb_binary.compiler.cxxflags.remove('-std=c++1y')
|
||||
elif '-std=c++14' in pb_binary.compiler.cxxflags:
|
||||
pb_binary.compiler.cxxflags.remove('-std=c++14')
|
||||
|
||||
if cxx.target.arch == 'x86':
|
||||
pb_lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||
elif cxx.target.arch == 'x86_64':
|
||||
pb_lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||
pb_binary.compiler.linkflags.append(pb_lib_path)
|
||||
|
||||
SM.binaries += [builder.Add(pb_binary)]
|
||||
|
||||
binary.compiler.cxxdefines += [
|
||||
'PROTOBUF_PROXY_ENABLE',
|
||||
'PROTOBUF_PROXY_BINARY_NAME="pbproxy.{}"'.format(sdk.ext),
|
||||
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)
|
||||
|
||||
|
||||
@@ -461,3 +461,23 @@ 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();
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ public:
|
||||
unsigned int SetReplyTo(unsigned int reply);
|
||||
bool IsChatTrigger();
|
||||
bool WasFloodedMessage();
|
||||
const char *GetPublicChatTrigger();
|
||||
const char *GetPrivateChatTrigger();
|
||||
private:
|
||||
enum ChatTriggerType {
|
||||
ChatTrigger_Public,
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla
|
||||
const char *cvarName, const char *cvarValue){
|
||||
int client = IndexOfEdict(pPlayer);
|
||||
|
||||
# if SOURCE_ENGINE == SE_CSGO
|
||||
# if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
|
||||
return;
|
||||
# endif
|
||||
|
||||
+76
-26
@@ -47,6 +47,8 @@
|
||||
#include <cstrike15_usermessages.pb.h>
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
#include <berimbau_usermessages.pb.h>
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
#include <vietnam_usermessages.pb.h>
|
||||
#endif
|
||||
|
||||
typedef ICommandLine *(*FakeGetCommandLine)();
|
||||
@@ -183,7 +185,9 @@ void CHalfLife2::InitLogicalEntData()
|
||||
|| SOURCE_ENGINE == SE_CSS \
|
||||
|| SOURCE_ENGINE == SE_SDK2013 \
|
||||
|| SOURCE_ENGINE == SE_BMS \
|
||||
|| SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
|| SOURCE_ENGINE == SE_BLADE \
|
||||
|| SOURCE_ENGINE == SE_NUCLEARDAWN \
|
||||
|| SOURCE_ENGINE == SE_PVKII
|
||||
|
||||
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
|
||||
{
|
||||
@@ -409,6 +413,17 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
|
||||
return pInfo->sc;
|
||||
}
|
||||
|
||||
ServerClass *CHalfLife2::FindEntityServerClass(CBaseEntity *pEntity)
|
||||
{
|
||||
IServerNetworkable* pNetwork = ((IServerUnknown *)pEntity)->GetNetworkable();
|
||||
if (pNetwork == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pNetwork->GetServerClass();
|
||||
}
|
||||
|
||||
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
|
||||
{
|
||||
DataTableInfo *pInfo = NULL;
|
||||
@@ -441,20 +456,25 @@ bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pInfo->lookup.retrieve(offset, info))
|
||||
{
|
||||
sm_sendprop_info_t temp_info;
|
||||
DataTableInfo::SendPropInfo temp;
|
||||
|
||||
if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
|
||||
if (!pInfo->lookup.retrieve(offset, &temp))
|
||||
{
|
||||
bool found = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp.info, 0);
|
||||
temp.name = offset;
|
||||
|
||||
pInfo->lookup.insert(offset, temp);
|
||||
|
||||
if (found)
|
||||
{
|
||||
return false;
|
||||
*info = temp.info;
|
||||
}
|
||||
|
||||
pInfo->lookup.insert(offset, temp_info);
|
||||
*info = temp_info;
|
||||
return found;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
*info = temp.info;
|
||||
return info->prop != nullptr;
|
||||
}
|
||||
|
||||
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
|
||||
@@ -488,15 +508,25 @@ bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatab
|
||||
m_Maps.add(i, pMap, new DataMapCache());
|
||||
|
||||
DataMapCache *cache = i->value;
|
||||
DataMapCacheInfo temp;
|
||||
|
||||
if (!cache->retrieve(offset, pDataTable))
|
||||
if (!cache->retrieve(offset, &temp))
|
||||
{
|
||||
if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable))
|
||||
return false;
|
||||
cache->insert(offset, *pDataTable);
|
||||
bool found = UTIL_FindDataMapInfo(pMap, offset, &temp.info);
|
||||
temp.name = offset;
|
||||
|
||||
cache->insert(offset, temp);
|
||||
|
||||
if (found)
|
||||
{
|
||||
*pDataTable = temp.info;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
return true;
|
||||
*pDataTable = temp.info;
|
||||
return pDataTable->prop != nullptr;
|
||||
}
|
||||
|
||||
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||
@@ -537,7 +567,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
||||
char buffer[253];
|
||||
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CCSUsrMsg_SayText *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
@@ -564,7 +594,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CCSUsrMsg_TextMsg *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
@@ -601,7 +631,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
{
|
||||
cell_t players[] = {client};
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CCSUsrMsg_HintText *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
@@ -631,7 +661,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
|
||||
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CCSUsrMsg_HintText *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
@@ -666,7 +696,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
||||
int count = 0;
|
||||
cell_t players[] = {client};
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CCSUsrMsg_VGUIMenu *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
@@ -691,7 +721,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
||||
SubKey = data->GetFirstSubKey();
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
pMsg->set_name(name);
|
||||
pMsg->set_show(show);
|
||||
|
||||
@@ -1080,8 +1110,26 @@ int CHalfLife2::ReferenceToIndex(cell_t entRef)
|
||||
|
||||
return hndl.GetEntryIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
CEntInfo *pInfo = LookupEntity(entRef);
|
||||
if (!pInfo)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
IServerUnknown *pUnk = static_cast<IServerUnknown *>(pInfo->m_pEntity);
|
||||
if (!pUnk)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
CBaseEntity *pEntity = pUnk->GetBaseEntity();
|
||||
if (!pEntity)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
return entRef;
|
||||
return entRef;
|
||||
}
|
||||
}
|
||||
|
||||
cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
|
||||
@@ -1233,7 +1281,7 @@ bool IsWindowsReservedDeviceName(const char *pMapname)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
|
||||
// This frees memory allocated by the game using the game's CRT on Windows,
|
||||
// avoiding a crash due to heap corruption (issue #910).
|
||||
template< class T, class I >
|
||||
@@ -1338,7 +1386,7 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
|
||||
}
|
||||
|
||||
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM \
|
||||
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS
|
||||
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_PVKII
|
||||
static IVEngineServer *engine23 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer023", nullptr));
|
||||
if (engine23)
|
||||
{
|
||||
@@ -1384,7 +1432,7 @@ bool CHalfLife2::IsMapValid(const char *map)
|
||||
if (!map || !map[0])
|
||||
return false;
|
||||
|
||||
return FindMap(map) != SMFindMapResult::NotFound;
|
||||
return FindMap(map) == SMFindMapResult::Found;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||
@@ -1525,7 +1573,9 @@ uint64_t CHalfLife2::GetServerSteamId64() const
|
||||
|| SOURCE_ENGINE == SE_DOI \
|
||||
|| SOURCE_ENGINE == SE_SDK2013 \
|
||||
|| SOURCE_ENGINE == SE_ALIENSWARM \
|
||||
|| SOURCE_ENGINE == SE_TF2
|
||||
|| SOURCE_ENGINE == SE_TF2 \
|
||||
|| SOURCE_ENGINE == SE_PVKII \
|
||||
|| SOURCE_ENGINE == SE_MCV
|
||||
const CSteamID *sid = engine->GetGameServerSteamID();
|
||||
if (sid)
|
||||
{
|
||||
|
||||
+27
-10
@@ -74,7 +74,7 @@ using namespace SourceMod;
|
||||
|| 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
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD || SOURCE_ENGINE == SE_PVKII
|
||||
#define SOURCE_BIN_PREFIX "lib"
|
||||
#define SOURCE_BIN_SUFFIX ""
|
||||
#else
|
||||
@@ -89,16 +89,24 @@ using namespace SourceMod;
|
||||
|
||||
struct DataTableInfo
|
||||
{
|
||||
struct SendPropPolicy
|
||||
struct SendPropInfo
|
||||
{
|
||||
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
|
||||
static inline bool matches(const char *name, const SendPropInfo &info)
|
||||
{
|
||||
return strcmp(name, info.prop->GetName()) == 0;
|
||||
return strcmp(name, info.name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
|
||||
SendPropInfo()
|
||||
: name(), info{nullptr, 0}
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
sm_sendprop_info_t info;
|
||||
};
|
||||
|
||||
static inline bool matches(const char *name, const DataTableInfo *info)
|
||||
@@ -116,22 +124,30 @@ struct DataTableInfo
|
||||
}
|
||||
|
||||
ServerClass *sc;
|
||||
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
|
||||
NameHashSet<SendPropInfo> lookup;
|
||||
};
|
||||
|
||||
struct DataMapCachePolicy
|
||||
struct DataMapCacheInfo
|
||||
{
|
||||
static inline bool matches(const char *name, const sm_datatable_info_t &info)
|
||||
static inline bool matches(const char *name, const DataMapCacheInfo &info)
|
||||
{
|
||||
return strcmp(name, info.prop->fieldName) == 0;
|
||||
return strcmp(name, info.name.c_str()) == 0;
|
||||
}
|
||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
|
||||
DataMapCacheInfo()
|
||||
: name(), info{nullptr, 0}
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
sm_datatable_info_t info;
|
||||
};
|
||||
|
||||
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
|
||||
typedef NameHashSet<DataMapCacheInfo> DataMapCache;
|
||||
|
||||
struct DelayedFakeCliCmd
|
||||
{
|
||||
@@ -205,6 +221,7 @@ public: //IGameHelpers
|
||||
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);
|
||||
@@ -235,7 +252,7 @@ public: //IGameHelpers
|
||||
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
|
||||
#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);
|
||||
|
||||
+29
-26
@@ -38,6 +38,7 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "sourcemm_api.h"
|
||||
#include "logic_bridge.h"
|
||||
|
||||
@@ -68,6 +69,29 @@ 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);
|
||||
@@ -699,30 +723,9 @@ bool MenuManager::MenuSoundsEnabled()
|
||||
return (sm_menu_sounds.GetInt() != 0);
|
||||
}
|
||||
|
||||
ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
size_t maxlength)
|
||||
std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
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;
|
||||
std::string *sound = nullptr;
|
||||
|
||||
switch (sel)
|
||||
{
|
||||
@@ -732,7 +735,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_SelectSound.size() > 0)
|
||||
{
|
||||
sound = m_SelectSound.c_str();
|
||||
sound = &m_SelectSound;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -740,7 +743,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitBackSound.size() > 0)
|
||||
{
|
||||
sound = m_ExitBackSound.c_str();
|
||||
sound = &m_ExitBackSound;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -748,7 +751,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitSound.size() > 0)
|
||||
{
|
||||
sound = m_ExitSound.c_str();
|
||||
sound = &m_ExitSound;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+6
-10
@@ -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,12 +55,8 @@ 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()
|
||||
@@ -99,7 +95,7 @@ public:
|
||||
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
|
||||
public:
|
||||
bool MenuSoundsEnabled();
|
||||
const char *GetMenuSound(ItemSelection sel);
|
||||
std::string *GetMenuSound(ItemSelection sel);
|
||||
protected:
|
||||
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
|
||||
Handle_t CreateStyleHandle(IMenuStyle *style);
|
||||
@@ -109,9 +105,9 @@ private:
|
||||
CVector<IMenuStyle *> m_Styles;
|
||||
HandleType_t m_StyleType;
|
||||
HandleType_t m_MenuType;
|
||||
String m_SelectSound;
|
||||
String m_ExitBackSound;
|
||||
String m_ExitSound;
|
||||
std::string m_SelectSound = "";
|
||||
std::string m_ExitBackSound = "";
|
||||
std::string m_ExitSound = "";
|
||||
};
|
||||
|
||||
extern MenuManager g_Menus;
|
||||
|
||||
+77
-21
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ void BaseMenuStyle::ProcessWatchList()
|
||||
}
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
|
||||
logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
|
||||
m_WatchList.m_Size,
|
||||
m_WatchList.m_FirstLink,
|
||||
m_WatchList.m_FreeNodes,
|
||||
@@ -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);
|
||||
|
||||
const char *sound = g_Menus.GetMenuSound(type);
|
||||
std::string *sound = g_Menus.GetMenuSound(type);
|
||||
|
||||
if (sound != NULL)
|
||||
if (nullptr != sound && !sound->empty())
|
||||
{
|
||||
edict_t *pEdict = PEntityOfEntIndex(client);
|
||||
if (pEdict)
|
||||
@@ -323,23 +323,23 @@ 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,
|
||||
-1,
|
||||
sound->c_str(),
|
||||
-1,
|
||||
#endif
|
||||
sound,
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
sound->c_str(),
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
0,
|
||||
0,
|
||||
#endif
|
||||
0,
|
||||
PITCH_NORM,
|
||||
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_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
|
||||
0,
|
||||
#endif
|
||||
&pos);
|
||||
@@ -604,9 +604,9 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||
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)
|
||||
{
|
||||
}
|
||||
@@ -754,6 +754,62 @@ unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetItemCount()
|
||||
{
|
||||
return m_items.size();
|
||||
|
||||
@@ -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
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
|
||||
class CBaseMenu;
|
||||
|
||||
class BaseMenuStyle :
|
||||
class BaseMenuStyle :
|
||||
public IMenuStyle,
|
||||
public IClientListener
|
||||
{
|
||||
@@ -113,11 +113,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);
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#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[];
|
||||
@@ -182,7 +184,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
|
||||
{
|
||||
int count = pFilter->GetRecipientCount();
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||
#else
|
||||
bf_read br(bf->GetBasePointer(), 3);
|
||||
@@ -500,9 +502,13 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
// TODO: find what happens past 240 on CS:GO
|
||||
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
if (!msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
msg->set_bits_valid_slots(display_keys);
|
||||
msg->set_display_time(time);
|
||||
msg->set_menu_string(ptr);
|
||||
|
||||
@@ -40,6 +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"
|
||||
|
||||
+20
-1
@@ -109,6 +109,8 @@ 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
|
||||
@@ -122,8 +124,16 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
|
||||
}
|
||||
|
||||
const char *newmap = sm_nextmap.GetString();
|
||||
if (newmap[0] != '\0') {
|
||||
ke::SafeStrcpy(g_nextMap, sizeof(g_nextMap), newmap);
|
||||
newmap = g_nextMap;
|
||||
|
||||
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
|
||||
// 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))
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
@@ -142,6 +152,15 @@ 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)
|
||||
{
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public:
|
||||
|
||||
private:
|
||||
MapChangeData m_tempChangeInfo;
|
||||
char lastMap[32];
|
||||
char lastMap[PLATFORM_MAX_PATH];
|
||||
};
|
||||
|
||||
extern NextMapManager g_NextMap;
|
||||
|
||||
+128
-119
@@ -59,6 +59,8 @@ bool g_OnMapStarted = false;
|
||||
IForward *PreAdminCheck = NULL;
|
||||
IForward *PostAdminCheck = NULL;
|
||||
IForward *PostAdminFilter = NULL;
|
||||
IForward *ServerEnterHibernation = NULL;
|
||||
IForward *ServerExitHibernation = NULL;
|
||||
|
||||
const unsigned int *g_NumPlayersToAuth = NULL;
|
||||
int lifestate_offset = -1;
|
||||
@@ -196,12 +198,15 @@ void PlayerManager::OnSourceModAllInitialized()
|
||||
m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
|
||||
m_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
|
||||
m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
|
||||
m_cllang = forwardsys->CreateForward("OnClientLanguageChanged", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
|
||||
m_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
|
||||
m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL);
|
||||
|
||||
PreAdminCheck = forwardsys->CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
|
||||
PostAdminCheck = forwardsys->CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
|
||||
PostAdminFilter = forwardsys->CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
|
||||
ServerEnterHibernation = forwardsys->CreateForward("OnServerEnterHibernation", ET_Ignore, 0, NULL);
|
||||
ServerExitHibernation = forwardsys->CreateForward("OnServerExitHibernation", ET_Ignore, 0, NULL);
|
||||
|
||||
m_bIsListenServer = !engine->IsDedicatedServer();
|
||||
m_ListenClient = 0;
|
||||
@@ -212,6 +217,9 @@ void PlayerManager::OnSourceModAllInitialized()
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdMaxplayersCallback), true);
|
||||
maxplayersCmd = pCmd;
|
||||
}
|
||||
|
||||
gameevents->AddListener(this, "player_connect", true);
|
||||
gameevents->AddListener(this, "player_disconnect", true);
|
||||
}
|
||||
|
||||
void PlayerManager::OnSourceModShutdown()
|
||||
@@ -246,12 +254,15 @@ void PlayerManager::OnSourceModShutdown()
|
||||
forwardsys->ReleaseForward(m_clcommandkv_post);
|
||||
forwardsys->ReleaseForward(m_clinfochanged);
|
||||
forwardsys->ReleaseForward(m_clauth);
|
||||
forwardsys->ReleaseForward(m_cllang);
|
||||
forwardsys->ReleaseForward(m_onActivate);
|
||||
forwardsys->ReleaseForward(m_onActivate2);
|
||||
|
||||
forwardsys->ReleaseForward(PreAdminCheck);
|
||||
forwardsys->ReleaseForward(PostAdminCheck);
|
||||
forwardsys->ReleaseForward(PostAdminFilter);
|
||||
forwardsys->ReleaseForward(ServerEnterHibernation);
|
||||
forwardsys->ReleaseForward(ServerExitHibernation);
|
||||
|
||||
delete [] m_Players;
|
||||
|
||||
@@ -259,6 +270,8 @@ void PlayerManager::OnSourceModShutdown()
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, maxplayersCmd, SH_STATIC(CmdMaxplayersCallback), true);
|
||||
}
|
||||
|
||||
gameevents->RemoveListener(this);
|
||||
}
|
||||
|
||||
ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
|
||||
@@ -512,7 +525,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
||||
/* Get the client's language */
|
||||
if (m_QueryLang)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
pPlayer->m_LangId = translator->GetServerLanguage();
|
||||
#else
|
||||
const char *name;
|
||||
@@ -520,10 +533,13 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
||||
{
|
||||
unsigned int langid;
|
||||
pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage();
|
||||
|
||||
OnClientLanguageChanged(client, pPlayer->m_LangId);
|
||||
} else {
|
||||
pPlayer->m_LangId = translator->GetServerLanguage();
|
||||
}
|
||||
#endif
|
||||
pPlayer->m_OriginalLangId = pPlayer->m_LangId;
|
||||
}
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
@@ -641,7 +657,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
|
||||
int userId = engine->GetPlayerUserId(pEntity);
|
||||
#if (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_PVKII)
|
||||
static ConVar *tv_name = icvar->FindVar("tv_name");
|
||||
#endif
|
||||
#if SOURCE_ENGINE == SE_TF2
|
||||
@@ -664,10 +680,13 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
&& ((!m_bIsReplayActive && newCount == 1)
|
||||
|| (m_bIsReplayActive && newCount == 2))
|
||||
&& (m_SourceTVUserId == userId
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_MCV
|
||||
// It seems likely that MCV will change this at some point, but it's GOTV at the moment.
|
||||
|| strcmp(playername, "GOTV") == 0
|
||||
#elif SOURCE_ENGINE == SE_BLADE
|
||||
|| strcmp(playername, "BBTV") == 0
|
||||
#elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_PVKII)
|
||||
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
|
||||
#else
|
||||
|| strcmp(playername, "SourceTV") == 0
|
||||
@@ -721,7 +740,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
}
|
||||
pPlayer->Authorize_Post();
|
||||
}
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
else if(m_QueryLang)
|
||||
{
|
||||
// Not a bot
|
||||
@@ -770,6 +789,11 @@ void PlayerManager::OnSourceModLevelEnd()
|
||||
|
||||
void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
|
||||
{
|
||||
cell_t res;
|
||||
if (bHibernating)
|
||||
ServerEnterHibernation->Execute(&res);
|
||||
else
|
||||
ServerExitHibernation->Execute(&res);
|
||||
/* If bots were added at map start, but not fully inited before hibernation, there will
|
||||
* be no OnClientDisconnect for them, despite them getting booted right before this.
|
||||
*/
|
||||
@@ -781,7 +805,7 @@ void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
|
||||
CPlayer *pPlayer = &m_Players[i];
|
||||
if (pPlayer->IsConnected() && pPlayer->IsFakeClient())
|
||||
{
|
||||
#if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE >= SE_CSGO || SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
#if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_MCV
|
||||
// These games have the bug fixed where hltv/replay was getting kicked on hibernation
|
||||
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
|
||||
continue;
|
||||
@@ -967,8 +991,6 @@ void ClientConsolePrint(edict_t *e, const char *fmt, ...)
|
||||
void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
||||
{
|
||||
char buffer[256];
|
||||
unsigned int id = 0;
|
||||
unsigned int start = 0;
|
||||
|
||||
AutoExtensionList extensions(extsys);
|
||||
if (!extensions->size())
|
||||
@@ -977,11 +999,6 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ArgC() > 2)
|
||||
{
|
||||
start = atoi(args.Arg(2));
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < extensions->size(); i++)
|
||||
{
|
||||
@@ -993,17 +1010,6 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
||||
continue;
|
||||
}
|
||||
|
||||
id++;
|
||||
if (id < start)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id - start > 10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
IExtensionInterface *api = ext->GetAPI();
|
||||
|
||||
const char *name = api->GetExtensionName();
|
||||
@@ -1028,31 +1034,14 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
||||
len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, ": %s", description);
|
||||
}
|
||||
|
||||
|
||||
ClientConsolePrint(player->GetEdict(), "%s", buffer);
|
||||
}
|
||||
|
||||
for (; i < extensions->size(); i++)
|
||||
{
|
||||
char error[255];
|
||||
if (extensions->at(i)->IsRunning(error, sizeof(error)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < extensions->size())
|
||||
{
|
||||
ClientConsolePrint(player->GetEdict(), "To see more, type \"sm exts %d\"", id);
|
||||
}
|
||||
}
|
||||
|
||||
void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
||||
{
|
||||
char buffer[256];
|
||||
unsigned int id = 0;
|
||||
edict_t *e = player->GetEdict();
|
||||
unsigned int start = 0;
|
||||
|
||||
AutoPluginList plugins(scripts);
|
||||
if (!plugins->size())
|
||||
@@ -1061,11 +1050,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ArgC() > 2)
|
||||
{
|
||||
start = atoi(args.Arg(2));
|
||||
}
|
||||
|
||||
SourceHook::List<SMPlugin *> m_FailList;
|
||||
|
||||
size_t i = 0;
|
||||
@@ -1078,18 +1062,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Count valid plugins */
|
||||
id++;
|
||||
if (id < start)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id - start > 10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
const sm_plugininfo_t *info = pl->GetPublicInfo();
|
||||
len = ke::SafeSprintf(buffer, sizeof(buffer), " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
|
||||
@@ -1107,21 +1079,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
||||
}
|
||||
ClientConsolePrint(e, "%s", buffer);
|
||||
}
|
||||
|
||||
/* See if we can get more plugins */
|
||||
for (; i < plugins->size(); i++)
|
||||
{
|
||||
if (plugins->at(i)->GetStatus() == Plugin_Running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we actually have more plugins? */
|
||||
if (i < plugins->size())
|
||||
{
|
||||
ClientConsolePrint(e, "To see more, type \"sm plugins %d\"", id);
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
@@ -1207,7 +1164,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
||||
if (g_ConsoleDetours.IsEnabled())
|
||||
{
|
||||
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, &cargs);
|
||||
if (res2 >= Pl_Stop)
|
||||
if (res2 >= Pl_Handled)
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
@@ -1337,65 +1294,69 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
||||
m_clinfochanged->PushCell(client);
|
||||
m_clinfochanged->Execute(&res, NULL);
|
||||
|
||||
if (pPlayer->IsFakeClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IPlayerInfo *info = pPlayer->GetPlayerInfo();
|
||||
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
|
||||
const char *old_name = pPlayer->m_Name.c_str();
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
const char *networkid_force;
|
||||
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
|
||||
{
|
||||
unsigned int accountId = pPlayer->GetSteamAccountID();
|
||||
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
|
||||
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
|
||||
|
||||
pPlayer->Kick("NetworkID spoofing detected.");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcmp(old_name, new_name) != 0)
|
||||
{
|
||||
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
|
||||
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
||||
if (!pPlayer->IsFakeClient())
|
||||
{
|
||||
if (!CheckSetAdminName(client, pPlayer, id))
|
||||
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
|
||||
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
||||
{
|
||||
char kickMsg[128];
|
||||
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
|
||||
pPlayer->Kick(kickMsg);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
if (!CheckSetAdminName(client, pPlayer, id))
|
||||
{
|
||||
char kickMsg[128];
|
||||
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
|
||||
pPlayer->Kick(kickMsg);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
}
|
||||
} else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
|
||||
if (id == pPlayer->GetAdminId())
|
||||
{
|
||||
/* This player is changing their name; force them to drop admin privileges! */
|
||||
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
||||
else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
|
||||
if (id == pPlayer->GetAdminId())
|
||||
{
|
||||
/* This player is changing their name; force them to drop admin privileges! */
|
||||
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pPlayer->SetName(new_name);
|
||||
}
|
||||
|
||||
if (m_PassInfoVar.size() > 0)
|
||||
if (!pPlayer->IsFakeClient())
|
||||
{
|
||||
/* Try for a password change */
|
||||
const char *old_pass = pPlayer->m_LastPassword.c_str();
|
||||
const char *new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
|
||||
if (strcmp(old_pass, new_pass) != 0)
|
||||
if (m_PassInfoVar.size() > 0)
|
||||
{
|
||||
pPlayer->m_LastPassword.assign(new_pass);
|
||||
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
|
||||
/* Try for a password change */
|
||||
const char* old_pass = pPlayer->m_LastPassword.c_str();
|
||||
const char* new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
|
||||
if (strcmp(old_pass, new_pass) != 0)
|
||||
{
|
||||
/* If there is already an admin id assigned, this will just bail out. */
|
||||
pPlayer->DoBasicAdminChecks();
|
||||
pPlayer->m_LastPassword.assign(new_pass);
|
||||
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
|
||||
{
|
||||
/* If there is already an admin id assigned, this will just bail out. */
|
||||
pPlayer->DoBasicAdminChecks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
const char* networkid_force;
|
||||
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
|
||||
{
|
||||
unsigned int accountId = pPlayer->GetSteamAccountID();
|
||||
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
|
||||
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
|
||||
|
||||
pPlayer->Kick("NetworkID spoofing detected.");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Notify Extensions */
|
||||
List<IClientListener *>::iterator iter;
|
||||
IClientListener *pListener = NULL;
|
||||
@@ -1409,6 +1370,13 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::OnClientLanguageChanged(int client, unsigned int language)
|
||||
{
|
||||
m_cllang->PushCell(client);
|
||||
m_cllang->PushCell(language);
|
||||
m_cllang->Execute(NULL);
|
||||
}
|
||||
|
||||
int PlayerManager::GetMaxClients()
|
||||
{
|
||||
return m_maxClients;
|
||||
@@ -1428,6 +1396,11 @@ int PlayerManager::GetNumPlayers()
|
||||
return m_PlayerCount;
|
||||
}
|
||||
|
||||
int PlayerManager::GetNumClients()
|
||||
{
|
||||
return m_ClientCount;
|
||||
}
|
||||
|
||||
int PlayerManager::GetClientOfUserId(int userid)
|
||||
{
|
||||
if (userid < 0 || userid > USHRT_MAX)
|
||||
@@ -2008,7 +1981,7 @@ void CmdMaxplayersCallback()
|
||||
g_Players.MaxPlayersChanged();
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||
{
|
||||
for (int i = 1; i <= m_maxClients; i++)
|
||||
@@ -2016,7 +1989,10 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
|
||||
if (m_Players[i].m_LanguageCookie == cookie)
|
||||
{
|
||||
unsigned int langid;
|
||||
m_Players[i].m_LangId = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
|
||||
unsigned int new_langid = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
|
||||
m_Players[i].m_LangId = new_langid;
|
||||
m_Players[i].m_OriginalLangId = new_langid;
|
||||
OnClientLanguageChanged(i, new_langid);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2026,6 +2002,27 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
|
||||
}
|
||||
#endif
|
||||
|
||||
/* IGameEventListener2::FireGameEvent */
|
||||
void PlayerManager::FireGameEvent(IGameEvent *pEvent)
|
||||
{
|
||||
const char *name = pEvent->GetName();
|
||||
|
||||
if (strcmp(name, "player_connect") == 0)
|
||||
{
|
||||
const int client = pEvent->GetInt("index") + 1;
|
||||
const int userid = pEvent->GetInt("userid");
|
||||
|
||||
m_ClientCount++;
|
||||
}
|
||||
else if (strcmp(name, "player_disconnect") == 0)
|
||||
{
|
||||
const int userid = pEvent->GetInt("userid");
|
||||
const int client = m_UserIdLookUp[userid];
|
||||
|
||||
m_ClientCount--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************
|
||||
*** PLAYER CODE ***
|
||||
@@ -2044,6 +2041,7 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|
||||
m_pEdict = pEntity;
|
||||
m_iIndex = IndexOfEdict(pEntity);
|
||||
m_LangId = translator->GetServerLanguage();
|
||||
m_OriginalLangId = m_LangId;
|
||||
|
||||
m_Serial.bits.index = m_iIndex;
|
||||
m_Serial.bits.serial = g_PlayerSerialCount++;
|
||||
@@ -2064,7 +2062,9 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|
||||
|| SOURCE_ENGINE == SE_HL2DM \
|
||||
|| SOURCE_ENGINE == SE_BMS \
|
||||
|| SOURCE_ENGINE == SE_INSURGENCY \
|
||||
|| SOURCE_ENGINE == SE_DOI
|
||||
|| SOURCE_ENGINE == SE_DOI \
|
||||
|| SOURCE_ENGINE == SE_BLADE \
|
||||
|| SOURCE_ENGINE == SE_PVKII
|
||||
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
|
||||
#else
|
||||
#if SOURCE_ENGINE == SE_SDK2013
|
||||
@@ -2240,7 +2240,7 @@ void CPlayer::Disconnect()
|
||||
m_bIsSourceTV = false;
|
||||
m_bIsReplay = false;
|
||||
m_Serial.value = -1;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
m_LanguageCookie = InvalidQueryCvarCookie;
|
||||
#endif
|
||||
ClearNetchannelQueue();
|
||||
@@ -2462,7 +2462,7 @@ void CPlayer::Kick(const char *str)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
pClient->Disconnect(str);
|
||||
#else
|
||||
pClient->Disconnect("%s", str);
|
||||
@@ -2609,9 +2609,18 @@ unsigned int CPlayer::GetLanguageId()
|
||||
return m_LangId;
|
||||
}
|
||||
|
||||
unsigned int CPlayer::GetOriginalLanguageId()
|
||||
{
|
||||
return m_OriginalLangId;
|
||||
}
|
||||
|
||||
void CPlayer::SetLanguageId(unsigned int id)
|
||||
{
|
||||
m_LangId = id;
|
||||
if(m_LangId != id)
|
||||
{
|
||||
m_LangId = id;
|
||||
g_Players.OnClientLanguageChanged(m_iIndex, id);
|
||||
}
|
||||
}
|
||||
|
||||
int CPlayer::GetUserId()
|
||||
|
||||
+12
-3
@@ -96,6 +96,7 @@ public:
|
||||
bool IsInKickQueue();
|
||||
IPlayerInfo *GetPlayerInfo();
|
||||
unsigned int GetLanguageId();
|
||||
unsigned int GetOriginalLanguageId();
|
||||
void SetLanguageId(unsigned int id);
|
||||
int GetUserId();
|
||||
bool RunAdminCacheChecks();
|
||||
@@ -145,13 +146,14 @@ private:
|
||||
bool m_bAdminCheckSignalled = false;
|
||||
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;
|
||||
serial_t m_Serial;
|
||||
CSteamID m_SteamId;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
||||
#endif
|
||||
std::deque<std::string> m_PrintfBuffer;
|
||||
@@ -159,7 +161,8 @@ private:
|
||||
|
||||
class PlayerManager :
|
||||
public SMGlobalClass,
|
||||
public IPlayerManager
|
||||
public IPlayerManager,
|
||||
public IGameEventListener2
|
||||
{
|
||||
friend class CPlayer;
|
||||
public:
|
||||
@@ -192,6 +195,7 @@ public:
|
||||
#endif
|
||||
void OnClientSettingsChanged(edict_t *pEntity);
|
||||
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
||||
void OnClientLanguageChanged(int client, unsigned int language);
|
||||
void OnServerHibernationUpdate(bool bHibernating);
|
||||
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
||||
void OnPrintfFrameAction(unsigned int serial);
|
||||
@@ -202,6 +206,7 @@ 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);
|
||||
@@ -212,6 +217,8 @@ public: //IPlayerManager
|
||||
int GetClientFromSerial(unsigned int serial);
|
||||
void ClearAdminId(AdminId id);
|
||||
void RecheckAnyAdmins();
|
||||
public: // IGameEventListener2
|
||||
void FireGameEvent(IGameEvent *pEvent);
|
||||
public:
|
||||
inline int MaxClients()
|
||||
{
|
||||
@@ -235,7 +242,7 @@ public:
|
||||
{
|
||||
return m_bInCCKVHook;
|
||||
}
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#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);
|
||||
#endif
|
||||
private:
|
||||
@@ -253,6 +260,7 @@ private:
|
||||
IForward *m_clcommandkv_post;
|
||||
IForward *m_clinfochanged;
|
||||
IForward *m_clauth;
|
||||
IForward *m_cllang;
|
||||
IForward *m_onActivate;
|
||||
IForward *m_onActivate2;
|
||||
CPlayer *m_Players;
|
||||
@@ -272,6 +280,7 @@ private:
|
||||
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
|
||||
|
||||
+19
-28
@@ -35,7 +35,6 @@
|
||||
#include "frame_hooks.h"
|
||||
#include "ConVarManager.h"
|
||||
#include "logic_bridge.h"
|
||||
#include <bridge/include/IProviderCallbacks.h>
|
||||
|
||||
#define TIMER_MIN_ACCURACY 0.1
|
||||
|
||||
@@ -171,8 +170,9 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec,
|
||||
TimerSystem::TimerSystem()
|
||||
{
|
||||
m_pMapTimer = NULL;
|
||||
m_bHasMapTickedYet = false;
|
||||
m_bHasMapSimulatedYet = false;
|
||||
m_fLastTickedTime = 0.0f;
|
||||
OnSourceModLevelEnd();
|
||||
}
|
||||
|
||||
TimerSystem::~TimerSystem()
|
||||
@@ -213,28 +213,29 @@ void TimerSystem::OnSourceModLevelEnd()
|
||||
{
|
||||
m_bHasMapTickedYet = false;
|
||||
m_bHasMapSimulatedYet = false;
|
||||
m_bWasSimulating = false;
|
||||
m_uFramesAhead = 0;
|
||||
}
|
||||
|
||||
/* Think is called before gpGlobals is updated every frame, even if the server is hibernating */
|
||||
void TimerSystem::Think(bool unused)
|
||||
void TimerSystem::GameFrame(bool simulating)
|
||||
{
|
||||
m_uFramesAhead++;
|
||||
bool simulating = m_bWasSimulating && m_uFramesAhead == 1;
|
||||
|
||||
if (m_bHasMapTickedYet) {
|
||||
g_fUniversalTime += gpGlobals->realtime - m_fLastTickedTime;
|
||||
} else {
|
||||
if (simulating && m_bHasMapTickedYet)
|
||||
{
|
||||
g_fUniversalTime += gpGlobals->curtime - m_fLastTickedTime;
|
||||
if (!m_bHasMapSimulatedYet)
|
||||
{
|
||||
m_bHasMapSimulatedYet = true;
|
||||
MapTimeLeftChanged();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fUniversalTime += gpGlobals->interval_per_tick;
|
||||
}
|
||||
|
||||
m_fLastTickedTime = gpGlobals->realtime;
|
||||
m_fLastTickedTime = gpGlobals->curtime;
|
||||
m_bHasMapTickedYet = true;
|
||||
|
||||
logicore.callbacks->OnThink(simulating);
|
||||
|
||||
if (g_fUniversalTime >= g_fTimerThink) {
|
||||
if (g_fUniversalTime >= g_fTimerThink)
|
||||
{
|
||||
RunFrame();
|
||||
|
||||
g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY);
|
||||
@@ -242,19 +243,9 @@ void TimerSystem::Think(bool unused)
|
||||
|
||||
RunFrameHooks(simulating);
|
||||
|
||||
m_pOnGameFrame->Execute();
|
||||
}
|
||||
|
||||
/* GameFrame is called after gpGlobals is updated, and may not be called when the server is hibernating */
|
||||
void TimerSystem::GameFrame(bool simulating)
|
||||
{
|
||||
m_bWasSimulating = simulating;
|
||||
m_uFramesAhead = 0;
|
||||
|
||||
if (simulating && !m_bHasMapSimulatedYet)
|
||||
if (m_pOnGameFrame->GetFunctionCount())
|
||||
{
|
||||
m_bHasMapSimulatedYet = true;
|
||||
MapTimeLeftChanged();
|
||||
m_pOnGameFrame->Execute(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,6 @@ public: //ITimerSystem
|
||||
public:
|
||||
void RunFrame();
|
||||
void RemoveMapChangeTimers();
|
||||
void Think(bool unused);
|
||||
void GameFrame(bool simulating);
|
||||
private:
|
||||
List<ITimer *> m_SingleTimers;
|
||||
@@ -93,8 +92,6 @@ private:
|
||||
/* This is stuff for our manual ticking escapades. */
|
||||
bool m_bHasMapTickedYet; /** Has the map ticked yet? */
|
||||
bool m_bHasMapSimulatedYet; /** Has the map simulated yet? */
|
||||
bool m_bWasSimulating; /** Was the last GameFrame simulating */
|
||||
unsigned m_uFramesAhead; /** Number of frames Think is ahead of GameFrame */
|
||||
float m_fLastTickedTime; /** Last time that the game currently gave
|
||||
us while ticking.
|
||||
*/
|
||||
|
||||
@@ -816,9 +816,6 @@ public:
|
||||
|
||||
inline bool GetColor(const char *pszFieldName, Color *out)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
@@ -832,14 +829,10 @@ public:
|
||||
);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool SetColor(const char *pszFieldName, const Color &value)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_NOT_REPEATED();
|
||||
@@ -851,14 +844,10 @@ public:
|
||||
msgRGBA->set_a(value.a());
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_REPEATED();
|
||||
@@ -873,14 +862,10 @@ public:
|
||||
);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_REPEATED();
|
||||
@@ -893,14 +878,10 @@ public:
|
||||
msgRGBA->set_a(value.a());
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool AddColor(const char *pszFieldName, const Color &value)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||
return false;
|
||||
#else
|
||||
GETCHECK_FIELD();
|
||||
CHECK_FIELD_TYPE(MESSAGE);
|
||||
CHECK_FIELD_REPEATED();
|
||||
@@ -912,7 +893,6 @@ public:
|
||||
msgRGBA->set_a(value.a());
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
|
||||
|
||||
+65
-62
@@ -37,16 +37,14 @@
|
||||
#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;
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *GetMessagePrototype(int msg_type);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||
#else
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
@@ -55,14 +53,14 @@ 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
|
||||
#endif // ==SE_CSGO || ==SE_BLADE || ==SE_MCV
|
||||
|
||||
UserMessages::UserMessages()
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
: m_InterceptBuffer(m_pBase, 2500)
|
||||
{
|
||||
#else
|
||||
: m_InterceptBuffer(nullptr)
|
||||
: m_InterceptBuffer(NULL)
|
||||
{
|
||||
#endif
|
||||
m_HookCount = 0;
|
||||
@@ -99,7 +97,7 @@ void UserMessages::OnSourceModAllShutdown()
|
||||
{
|
||||
if (m_HookCount)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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
|
||||
@@ -119,6 +117,8 @@ int UserMessages::GetMessageIndex(const char *msg)
|
||||
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;
|
||||
@@ -158,6 +158,8 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
||||
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;
|
||||
@@ -237,7 +239,7 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
return NULL;
|
||||
#else
|
||||
PbHandle buffer;
|
||||
protobuf::Message *buffer;
|
||||
|
||||
if (m_InExec || m_InHook)
|
||||
{
|
||||
@@ -266,9 +268,8 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
// direct message creation, return buffer "from engine". keep track
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
buffer = m_FakeEngineBuffer.AsUnowned();
|
||||
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
|
||||
buffer = m_FakeEngineBuffer;
|
||||
} else {
|
||||
char messageName[32];
|
||||
if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
|
||||
@@ -277,30 +278,27 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The message returned here should always local.
|
||||
auto msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
switch (m_FakeMetaRes)
|
||||
{
|
||||
case MRES_IGNORED:
|
||||
case MRES_HANDLED:
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
buffer = m_FakeEngineBuffer.AsUnowned();
|
||||
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
|
||||
buffer = m_FakeEngineBuffer;
|
||||
break;
|
||||
|
||||
case MRES_OVERRIDE:
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
|
||||
// fallthrough
|
||||
case MRES_SUPERCEDE:
|
||||
buffer = std::move(msg);
|
||||
buffer = msg;
|
||||
break;
|
||||
}
|
||||
|
||||
OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
}
|
||||
|
||||
assert(!buffer.is_owned());
|
||||
return buffer.GetLocalMessage();
|
||||
return buffer;
|
||||
#endif // USE_PROTOBUF_USERMESSAGES
|
||||
}
|
||||
|
||||
@@ -311,13 +309,12 @@ bool UserMessages::EndMessage()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
PbHandle localBuffer = std::move(m_FakeEngineBuffer);
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
PbHandle priv = localBuffer.ToPrivate(m_CurId);
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId,
|
||||
*priv.GetPrivateMessage());
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
delete m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer = NULL;
|
||||
} else {
|
||||
OnMessageEnd_Pre();
|
||||
|
||||
@@ -326,12 +323,10 @@ bool UserMessages::EndMessage()
|
||||
case MRES_IGNORED:
|
||||
case MRES_HANDLED:
|
||||
case MRES_OVERRIDE:
|
||||
{
|
||||
PbHandle priv = localBuffer.ToPrivate(m_CurId);
|
||||
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId,
|
||||
*priv.GetPrivateMessage());
|
||||
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
delete m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer = NULL;
|
||||
break;
|
||||
}
|
||||
//case MRES_SUPERCEDE:
|
||||
}
|
||||
|
||||
@@ -344,7 +339,7 @@ bool UserMessages::EndMessage()
|
||||
} else {
|
||||
engine->MessageEnd();
|
||||
}
|
||||
#endif // SE_CSGO || SE_BLADE
|
||||
#endif // SE_CSGO || SE_BLADE || SE_MCV
|
||||
|
||||
m_InExec = false;
|
||||
m_CurFlags = 0;
|
||||
@@ -429,7 +424,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
||||
|
||||
if (!m_HookCount++)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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
|
||||
@@ -451,12 +446,14 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
||||
}
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *GetMessagePrototype(int msg_type)
|
||||
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
|
||||
{
|
||||
#if 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
|
||||
@@ -506,7 +503,7 @@ void UserMessages::_DecRefCounter()
|
||||
{
|
||||
if (--m_HookCount == 0)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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
|
||||
@@ -518,13 +515,15 @@ void UserMessages::_DecRefCounter()
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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);
|
||||
#endif
|
||||
|
||||
OnStartMessage_Pre(&filter, msg_type, pszName);
|
||||
@@ -538,8 +537,7 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(&const_cast<protobuf::Message &>(msg), PbHandle::Unowned, PbHandle::Private);
|
||||
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
||||
}
|
||||
|
||||
OnStartMessage_Post(&filter, msg_type, pszName);
|
||||
@@ -574,8 +572,8 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
|
||||
RETURN_META(res)
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
PbHandle UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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)
|
||||
#else
|
||||
@@ -589,7 +587,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
|
||||
{
|
||||
m_InHook = false;
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, nullptr);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
m_CurId = msg_type;
|
||||
@@ -600,20 +598,22 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
if (!is_intercept_empty)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
m_InterceptBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_type)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer.AsUnowned());
|
||||
if (m_InterceptBuffer)
|
||||
delete m_InterceptBuffer;
|
||||
m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
|
||||
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
|
||||
#else
|
||||
m_InterceptBuffer.Reset();
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, nullptr);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
void* UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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)
|
||||
#else
|
||||
@@ -627,9 +627,9 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
m_OrigBuffer = m_InterceptBuffer.AsUnowned();
|
||||
m_OrigBuffer = m_InterceptBuffer;
|
||||
else
|
||||
m_OrigBuffer = m_FakeEngineBuffer.AsUnowned();
|
||||
m_OrigBuffer = m_FakeEngineBuffer;
|
||||
#else
|
||||
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
|
||||
#endif
|
||||
@@ -725,11 +725,8 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
{
|
||||
pInfo = (*iter);
|
||||
pInfo->IsHooked = true;
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
PbHandle local = m_InterceptBuffer.ToLocal(m_CurId);
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, local.GetLocalMessage(), m_CurRecFilter);
|
||||
m_InterceptBuffer.CopyFrom(local);
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
|
||||
#else
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
|
||||
#endif
|
||||
@@ -780,9 +777,8 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
|
||||
if (!handled && intercepted)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
PbHandle priv = m_InterceptBuffer.ToPrivate(m_CurId);
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *priv.GetPrivateMessage());
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||
#else
|
||||
bf_write *engine_bfw;
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
@@ -793,14 +789,17 @@ 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
|
||||
#endif // SE_CSGO || SE_BLADE || SE_MCV
|
||||
}
|
||||
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
PbHandle tmp_msg(GetMessagePrototype(m_CurId)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
tmp_msg.CopyFrom(m_OrigBuffer);
|
||||
auto pTempMsg = tmp_msg.GetLocalMessage();
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
int size = m_OrigBuffer->ByteSize();
|
||||
uint8 *data = (uint8 *)stackalloc(size);
|
||||
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||
|
||||
protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
|
||||
pTempMsg->ParsePartialFromArray(data, size);
|
||||
#else
|
||||
bf_write *pTempMsg = m_OrigBuffer;
|
||||
#endif
|
||||
@@ -823,6 +822,10 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
pInfo->IsHooked = false;
|
||||
iter++;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
delete pTempMsg;
|
||||
#endif
|
||||
}
|
||||
|
||||
UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
|
||||
|
||||
+9
-9
@@ -44,7 +44,7 @@
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#define USE_PROTOBUF_USERMESSAGES
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,6 @@ using namespace SourceMod;
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <netmessages.pb.h>
|
||||
#include "pb_handle.h"
|
||||
|
||||
using namespace google;
|
||||
#else
|
||||
@@ -103,14 +102,14 @@ public: //IUserMessages
|
||||
bool intercept=false);
|
||||
UserMessageType GetUserMessageType() const;
|
||||
public:
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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
|
||||
PbHandle OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
void* OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
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
|
||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
@@ -122,6 +121,7 @@ public:
|
||||
void OnMessageEnd_Post();
|
||||
private:
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *GetMessagePrototype(int msg_type);
|
||||
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
#else
|
||||
@@ -141,11 +141,11 @@ private:
|
||||
bf_read m_ReadBuffer;
|
||||
#else
|
||||
// The engine used to provide this. Now we track it.
|
||||
PbHandle m_OrigBuffer;
|
||||
PbHandle m_FakeEngineBuffer;
|
||||
protobuf::Message *m_OrigBuffer;
|
||||
protobuf::Message *m_FakeEngineBuffer;
|
||||
META_RES m_FakeMetaRes;
|
||||
|
||||
PbHandle m_InterceptBuffer;
|
||||
protobuf::Message *m_InterceptBuffer;
|
||||
#endif
|
||||
size_t m_HookCount;
|
||||
bool m_InHook;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#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 *);
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
|
||||
#else
|
||||
void LinkConCommandBase(ConCommandBase *pBase)
|
||||
|
||||
@@ -16,7 +16,7 @@ for cxx in builder.targets:
|
||||
'SM_DEFAULT_THREADER',
|
||||
'SM_LOGIC'
|
||||
]
|
||||
|
||||
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||
elif binary.compiler.target.platform == 'mac':
|
||||
@@ -84,6 +84,9 @@ for cxx in builder.targets:
|
||||
'smn_halflife.cpp',
|
||||
'FrameIterator.cpp',
|
||||
'DatabaseConfBuilder.cpp',
|
||||
'LumpManager.cpp',
|
||||
'smn_entitylump.cpp',
|
||||
'NativeInvoker.cpp',
|
||||
]
|
||||
|
||||
if binary.compiler.target.arch == 'x86_64':
|
||||
|
||||
+17
-21
@@ -128,8 +128,8 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
|
||||
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);
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
ke::RefPtr<ConfDbInfo> pInfo = list.GetDatabaseConf(name);
|
||||
|
||||
if (!pInfo)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ 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();
|
||||
std::string defaultDriver = list.GetDefaultDriver();
|
||||
if (!m_pDefault && defaultDriver.length() > 0)
|
||||
{
|
||||
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||
@@ -209,17 +209,14 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
}
|
||||
}
|
||||
|
||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
||||
for (size_t i = 0; i < list->size(); i++)
|
||||
{
|
||||
ke::RefPtr<ConfDbInfo> current = list->at(i);
|
||||
if (current->realDriver == pDriver)
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
for (auto conf : list) {
|
||||
if (conf->realDriver == pDriver)
|
||||
{
|
||||
current->realDriver = NULL;
|
||||
conf->realDriver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Someone unloaded the default driver? Silly.. */
|
||||
if (pDriver == m_pDefault)
|
||||
{
|
||||
@@ -255,8 +252,8 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
|
||||
IDBDriver *DBManager::GetDefaultDriver()
|
||||
{
|
||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
||||
std::string defaultDriver = list->GetDefaultDriver();
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
std::string defaultDriver = list.GetDefaultDriver();
|
||||
if (!m_pDefault && defaultDriver.length() > 0)
|
||||
{
|
||||
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||
@@ -322,12 +319,12 @@ 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);
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
ke::RefPtr<ConfDbInfo> info = list.GetDatabaseConf(name);
|
||||
if (!info)
|
||||
{
|
||||
// couldn't find requested conf, return default if exists
|
||||
info = list->GetDefaultConfiguration();
|
||||
info = list.GetDefaultConfiguration();
|
||||
if (!info)
|
||||
{
|
||||
return NULL;
|
||||
@@ -337,11 +334,10 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
||||
return &info->info;
|
||||
}
|
||||
|
||||
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
|
||||
ke::RefPtr<ConfDbInfo> DBManager::GetDatabaseConf(const char *name)
|
||||
{
|
||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
||||
ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name));
|
||||
return info;
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
return list.GetDatabaseConf(name);
|
||||
}
|
||||
|
||||
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||
@@ -582,8 +578,8 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
||||
|
||||
std::string DBManager::GetDefaultDriverName()
|
||||
{
|
||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
||||
return list->GetDefaultDriver();
|
||||
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||
return list.GetDefaultDriver();
|
||||
}
|
||||
|
||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||
|
||||
@@ -71,7 +71,7 @@ public: //IDBManager
|
||||
void AddDriver(IDBDriver *pDrivera);
|
||||
void RemoveDriver(IDBDriver *pDriver);
|
||||
const DatabaseInfo *FindDatabaseConf(const char *name);
|
||||
ConfDbInfo *GetDatabaseConf(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);
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
#define DBPARSE_LEVEL_DATABASE 2
|
||||
|
||||
DatabaseConfBuilder::DatabaseConfBuilder()
|
||||
: m_ParseList(nullptr),
|
||||
m_InfoList(new ConfDbInfoList())
|
||||
: m_ParseList(),
|
||||
m_InfoList()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ DatabaseConfBuilder::~DatabaseConfBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
ConfDbInfoList *DatabaseConfBuilder::GetConfigList()
|
||||
ConfDbInfoList &DatabaseConfBuilder::GetConfigList()
|
||||
{
|
||||
return m_InfoList;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ void DatabaseConfBuilder::ReadSMC_ParseStart()
|
||||
m_ParseLevel = 0;
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
|
||||
m_ParseList = new ConfDbInfoList();
|
||||
m_ParseList.clear();
|
||||
}
|
||||
|
||||
SMCResult DatabaseConfBuilder::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
@@ -116,7 +116,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_KeyValue(const SMCStates *states, const c
|
||||
{
|
||||
if (strcmp(key, "driver_default") == 0)
|
||||
{
|
||||
m_ParseList->SetDefaultDriver(value);
|
||||
m_ParseList.SetDefaultDriver(value);
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
if (strcmp(key, "driver") == 0)
|
||||
@@ -161,7 +161,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
|
||||
/* Save it.. */
|
||||
m_ParseCurrent->AddRef();
|
||||
m_ParseList->push_back(m_ParseCurrent);
|
||||
m_ParseList.push_back(m_ParseCurrent);
|
||||
m_ParseCurrent = nullptr;
|
||||
|
||||
/* Go up one level */
|
||||
@@ -176,9 +176,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
|
||||
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||
{
|
||||
m_InfoList->ReleaseMembers();
|
||||
delete m_InfoList;
|
||||
m_InfoList.clear();
|
||||
m_InfoList = m_ParseList;
|
||||
|
||||
m_ParseList = nullptr;
|
||||
m_ParseList.clear();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <am-vector.h>
|
||||
#include <am-string.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <am-refcounting-threadsafe.h>
|
||||
|
||||
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
|
||||
@@ -56,7 +57,7 @@ public:
|
||||
DatabaseInfo info;
|
||||
};
|
||||
|
||||
class ConfDbInfoList : public std::vector<ConfDbInfo *>
|
||||
class ConfDbInfoList : public std::vector<ke::RefPtr<ConfDbInfo>>
|
||||
{
|
||||
/* Allow internal usage of ConfDbInfoList */
|
||||
friend class DBManager;
|
||||
@@ -66,10 +67,10 @@ private:
|
||||
return m_DefDriver;
|
||||
}
|
||||
|
||||
ConfDbInfo *GetDatabaseConf(const char *name) {
|
||||
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name) {
|
||||
for (size_t i = 0; i < this->size(); i++)
|
||||
{
|
||||
ConfDbInfo *current = this->at(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)
|
||||
@@ -83,20 +84,15 @@ private:
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
ConfDbInfo *GetDefaultConfiguration() {
|
||||
|
||||
ke::RefPtr<ConfDbInfo> GetDefaultConfiguration() {
|
||||
return m_DefaultConfig;
|
||||
}
|
||||
void SetDefaultDriver(const char *input) {
|
||||
m_DefDriver = std::string(input);
|
||||
}
|
||||
void ReleaseMembers() {
|
||||
for (size_t i = 0; i < this->size(); i++) {
|
||||
ConfDbInfo *current = this->at(i);
|
||||
current->Release();
|
||||
}
|
||||
}
|
||||
private:
|
||||
ConfDbInfo *m_DefaultConfig;
|
||||
ke::RefPtr<ConfDbInfo> m_DefaultConfig;
|
||||
std::string m_DefDriver;
|
||||
};
|
||||
|
||||
@@ -108,7 +104,7 @@ public:
|
||||
~DatabaseConfBuilder();
|
||||
void StartParse();
|
||||
void SetPath(char* path);
|
||||
ConfDbInfoList *GetConfigList();
|
||||
ConfDbInfoList &GetConfigList();
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
@@ -120,10 +116,10 @@ private:
|
||||
unsigned int m_ParseLevel;
|
||||
unsigned int m_ParseState;
|
||||
ConfDbInfo *m_ParseCurrent;
|
||||
ConfDbInfoList *m_ParseList;
|
||||
ConfDbInfoList m_ParseList;
|
||||
private:
|
||||
std::string m_Filename;
|
||||
ConfDbInfoList *m_InfoList;
|
||||
ConfDbInfoList m_InfoList;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
|
||||
|
||||
@@ -69,13 +69,13 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
|
||||
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
||||
|
||||
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
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 (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);
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
|
||||
@@ -47,6 +47,8 @@ public: // IDebugListener
|
||||
void ReportError(const IErrorReport &report, IFrameIterator &iter);
|
||||
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, ...);
|
||||
|
||||
@@ -240,6 +240,8 @@ void CLocalExtension::Unload()
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
}
|
||||
|
||||
m_bFullyLoaded = false;
|
||||
}
|
||||
|
||||
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
||||
@@ -393,11 +395,6 @@ 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;
|
||||
|
||||
+132
-38
@@ -30,6 +30,7 @@
|
||||
#include "common_logic.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include "GameConfigs.h"
|
||||
@@ -46,6 +47,7 @@
|
||||
#include <am-string.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/IFileSystemBridge.h>
|
||||
|
||||
#if defined PLATFORM_POSIX
|
||||
#include <dlfcn.h>
|
||||
@@ -85,15 +87,12 @@ static const char *g_pParseEngine = NULL;
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
|
||||
#define PLATFORM_SERVER_BINARY "server.dll"
|
||||
#elif defined PLATFORM_LINUX
|
||||
#define PLATFORM_NAME "linux" PLATFORM_ARCH_SUFFIX
|
||||
#define PLATFORM_COMPAT_ALT "mac" PLATFORM_ARCH_SUFFIX /* Alternate platform name if game data is missing for primary one */
|
||||
#define PLATFORM_SERVER_BINARY "server_i486.so"
|
||||
#elif defined PLATFORM_APPLE
|
||||
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
|
||||
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
|
||||
#define PLATFORM_SERVER_BINARY "server.dylib"
|
||||
#endif
|
||||
|
||||
struct TempSigInfo
|
||||
@@ -106,8 +105,6 @@ struct TempSigInfo
|
||||
char sig[1024];
|
||||
char library[64];
|
||||
} s_TempSig;
|
||||
unsigned int s_ServerBinCRC;
|
||||
bool s_ServerBinCRC_Ok = false;
|
||||
|
||||
static bool DoesGameMatch(const char *value)
|
||||
{
|
||||
@@ -306,35 +303,21 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
{
|
||||
char error[255];
|
||||
error[0] = '\0';
|
||||
if (strcmp(name, "server") != 0)
|
||||
GameBinaryInfo binInfo;
|
||||
if (!g_GameConfigs.TryGetGameBinaryInfo(name, &binInfo))
|
||||
{
|
||||
ke::SafeSprintf(error, sizeof(error), "Unrecognized library \"%s\"", name);
|
||||
}
|
||||
else if (!s_ServerBinCRC_Ok)
|
||||
else if (!binInfo.m_crcOK)
|
||||
{
|
||||
FILE *fp;
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
|
||||
g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
|
||||
if ((fp = fopen(path, "rb")) == NULL)
|
||||
{
|
||||
ke::SafeSprintf(error, sizeof(error), "Could not open binary: %s", path);
|
||||
} else {
|
||||
size_t size;
|
||||
void *buffer;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
buffer = malloc(size);
|
||||
fread(buffer, size, 1, fp);
|
||||
s_ServerBinCRC = UTIL_CRC32(buffer, size);
|
||||
free(buffer);
|
||||
s_ServerBinCRC_Ok = true;
|
||||
fclose(fp);
|
||||
}
|
||||
ke::SafeSprintf(error, sizeof(error), "Could not get CRC for binary: %s", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
bCurrentBinCRC_Ok = binInfo.m_crcOK;
|
||||
bCurrentBinCRC = binInfo.m_crc;
|
||||
}
|
||||
|
||||
if (error[0] != '\0')
|
||||
{
|
||||
m_IgnoreLevel = 1;
|
||||
@@ -461,12 +444,12 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
||||
}
|
||||
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
|
||||
if (DoesPlatformMatch(key)
|
||||
&& s_ServerBinCRC_Ok
|
||||
&& bCurrentBinCRC_Ok
|
||||
&& !bShouldBeReadingDefault)
|
||||
{
|
||||
unsigned int crc = 0;
|
||||
sscanf(value, "%08X", &crc);
|
||||
if (s_ServerBinCRC == crc)
|
||||
if (bCurrentBinCRC == crc)
|
||||
{
|
||||
bShouldBeReadingDefault = true;
|
||||
}
|
||||
@@ -603,14 +586,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
|
||||
}
|
||||
void *addrInBase = NULL;
|
||||
if (strcmp(s_TempSig.library, "server") == 0)
|
||||
GameBinaryInfo binInfo;
|
||||
if (g_GameConfigs.TryGetGameBinaryInfo(s_TempSig.library, &binInfo))
|
||||
{
|
||||
addrInBase = bridge->serverFactory;
|
||||
} else if (strcmp(s_TempSig.library, "engine") == 0) {
|
||||
addrInBase = bridge->engineFactory;
|
||||
} else if (strcmp(s_TempSig.library, "matchmaking_ds") == 0) {
|
||||
addrInBase = bridge->matchmakingDSFactory;
|
||||
addrInBase = binInfo.m_pAddr;
|
||||
}
|
||||
|
||||
void *final_addr = NULL;
|
||||
if (addrInBase == NULL)
|
||||
{
|
||||
@@ -810,7 +791,10 @@ public:
|
||||
(!had_game && matched_engine) ||
|
||||
(matched_engine && matched_game))
|
||||
{
|
||||
fileList->push_back(cur_file);
|
||||
if (fileList->find(cur_file) == fileList->end())
|
||||
{
|
||||
fileList->push_back(cur_file);
|
||||
}
|
||||
}
|
||||
state = MSTATE_MAIN;
|
||||
}
|
||||
@@ -1099,6 +1083,42 @@ bool CGameConfig::GetMemSig(const char *key, void **addr)
|
||||
return m_Sigs.retrieve(key, addr);
|
||||
}
|
||||
|
||||
void GameBinPathManager::Init()
|
||||
{
|
||||
char search_path[PLATFORM_MAX_PATH * 8];
|
||||
bridge->filesystem->GetSearchPath("GAMEBIN", false, search_path, sizeof(search_path));
|
||||
|
||||
char addons_folder[12];
|
||||
ke::SafeSprintf(addons_folder, sizeof(addons_folder), "%caddons%c", PLATFORM_SEP_CHAR, PLATFORM_SEP_CHAR);
|
||||
|
||||
std::istringstream iss(search_path);
|
||||
for (std::string path; std::getline(iss, path, ';');)
|
||||
{
|
||||
if (path.length() > 0
|
||||
&& path.find(addons_folder) == std::string::npos
|
||||
&& m_lookup.find(path) == m_lookup.cend()
|
||||
)
|
||||
{
|
||||
m_lookup.insert(path);
|
||||
m_ordered.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
iss.clear();
|
||||
|
||||
bridge->filesystem->GetSearchPath("EXECUTABLE_PATH", false, search_path, sizeof(search_path));
|
||||
iss.str(search_path);
|
||||
|
||||
for (std::string path; std::getline(iss, path, ';');)
|
||||
{
|
||||
if (m_lookup.find(path) == m_lookup.cend())
|
||||
{
|
||||
m_lookup.insert(path);
|
||||
m_ordered.push_back(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameConfigManager::GameConfigManager()
|
||||
{
|
||||
}
|
||||
@@ -1109,6 +1129,8 @@ GameConfigManager::~GameConfigManager()
|
||||
|
||||
void GameConfigManager::OnSourceModStartup(bool late)
|
||||
{
|
||||
m_gameBinPathManager.Init();
|
||||
|
||||
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
|
||||
|
||||
strncopy(g_Game, g_pSM->GetGameFolderName(), sizeof(g_Game));
|
||||
@@ -1231,3 +1253,75 @@ void GameConfigManager::RemoveCachedConfig(CGameConfig *config)
|
||||
{
|
||||
m_Lookup.remove(config->m_File);
|
||||
}
|
||||
|
||||
void GameConfigManager::CacheGameBinaryInfo(const char* pszName)
|
||||
{
|
||||
GameBinaryInfo info;
|
||||
|
||||
char name[64];
|
||||
bridge->FormatSourceBinaryName(pszName, name, sizeof(name));
|
||||
|
||||
char binary_path[PLATFORM_MAX_PATH];
|
||||
for (auto it = m_gameBinPathManager.Paths().begin(); it != m_gameBinPathManager.Paths().end(); ++it)
|
||||
{
|
||||
ke::SafeSprintf(binary_path, sizeof(binary_path), "%s%s%s", it->c_str(), it->back() == PLATFORM_SEP_CHAR ? "" : PLATFORM_SEP, name);
|
||||
#if defined PLATFORM_WINDOWS
|
||||
HMODULE hModule = LoadLibraryA(binary_path);
|
||||
if (hModule)
|
||||
{
|
||||
info.m_pAddr = GetProcAddress(hModule, "CreateInterface");
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
#else
|
||||
void *pHandle = dlopen(binary_path, RTLD_NOW);
|
||||
if (pHandle)
|
||||
{
|
||||
info.m_pAddr = dlsym(pHandle, "CreateInterface");
|
||||
dlclose(pHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info.m_pAddr)
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't bother trying to get CRC if we couldn't find the bin loaded
|
||||
if (info.m_pAddr)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen(binary_path, "rb")) == 0)
|
||||
{
|
||||
info.m_crc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size;
|
||||
void* buffer;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
buffer = malloc(size);
|
||||
fread(buffer, size, 1, fp);
|
||||
info.m_crc = UTIL_CRC32(buffer, size);
|
||||
free(buffer);
|
||||
info.m_crcOK = true;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
// But insert regardless, to cache the first lookup (even as failed)
|
||||
m_gameBinInfos.insert(pszName, info);
|
||||
}
|
||||
|
||||
bool GameConfigManager::TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest)
|
||||
{
|
||||
if (m_gameBinInfos.retrieve(pszName, pDest))
|
||||
return pDest->m_pAddr != nullptr;
|
||||
|
||||
CacheGameBinaryInfo(pszName);
|
||||
|
||||
return m_gameBinInfos.retrieve(pszName, pDest);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
@@ -91,6 +92,8 @@ private:
|
||||
std::string m_offset;
|
||||
std::string m_Game;
|
||||
std::string m_Key;
|
||||
unsigned int bCurrentBinCRC;
|
||||
bool bCurrentBinCRC_Ok = false;
|
||||
bool bShouldBeReadingDefault;
|
||||
bool had_game;
|
||||
bool matched_game;
|
||||
@@ -126,6 +129,30 @@ private:
|
||||
time_t m_ModTime;
|
||||
};
|
||||
|
||||
struct GameBinaryInfo
|
||||
{
|
||||
void *m_pAddr = nullptr;
|
||||
uint32_t m_crc = 0;
|
||||
bool m_crcOK = false;
|
||||
};
|
||||
|
||||
class GameBinPathManager
|
||||
{
|
||||
public:
|
||||
GameBinPathManager() {}
|
||||
~GameBinPathManager() {}
|
||||
public:
|
||||
void Init();
|
||||
|
||||
inline const std::vector<std::string>& Paths() const
|
||||
{
|
||||
return m_ordered;
|
||||
}
|
||||
private:
|
||||
std::unordered_set<std::string> m_lookup;
|
||||
std::vector<std::string> m_ordered;
|
||||
};
|
||||
|
||||
class GameConfigManager :
|
||||
public IGameConfigManager,
|
||||
public SMGlobalClass
|
||||
@@ -148,11 +175,16 @@ public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModAllShutdown();
|
||||
public:
|
||||
bool TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest);
|
||||
void RemoveCachedConfig(CGameConfig *config);
|
||||
private:
|
||||
void CacheGameBinaryInfo(const char* pszName);
|
||||
private:
|
||||
NameHashSet<CGameConfig *> m_Lookup;
|
||||
StringHashMap<GameBinaryInfo> m_gameBinInfos;
|
||||
public:
|
||||
StringHashMap<ITextListener_SMC *> m_customHandlers;
|
||||
GameBinPathManager m_gameBinPathManager;
|
||||
};
|
||||
|
||||
extern GameConfigManager g_GameConfigs;
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "sm_invalidparamhandler.h"
|
||||
#endif
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
HandleSystem g_HandleSys;
|
||||
|
||||
QHandle *ignore_handle;
|
||||
@@ -299,6 +301,28 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
||||
}
|
||||
}
|
||||
|
||||
if (owner)
|
||||
{
|
||||
owner->num_handles++;
|
||||
if (!owner->warned_handle_usage && owner->num_handles >= HANDLESYS_WARN_USAGE)
|
||||
{
|
||||
owner->warned_handle_usage = true;
|
||||
|
||||
std::string path = "<unknown>";
|
||||
if (auto plugin = scripts->FindPluginByIdentity(owner))
|
||||
{
|
||||
path = "plugin "s + plugin->GetFilename();
|
||||
}
|
||||
else if (auto ext = g_Extensions.GetExtensionFromIdent(owner))
|
||||
{
|
||||
path = "extension "s + ext->GetFilename();
|
||||
}
|
||||
|
||||
logger->LogError("[SM] Warning: %s is using more than %d handles!",
|
||||
path.c_str(), HANDLESYS_WARN_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
QHandle *pHandle = &m_Handles[handle];
|
||||
|
||||
assert(pHandle->set == false);
|
||||
@@ -320,7 +344,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
||||
|
||||
/* Create the hash value */
|
||||
Handle_t hash = pHandle->serial;
|
||||
hash <<= 16;
|
||||
hash <<= HANDLESYS_HANDLE_BITS;
|
||||
hash |= handle;
|
||||
|
||||
/* Add a reference count to the type */
|
||||
@@ -484,7 +508,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
||||
unsigned int *in_index,
|
||||
bool ignoreFree)
|
||||
{
|
||||
unsigned int serial = (handle >> 16);
|
||||
unsigned int serial = (handle >> HANDLESYS_HANDLE_BITS);
|
||||
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
||||
|
||||
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
||||
@@ -640,7 +664,7 @@ Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
|
||||
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
unsigned int serial = (hndl >> 16);
|
||||
unsigned int serial = (hndl >> HANDLESYS_HANDLE_BITS);
|
||||
#endif
|
||||
index = (hndl & HANDLESYS_HANDLE_MASK);
|
||||
|
||||
@@ -664,6 +688,9 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
|
||||
QHandleType *pType = &m_Types[pHandle->type];
|
||||
|
||||
if (pHandle->owner && pHandle->owner->num_handles > 0)
|
||||
pHandle->owner->num_handles--;
|
||||
|
||||
if (pHandle->clone)
|
||||
{
|
||||
/* If we're a clone, decrease the parent reference count */
|
||||
@@ -1138,12 +1165,12 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
||||
continue;
|
||||
}
|
||||
/* Get the index */
|
||||
unsigned int index = (m_Handles[i].serial << 16) | i;
|
||||
unsigned int index = (m_Handles[i].serial << HANDLESYS_HANDLE_BITS) | i;
|
||||
/* Determine the owner */
|
||||
const char *owner = "UNKNOWN";
|
||||
if (m_Handles[i].owner)
|
||||
{
|
||||
IdentityToken_t *pOwner = m_Handles[i].owner;
|
||||
IdentityToken_t *pOwner = m_Handles[i].owner;
|
||||
if (pOwner == g_pCoreIdent)
|
||||
{
|
||||
owner = "CORE";
|
||||
|
||||
@@ -42,14 +42,17 @@
|
||||
#include <sm_namehashset.h>
|
||||
#include "common_logic.h"
|
||||
|
||||
#define HANDLESYS_MAX_HANDLES (1<<15)
|
||||
#define HANDLESYS_HANDLE_BITS 20
|
||||
#define HANDLESYS_MAX_HANDLES ((1 << HANDLESYS_HANDLE_BITS) - 1)
|
||||
#define HANDLESYS_MAX_TYPES (1<<9)
|
||||
#define HANDLESYS_MAX_SUBTYPES 0xF
|
||||
#define HANDLESYS_SUBTYPE_MASK 0xF
|
||||
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
||||
#define HANDLESYS_MAX_SERIALS 0xFFFF
|
||||
#define HANDLESYS_SERIAL_MASK 0xFFFF0000
|
||||
#define HANDLESYS_HANDLE_MASK 0x0000FFFF
|
||||
#define HANDLESYS_SERIAL_BITS (32 - HANDLESYS_HANDLE_BITS)
|
||||
#define HANDLESYS_MAX_SERIALS (1 << HANDLESYS_SERIAL_BITS)
|
||||
#define HANDLESYS_SERIAL_MASK (((1 << HANDLESYS_SERIAL_BITS) - 1) << HANDLESYS_HANDLE_BITS)
|
||||
#define HANDLESYS_HANDLE_MASK ((1 << HANDLESYS_HANDLE_BITS) - 1)
|
||||
#define HANDLESYS_WARN_USAGE 100000
|
||||
|
||||
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* Entity Lump Manager
|
||||
* Copyright (C) 2021-2022 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 "LumpManager.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
EntityLumpParseResult::operator bool() const {
|
||||
return m_Status == Status_OK;
|
||||
}
|
||||
|
||||
EntityLumpParseResult EntityLumpManager::Parse(const char* pMapEntities) {
|
||||
m_Entities.clear();
|
||||
|
||||
std::istringstream mapEntities(pMapEntities);
|
||||
|
||||
for (;;) {
|
||||
std::string token;
|
||||
mapEntities >> std::ws >> token >> std::ws;
|
||||
|
||||
// Assert that we're at the start of a new block, otherwise we're done parsing
|
||||
if (token != "{") {
|
||||
if (token == "\0") {
|
||||
break;
|
||||
} else {
|
||||
return EntityLumpParseResult {
|
||||
Status_UnexpectedChar, mapEntities.tellg()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse key / value pairs until we reach a closing brace. We currently assume there
|
||||
* are only quoted keys / values up to the next closing brace.
|
||||
*
|
||||
* The SDK suggests that there are cases that could use non-quoted symbols and nested
|
||||
* braces (`shared/mapentities_shared.cpp::MapEntity_ParseToken`), but I haven't seen
|
||||
* those in practice.
|
||||
*/
|
||||
EntityLumpEntry entry;
|
||||
while (mapEntities.peek() != '}') {
|
||||
std::string key, value;
|
||||
|
||||
if (mapEntities.peek() != '"') {
|
||||
return EntityLumpParseResult {
|
||||
Status_UnexpectedChar, mapEntities.tellg()
|
||||
};
|
||||
}
|
||||
mapEntities >> quoted(key) >> std::ws;
|
||||
|
||||
if (mapEntities.peek() != '"') {
|
||||
return EntityLumpParseResult {
|
||||
Status_UnexpectedChar, mapEntities.tellg()
|
||||
};
|
||||
}
|
||||
mapEntities >> quoted(value) >> std::ws;
|
||||
|
||||
entry.emplace_back(key, value);
|
||||
}
|
||||
mapEntities.get();
|
||||
m_Entities.push_back(std::make_shared<EntityLumpEntry>(entry));
|
||||
}
|
||||
|
||||
return EntityLumpParseResult{};
|
||||
}
|
||||
|
||||
std::string EntityLumpManager::Dump() {
|
||||
std::ostringstream stream;
|
||||
for (const auto& entry : m_Entities) {
|
||||
// ignore empty entries
|
||||
if (entry->empty()) {
|
||||
continue;
|
||||
}
|
||||
stream << "{\n";
|
||||
for (const auto& pair : *entry) {
|
||||
stream << '"' << pair.first << "\" \"" << pair.second << '"' << '\n';
|
||||
}
|
||||
stream << "}\n";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::weak_ptr<EntityLumpEntry> EntityLumpManager::Get(size_t index) {
|
||||
return m_Entities[index];
|
||||
}
|
||||
|
||||
void EntityLumpManager::Erase(size_t index) {
|
||||
m_Entities.erase(m_Entities.begin() + index);
|
||||
}
|
||||
|
||||
void EntityLumpManager::Insert(size_t index) {
|
||||
m_Entities.emplace(m_Entities.begin() + index, std::make_shared<EntityLumpEntry>());
|
||||
}
|
||||
|
||||
size_t EntityLumpManager::Append() {
|
||||
auto it = m_Entities.emplace(m_Entities.end(), std::make_shared<EntityLumpEntry>());
|
||||
return std::distance(m_Entities.begin(), it);
|
||||
}
|
||||
|
||||
size_t EntityLumpManager::Length() {
|
||||
return m_Entities.size();
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* Entity Lump Manager
|
||||
* Copyright (C) 2021-2022 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_LUMPMANAGER_H_
|
||||
#define _INCLUDE_LUMPMANAGER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Entity lump manager. Provides a list that stores a list of key / value pairs and the
|
||||
* functionality to (de)serialize it from / to an entity string.
|
||||
* This file and its corresponding .cpp should be compilable independently of SourceMod;
|
||||
* the SourceMod interop is located within smn_entitylump.
|
||||
*
|
||||
* @file lumpmanager.h
|
||||
* @brief Class definition for object that parses lumps.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A container of key / value pairs.
|
||||
*/
|
||||
using EntityLumpEntry = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
enum EntityLumpParseStatus {
|
||||
Status_OK,
|
||||
Status_UnexpectedChar,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Result of parsing an entity lump. On a parse error, m_Status is not Status_OK and
|
||||
* m_Position indicates the offset within the string that caused the parse error.
|
||||
*/
|
||||
struct EntityLumpParseResult {
|
||||
EntityLumpParseStatus m_Status;
|
||||
std::streamoff m_Position;
|
||||
|
||||
operator bool() const;
|
||||
const char* Description() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Manages entity lump entries.
|
||||
*/
|
||||
class EntityLumpManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Parses the map entities string into an internal representation.
|
||||
*/
|
||||
EntityLumpParseResult Parse(const char* pMapEntities);
|
||||
|
||||
/**
|
||||
* @brief Dumps the current internal representation out to an std::string.
|
||||
*/
|
||||
std::string Dump();
|
||||
|
||||
/**
|
||||
* @brief Returns a weak reference to an EntityLumpEntry. Used for handles on the scripting side.
|
||||
*/
|
||||
std::weak_ptr<EntityLumpEntry> Get(size_t index);
|
||||
|
||||
/**
|
||||
* @brief Removes an EntityLumpEntry at the given index, shifting down all entries after it by one.
|
||||
*/
|
||||
void Erase(size_t index);
|
||||
|
||||
/**
|
||||
* @brief Inserts a new EntityLumpEntry at the given index, shifting up the entries previously at the index and after it up by one.
|
||||
*/
|
||||
void Insert(size_t index);
|
||||
|
||||
/**
|
||||
* @brief Adds a new EntityLumpEntry to the end. Returns the index of the entry.
|
||||
*/
|
||||
size_t Append();
|
||||
|
||||
/**
|
||||
* @brief Returns the number of EntityLumpEntry items in the list.
|
||||
*/
|
||||
size_t Length();
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<EntityLumpEntry>> m_Entities;
|
||||
};
|
||||
|
||||
#endif // _INCLUDE_LUMPMANAGER_H_
|
||||
+51
-28
@@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;
|
||||
|
||||
MemoryUtils::MemoryUtils()
|
||||
{
|
||||
m_InfoMap.init();
|
||||
#ifdef PLATFORM_APPLE
|
||||
|
||||
task_dyld_info_data_t dyld_info;
|
||||
@@ -77,20 +78,19 @@ void MemoryUtils::OnSourceModAllInitialized()
|
||||
|
||||
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||
{
|
||||
DynLibInfo lib;
|
||||
bool found;
|
||||
char *ptr, *end;
|
||||
const DynLibInfo* lib = nullptr;
|
||||
|
||||
memset(&lib, 0, sizeof(DynLibInfo));
|
||||
|
||||
if (!GetLibraryInfo(libPtr, lib))
|
||||
if ((lib = GetLibraryInfo(libPtr)) == nullptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
||||
end = ptr + lib.memorySize - len;
|
||||
// Search in the original unaltered state of the binary.
|
||||
char *start = lib->originalCopy.get();
|
||||
char *ptr = start;
|
||||
char *end = ptr + lib->memorySize - len;
|
||||
|
||||
bool found;
|
||||
while (ptr < end)
|
||||
{
|
||||
found = true;
|
||||
@@ -103,8 +103,9 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l
|
||||
}
|
||||
}
|
||||
|
||||
// Translate the found offset into the actual live binary memory space.
|
||||
if (found)
|
||||
return ptr;
|
||||
return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start);
|
||||
|
||||
ptr++;
|
||||
}
|
||||
@@ -116,6 +117,8 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
/* Add this this library into the cache */
|
||||
GetLibraryInfo(handle);
|
||||
return GetProcAddress((HMODULE)handle, symbol);
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
@@ -162,6 +165,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add this this library into the cache */
|
||||
GetLibraryInfo((void *)dlmap->l_addr);
|
||||
|
||||
/* If we don't have a symbol table for this library, then create one */
|
||||
if (table == NULL)
|
||||
{
|
||||
@@ -325,6 +331,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
/* Uh oh, we couldn't find a matching handle */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add this this library into the cache */
|
||||
GetLibraryInfo((void *)dlbase);
|
||||
|
||||
/* See if we already have a symbol table for this library */
|
||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||
@@ -429,15 +438,17 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr)
|
||||
{
|
||||
uintptr_t baseAddr;
|
||||
|
||||
if (libPtr == NULL)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DynLibInfo lib;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
#ifdef PLATFORM_X86
|
||||
@@ -456,7 +467,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
||||
@@ -470,19 +481,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
/* Check PE magic and signature */
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check architecture */
|
||||
if (file->Machine != PE_FILE_MACHINE)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library */
|
||||
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Finally, we can do this */
|
||||
@@ -509,12 +520,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
if (!dladdr(libPtr, &info))
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* This is for our insane sanity checks :o */
|
||||
@@ -524,31 +535,31 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
/* Check ELF magic */
|
||||
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check ELF version */
|
||||
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check ELF endianness */
|
||||
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check ELF architecture */
|
||||
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library/shared object */
|
||||
if (file->e_type != ET_DYN)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
phdrCount = file->e_phnum;
|
||||
@@ -598,12 +609,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
if (!dladdr(libPtr, &info))
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* This is for our insane sanity checks :o */
|
||||
@@ -613,19 +624,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
/* Check Mach-O magic */
|
||||
if (file->magic != MACH_MAGIC)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check architecture */
|
||||
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library */
|
||||
if (file->filetype != MH_DYLIB)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cmd_count = file->ncmds;
|
||||
@@ -646,5 +657,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||
|
||||
return true;
|
||||
LibraryInfoMap::Insert i = m_InfoMap.findForAdd(lib.baseAddress);
|
||||
if (i.found())
|
||||
{
|
||||
// We already loaded this binary before.
|
||||
return &i->value;
|
||||
}
|
||||
|
||||
// Keep a copy of the binary in its initial unpatched state for lookup.
|
||||
lib.originalCopy = std::make_unique<char[]>(lib.memorySize);
|
||||
memcpy(lib.originalCopy.get(), lib.baseAddress, lib.memorySize);
|
||||
m_InfoMap.add(i, lib.baseAddress, std::move(lib));
|
||||
|
||||
return &i->value;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <IMemoryUtils.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <memory>
|
||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
#include <sh_vector.h>
|
||||
#include "sm_symtable.h"
|
||||
@@ -49,6 +51,7 @@ struct DynLibInfo
|
||||
{
|
||||
void *baseAddress;
|
||||
size_t memorySize;
|
||||
std::unique_ptr<char[]> originalCopy;
|
||||
};
|
||||
|
||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
@@ -73,7 +76,7 @@ public: // IMemoryUtils
|
||||
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||
void *ResolveSymbol(void *handle, const char *symbol);
|
||||
public:
|
||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||
const DynLibInfo *GetLibraryInfo(const void *libPtr);
|
||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
private:
|
||||
CVector<LibSymbolTable *> m_SymTables;
|
||||
@@ -83,6 +86,8 @@ private:
|
||||
SInt32 m_OSXMinor;
|
||||
#endif
|
||||
#endif
|
||||
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
|
||||
LibraryInfoMap m_InfoMap;
|
||||
};
|
||||
|
||||
extern MemoryUtils g_MemUtils;
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
// vim: set sts=2 ts=8 sw=2 tw=99 et:
|
||||
//
|
||||
// Copyright (C) 2006-2015 AlliedModders LLC
|
||||
//
|
||||
// This file is part of SourcePawn. SourcePawn is free software: you can
|
||||
// redistribute it and/or modify it under the terms of the GNU General Public
|
||||
// License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "NativeInvoker.h"
|
||||
|
||||
/********************
|
||||
* FUNCTION CALLING *
|
||||
********************/
|
||||
|
||||
NativeInvoker::NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native)
|
||||
: context_(pContext),
|
||||
m_curparam(0),
|
||||
m_errorstate(SP_ERROR_NONE),
|
||||
native_(native)
|
||||
{
|
||||
}
|
||||
|
||||
NativeInvoker::~NativeInvoker()
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeInvoker::IsRunnable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IPluginContext *
|
||||
NativeInvoker::GetParentContext()
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
int NativeInvoker::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
|
||||
m_info[m_curparam].marked = false;
|
||||
m_params[m_curparam] = cell;
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::PushCellByRef(cell_t *cell, int flags)
|
||||
{
|
||||
return PushArray(cell, 1, flags);
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::PushFloat(float number)
|
||||
{
|
||||
cell_t val = sp::FloatCellUnion(number).cell;
|
||||
|
||||
return PushCell(val);
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::PushFloatByRef(float *number, int flags)
|
||||
{
|
||||
return PushCellByRef((cell_t *)number, flags);
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
|
||||
info->flags = inarray ? copyback : 0;
|
||||
info->marked = true;
|
||||
info->size = cells;
|
||||
info->str.is_sz = false;
|
||||
info->orig_addr = inarray;
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::PushString(const char *string)
|
||||
{
|
||||
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||
{
|
||||
return _PushString(buffer, sz_flags, cp_flags, length);
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
|
||||
info->marked = true;
|
||||
info->orig_addr = (cell_t *)string;
|
||||
info->flags = cp_flags;
|
||||
info->size = len;
|
||||
info->str.sz_flags = sz_flags;
|
||||
info->str.is_sz = true;
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
NativeInvoker::Cancel()
|
||||
{
|
||||
if (!m_curparam)
|
||||
return;
|
||||
|
||||
m_errorstate = SP_ERROR_NONE;
|
||||
m_curparam = 0;
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::Execute(cell_t *result, cell_t buffer, cell_t size)
|
||||
{
|
||||
context_->ClearLastNativeError();
|
||||
|
||||
// For backward compatibility, we have to clear the exception state.
|
||||
// Otherwise code like this:
|
||||
//
|
||||
// static cell_t native(cx, params) {
|
||||
// for (auto callback : callbacks) {
|
||||
// callback->Execute();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Could unintentionally leak a pending exception back to the caller,
|
||||
// which wouldn't have happened before the Great Exception Refactoring.
|
||||
|
||||
SourcePawn::ExceptionHandler eh(context_);
|
||||
eh.Debug(!size);
|
||||
|
||||
if (!Invoke(result)) {
|
||||
if(size)
|
||||
context_->StringToLocalUTF8(buffer, size, eh.Message(), NULL);
|
||||
int Err = context_->GetLastNativeError();
|
||||
context_->ClearLastNativeError();
|
||||
return Err;
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool
|
||||
NativeInvoker::Invoke(cell_t *result)
|
||||
{
|
||||
if (!IsRunnable()) {
|
||||
Cancel();
|
||||
context_->ReportErrorNumber(SP_ERROR_NOT_RUNNABLE);
|
||||
return false;
|
||||
}
|
||||
if (int err = m_errorstate) {
|
||||
Cancel();
|
||||
context_->ReportErrorNumber(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
//This is for re-entrancy!
|
||||
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
|
||||
cell_t *temp_params = &_temp_params[1];
|
||||
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int numparams = m_curparam;
|
||||
unsigned int i;
|
||||
|
||||
if (numparams)
|
||||
{
|
||||
//Save the info locally, then reset it for re-entrant calls.
|
||||
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
||||
}
|
||||
m_curparam = 0;
|
||||
|
||||
/* Initialize 0th parameter */
|
||||
_temp_params[0] = numparams;
|
||||
|
||||
/* Browse the parameters and build arrays */
|
||||
bool ok = true;
|
||||
for (i=0; i<numparams; i++) {
|
||||
/* Is this marked as an array? */
|
||||
if (temp_info[i].marked) {
|
||||
if (!temp_info[i].str.is_sz) {
|
||||
/* Allocate a normal/generic array */
|
||||
int err = context_->HeapAlloc(
|
||||
temp_info[i].size,
|
||||
&(temp_info[i].local_addr),
|
||||
&(temp_info[i].phys_addr));
|
||||
if (err != SP_ERROR_NONE) {
|
||||
context_->ReportErrorNumber(err);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (temp_info[i].orig_addr)
|
||||
{
|
||||
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
|
||||
}
|
||||
} else {
|
||||
/* Calculate cells required for the string */
|
||||
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
|
||||
|
||||
/* Allocate the buffer */
|
||||
int err = context_->HeapAlloc(
|
||||
cells,
|
||||
&(temp_info[i].local_addr),
|
||||
&(temp_info[i].phys_addr));
|
||||
if (err != SP_ERROR_NONE) {
|
||||
context_->ReportErrorNumber(err);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy original string if necessary */
|
||||
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
|
||||
{
|
||||
/* Cut off UTF-8 properly */
|
||||
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) {
|
||||
context_->StringToLocalUTF8(
|
||||
temp_info[i].local_addr,
|
||||
temp_info[i].size,
|
||||
(const char *)temp_info[i].orig_addr,
|
||||
NULL);
|
||||
}
|
||||
/* Copy a binary blob */
|
||||
else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
|
||||
{
|
||||
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
|
||||
}
|
||||
/* Copy ASCII characters */
|
||||
else
|
||||
{
|
||||
context_->StringToLocal(
|
||||
temp_info[i].local_addr,
|
||||
temp_info[i].size,
|
||||
(const char *)temp_info[i].orig_addr);
|
||||
}
|
||||
}
|
||||
} /* End array/string calculation */
|
||||
/* Update the pushed parameter with the byref local address */
|
||||
temp_params[i] = temp_info[i].local_addr;
|
||||
} else {
|
||||
/* Just copy the value normally */
|
||||
temp_params[i] = m_params[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the call if we can */
|
||||
if (ok)
|
||||
{
|
||||
*result = native_->func()(context_, _temp_params);
|
||||
}
|
||||
|
||||
/* i should be equal to the last valid parameter + 1 */
|
||||
bool docopies = ok;
|
||||
while (i--) {
|
||||
if (!temp_info[i].marked)
|
||||
continue;
|
||||
|
||||
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) {
|
||||
if (temp_info[i].orig_addr) {
|
||||
if (temp_info[i].str.is_sz) {
|
||||
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
|
||||
|
||||
} else {
|
||||
if (temp_info[i].size == 1) {
|
||||
*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
|
||||
} else {
|
||||
memcpy(temp_info[i].orig_addr,
|
||||
temp_info[i].phys_addr,
|
||||
temp_info[i].size * sizeof(cell_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (int err = context_->HeapPop(temp_info[i].local_addr))
|
||||
context_->ReportErrorNumber(err);
|
||||
}
|
||||
|
||||
return context_->GetLastNativeError() == SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
NativeInvoker::SetError(int err)
|
||||
{
|
||||
m_errorstate = err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int NativeInvoker::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
|
||||
funcid_t NativeInvoker::GetFunctionID() { return 0; }
|
||||
int NativeInvoker::Execute2(IPluginContext *ctx, cell_t *result) { return 0; }
|
||||
int NativeInvoker::CallFunction2(IPluginContext *ctx, const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
|
||||
IPluginRuntime *NativeInvoker::GetParentRuntime() { return NULL; }
|
||||
@@ -0,0 +1,79 @@
|
||||
// vim: set sts=2 ts=8 sw=2 tw=99 et:
|
||||
//
|
||||
// Copyright (C) 2006-2015 AlliedModders LLC
|
||||
//
|
||||
// This file is part of SourcePawn. SourcePawn is free software: you can
|
||||
// redistribute it and/or modify it under the terms of the GNU General Public
|
||||
// License as published by the Free Software Foundation, either version 3 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
//
|
||||
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <amtl/am-autoptr.h>
|
||||
#include <amtl/am-refcounting.h>
|
||||
#include "Native.h"
|
||||
|
||||
struct ParamInfo
|
||||
{
|
||||
int flags; /* Copy-back flags */
|
||||
bool marked; /* Whether this is marked as being used */
|
||||
cell_t local_addr; /* Local address to free */
|
||||
cell_t *phys_addr; /* Physical address of our copy */
|
||||
cell_t *orig_addr; /* Original address to copy back to */
|
||||
ucell_t size; /* Size of array in bytes */
|
||||
struct {
|
||||
bool is_sz; /* is a string */
|
||||
int sz_flags; /* has sz flags */
|
||||
} str;
|
||||
};
|
||||
|
||||
class NativeInvoker : public IPluginFunction
|
||||
{
|
||||
public:
|
||||
NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native);
|
||||
virtual ~NativeInvoker();
|
||||
|
||||
public:
|
||||
int PushCell(cell_t cell);
|
||||
int PushCellByRef(cell_t *cell, int flags);
|
||||
int PushFloat(float number);
|
||||
int PushFloatByRef(float *number, int flags);
|
||||
int PushArray(cell_t *inarray, unsigned int cells, int copyback);
|
||||
int PushString(const char *string);
|
||||
int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
|
||||
int Execute(cell_t *result, cell_t buffer=0, cell_t size=0);
|
||||
void Cancel();
|
||||
int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result);
|
||||
IPluginContext *GetParentContext();
|
||||
bool Invoke(cell_t *result);
|
||||
bool IsRunnable();
|
||||
funcid_t GetFunctionID();
|
||||
int Execute2(IPluginContext *ctx, cell_t *result);
|
||||
int CallFunction2(IPluginContext *ctx,
|
||||
const cell_t *params,
|
||||
unsigned int num_params,
|
||||
cell_t *result);
|
||||
IPluginRuntime *GetParentRuntime();
|
||||
const char *DebugName() {
|
||||
return native_->name();
|
||||
}
|
||||
|
||||
private:
|
||||
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
||||
int SetError(int err);
|
||||
|
||||
private:
|
||||
IPluginContext *context_;
|
||||
cell_t m_params[SP_MAX_EXEC_PARAMS];
|
||||
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int m_curparam;
|
||||
int m_errorstate;
|
||||
ke::RefPtr<Native> native_;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
@@ -48,6 +48,8 @@
|
||||
#include <bridge/include/IVEngineServerBridge.h>
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
|
||||
#define SOURCEMOD_PLUGINAPI_VERSION 7
|
||||
|
||||
CPluginManager g_PluginSys;
|
||||
HandleType_t g_PluginType = 0;
|
||||
IdentityType_t g_PluginIdent = 0;
|
||||
@@ -309,12 +311,12 @@ bool CPlugin::ReadInfo()
|
||||
|
||||
base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
|
||||
m_FileVersion = info->version;
|
||||
if (m_FileVersion >= 4) {
|
||||
if (m_FileVersion >= 5) {
|
||||
base->LocalToString(info->date, (char **)&pDate);
|
||||
base->LocalToString(info->time, (char **)&pTime);
|
||||
ke::SafeSprintf(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
|
||||
}
|
||||
if (m_FileVersion > 5) {
|
||||
if (m_FileVersion > SOURCEMOD_PLUGINAPI_VERSION) {
|
||||
base->LocalToString(info->filevers, (char **)&pFileVers);
|
||||
EvictWithError(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
|
||||
return false;
|
||||
|
||||
@@ -49,15 +49,17 @@ namespace SourceMod
|
||||
{
|
||||
struct IdentityToken_t
|
||||
{
|
||||
Handle_t ident;
|
||||
void *ptr;
|
||||
IdentityType_t type;
|
||||
Handle_t ident = 0;
|
||||
void *ptr = nullptr;
|
||||
IdentityType_t type = 0;
|
||||
size_t num_handles = 0;
|
||||
bool warned_handle_usage = false;
|
||||
};
|
||||
};
|
||||
|
||||
struct IfaceInfo
|
||||
{
|
||||
bool operator ==(const IfaceInfo &info)
|
||||
bool operator ==(const IfaceInfo &info) const
|
||||
{
|
||||
return (info.iface == iface && info.owner == owner);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "LibrarySys.h"
|
||||
#include "RootConsoleMenu.h"
|
||||
#include "CellArray.h"
|
||||
#include "smn_entitylump.h"
|
||||
#include <bridge/include/BridgeAPI.h>
|
||||
#include <bridge/include/IProviderCallbacks.h>
|
||||
|
||||
@@ -89,6 +90,8 @@ CNativeOwner g_CoreNatives;
|
||||
PseudoAddressManager pseudoAddr;
|
||||
#endif
|
||||
|
||||
EntityLumpParseResult lastParseResult;
|
||||
|
||||
static void AddCorePhraseFile(const char *filename)
|
||||
{
|
||||
g_pCorePhrases->AddPhraseFile(filename);
|
||||
@@ -135,6 +138,35 @@ static uint32_t ToPseudoAddress(void *addr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SetEntityLumpWritable(bool writable)
|
||||
{
|
||||
g_bLumpAvailableForWriting = writable;
|
||||
|
||||
// write-lock causes the map entities to be serialized out to string
|
||||
if (!writable)
|
||||
{
|
||||
g_strMapEntities = lumpmanager->Dump();
|
||||
}
|
||||
}
|
||||
|
||||
static bool ParseEntityLumpString(const char *pMapEntities, int &status, size_t &position)
|
||||
{
|
||||
lastParseResult = lumpmanager->Parse(pMapEntities);
|
||||
status = static_cast<int>(lastParseResult.m_Status);
|
||||
position = static_cast<size_t>(lastParseResult.m_Position);
|
||||
return lastParseResult;
|
||||
}
|
||||
|
||||
// returns nullptr if the original lump failed to parse
|
||||
static const char* GetEntityLumpString()
|
||||
{
|
||||
if (!lastParseResult)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return g_strMapEntities.c_str();
|
||||
}
|
||||
|
||||
// Defined in smn_filesystem.cpp.
|
||||
extern bool OnLogPrint(const char *msg);
|
||||
|
||||
@@ -170,6 +202,9 @@ static sm_logic_t logic =
|
||||
CellArray::Free,
|
||||
FromPseudoAddress,
|
||||
ToPseudoAddress,
|
||||
SetEntityLumpWritable,
|
||||
ParseEntityLumpString,
|
||||
GetEntityLumpString,
|
||||
&g_PluginSys,
|
||||
&g_ShareSys,
|
||||
&g_Extensions,
|
||||
|
||||
@@ -89,6 +89,6 @@ unsigned int UTIL_CRC32(const void *pdata, size_t data_length)
|
||||
crc = CRCTable[c] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc;
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,11 @@ static cell_t CreateArray(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
if (params[2])
|
||||
{
|
||||
array->resize(params[2]);
|
||||
if (!array->resize(params[2]))
|
||||
{
|
||||
delete array;
|
||||
return pContext->ThrowNativeError("Failed to resize array to startsize \"%u\".", params[2]);
|
||||
}
|
||||
}
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
@@ -277,7 +281,19 @@ static cell_t GetArrayString(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||
}
|
||||
|
||||
cell_t *blk = array->at(idx);
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 5)
|
||||
{
|
||||
blocknumber = (size_t)params[5];
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
|
||||
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||
size_t numWritten = 0;
|
||||
|
||||
pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
|
||||
@@ -303,7 +319,19 @@ static cell_t GetArrayArray(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||
}
|
||||
|
||||
cell_t *blk = array->at(idx);
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 5)
|
||||
{
|
||||
blocknumber = (size_t)params[5];
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
|
||||
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||
size_t indexes = array->blocksize();
|
||||
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
||||
{
|
||||
@@ -375,12 +403,30 @@ static cell_t SetArrayString(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||
}
|
||||
|
||||
cell_t *blk = array->at(idx);
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 5)
|
||||
{
|
||||
blocknumber = (size_t)params[5];
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
|
||||
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[3], &str);
|
||||
|
||||
return strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
|
||||
size_t maxlength = array->blocksize() * sizeof(cell_t);
|
||||
if (params[0] >= 4 && params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
||||
{
|
||||
maxlength = (size_t)params[4];
|
||||
}
|
||||
|
||||
return strncopy((char*)blk, str, maxlength);
|
||||
}
|
||||
|
||||
static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
|
||||
@@ -401,7 +447,19 @@ static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||
}
|
||||
|
||||
cell_t *blk = array->at(idx);
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 5)
|
||||
{
|
||||
blocknumber = (size_t)params[5];
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
|
||||
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||
size_t indexes = array->blocksize();
|
||||
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
||||
{
|
||||
@@ -529,12 +587,24 @@ static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
// the blocknumber is not guaranteed to always be passed
|
||||
size_t blocknumber = 0;
|
||||
if (params[0] >= 3)
|
||||
{
|
||||
blocknumber = (size_t)params[3];
|
||||
}
|
||||
|
||||
if (blocknumber >= array->blocksize())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||
}
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
for (unsigned int i = 0; i < array->size(); i++)
|
||||
{
|
||||
const char *array_str = (const char *)array->at(i);
|
||||
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
|
||||
if (strcmp(str, array_str) == 0)
|
||||
{
|
||||
return (cell_t) i;
|
||||
|
||||
@@ -83,6 +83,22 @@ static cell_t CreateStack(IPluginContext *pContext, const cell_t *params)
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t ClearStack(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellArray *array;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
array->clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t CloneStack(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellArray *oldArray;
|
||||
@@ -224,9 +240,9 @@ static cell_t PopStackCell(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (idx >= array->blocksize() * 4)
|
||||
if (idx >= array->blocksize() * sizeof(cell_t))
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
|
||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
|
||||
}
|
||||
*buffer = (cell_t)*((char *)blk + idx);
|
||||
}
|
||||
@@ -340,8 +356,8 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
|
||||
rval = blk[idx];
|
||||
} else {
|
||||
if (idx >= array->blocksize() * 4)
|
||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
|
||||
if (idx >= array->blocksize() * sizeof(cell_t))
|
||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
|
||||
rval = (cell_t)*((char *)blk + idx);
|
||||
}
|
||||
|
||||
@@ -349,6 +365,32 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
|
||||
return rval;
|
||||
}
|
||||
|
||||
static cell_t ArrayStack_Top(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||
if (!array.Ok())
|
||||
return 0;
|
||||
|
||||
if (array->size() == 0)
|
||||
return pContext->ThrowNativeError("stack is empty");
|
||||
|
||||
cell_t *blk = array->at(array->size() - 1);
|
||||
size_t idx = (size_t)params[2];
|
||||
|
||||
cell_t rval;
|
||||
if (params[3] == 0) {
|
||||
if (idx >= array->blocksize())
|
||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
|
||||
rval = blk[idx];
|
||||
} else {
|
||||
if (idx >= array->blocksize() * sizeof(cell_t))
|
||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
|
||||
rval = (cell_t)*((char *)blk + idx);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||
@@ -371,6 +413,27 @@ static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *param
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t ArrayStack_TopString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||
if (!array.Ok())
|
||||
return 0;
|
||||
|
||||
if (array->size() == 0)
|
||||
return pContext->ThrowNativeError("stack is empty");
|
||||
|
||||
size_t idx = array->size() - 1;
|
||||
cell_t *blk = array->at(idx);
|
||||
|
||||
cell_t *pWritten;
|
||||
pContext->LocalToPhysAddr(params[4], &pWritten);
|
||||
|
||||
size_t numWritten;
|
||||
pContext->StringToLocalUTF8(params[2], params[3], (char *)blk, &numWritten);
|
||||
*pWritten = (cell_t)numWritten;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||
@@ -395,6 +458,29 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t ArrayStack_TopArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||
if (!array.Ok())
|
||||
return 0;
|
||||
|
||||
if (array->size() == 0)
|
||||
return pContext->ThrowNativeError("stack is empty");
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[2], &addr);
|
||||
|
||||
size_t idx = array->size() - 1;
|
||||
cell_t *blk = array->at(idx);
|
||||
size_t indexes = array->blocksize();
|
||||
|
||||
if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
|
||||
indexes = params[3];
|
||||
|
||||
memcpy(addr, blk, sizeof(cell_t) * indexes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
@@ -410,6 +496,21 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
|
||||
return array->blocksize();
|
||||
}
|
||||
|
||||
static cell_t GetStackSize(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
CellArray *array;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
return array->size();
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(cellStackNatives)
|
||||
{
|
||||
{"CreateStack", CreateStack},
|
||||
@@ -425,15 +526,20 @@ REGISTER_NATIVES(cellStackNatives)
|
||||
|
||||
// Transitional syntax support.
|
||||
{"ArrayStack.ArrayStack", CreateStack},
|
||||
{"ArrayStack.Clear", ClearStack},
|
||||
{"ArrayStack.Clone", CloneStack},
|
||||
{"ArrayStack.Pop", ArrayStack_Pop},
|
||||
{"ArrayStack.Top", ArrayStack_Top},
|
||||
{"ArrayStack.PopString", ArrayStack_PopString},
|
||||
{"ArrayStack.TopString", ArrayStack_TopString},
|
||||
{"ArrayStack.PopArray", ArrayStack_PopArray},
|
||||
{"ArrayStack.TopArray", ArrayStack_TopArray},
|
||||
{"ArrayStack.Push", PushStackCell},
|
||||
{"ArrayStack.PushString", PushStackString},
|
||||
{"ArrayStack.PushArray", PushStackArray},
|
||||
{"ArrayStack.Empty.get", IsStackEmpty},
|
||||
{"ArrayStack.BlockSize.get", GetStackBlockSize},
|
||||
{"ArrayStack.Length.get", GetStackSize},
|
||||
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
+173
-2
@@ -32,6 +32,9 @@
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include "common_logic.h"
|
||||
#include "Logger.h"
|
||||
|
||||
@@ -56,6 +59,7 @@
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <bridge/include/IExtensionBridge.h>
|
||||
#include <sh_vector.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
@@ -114,6 +118,71 @@ public:
|
||||
}
|
||||
} g_CoreNativeHelpers;
|
||||
|
||||
/**
|
||||
* @brief Nearly identical to the standard core plugin iterator
|
||||
* with one key difference. Next doesn't increment the counter
|
||||
* the first time it is ran. This is a hack for the methodmap..
|
||||
*/
|
||||
class CMMPluginIterator
|
||||
: public IPluginIterator,
|
||||
public IPluginsListener
|
||||
{
|
||||
public:
|
||||
CMMPluginIterator(const CVector<SMPlugin *> *list)
|
||||
: m_hasStarted(false)
|
||||
{
|
||||
for(auto iter = list->begin(); iter != list->end(); ++iter) {
|
||||
m_list.push_back(*iter);
|
||||
}
|
||||
scripts->FreePluginList(list);
|
||||
|
||||
m_current = m_list.begin();
|
||||
|
||||
scripts->AddPluginsListener(this);
|
||||
}
|
||||
|
||||
virtual ~CMMPluginIterator()
|
||||
{
|
||||
scripts->RemovePluginsListener(this);
|
||||
}
|
||||
virtual bool MorePlugins() override
|
||||
{
|
||||
return (m_current != m_list.end());
|
||||
}
|
||||
virtual IPlugin *GetPlugin() override
|
||||
{
|
||||
return *m_current;
|
||||
}
|
||||
virtual void NextPlugin() override
|
||||
{
|
||||
if(!m_hasStarted)
|
||||
{
|
||||
m_hasStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_current++;
|
||||
}
|
||||
virtual void Release() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void OnPluginDestroyed(IPlugin *plugin) override
|
||||
{
|
||||
if (*m_current == plugin)
|
||||
m_current = m_list.erase(m_current);
|
||||
else
|
||||
m_list.remove(static_cast<SMPlugin *>(plugin));
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<SMPlugin *> m_list;
|
||||
std::list<SMPlugin *>::iterator m_current;
|
||||
bool m_hasStarted;
|
||||
};
|
||||
|
||||
void LogAction(Handle_t hndl, int type, int client, int target, const char *message)
|
||||
{
|
||||
if (g_OnLogAction->GetFunctionCount())
|
||||
@@ -146,7 +215,7 @@ void LogAction(Handle_t hndl, int type, int client, int target, const char *mess
|
||||
g_Logger.LogMessage("[%s] %s", logtag, message);
|
||||
}
|
||||
|
||||
static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
|
||||
static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char buffer[512];
|
||||
|
||||
@@ -206,6 +275,49 @@ static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ParseTime(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *datetime;
|
||||
char *format;
|
||||
pContext->LocalToStringNULL(params[1], &datetime);
|
||||
pContext->LocalToStringNULL(params[2], &format);
|
||||
|
||||
if (format == NULL)
|
||||
{
|
||||
format = const_cast<char *>(bridge->GetCvarString(g_datetime_format));
|
||||
}
|
||||
else if (!format[0])
|
||||
{
|
||||
return pContext->ThrowNativeError("Time format string cannot be empty.");
|
||||
}
|
||||
if (!datetime || !datetime[0])
|
||||
{
|
||||
return pContext->ThrowNativeError("Date/time string cannot be empty.");
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/33542189
|
||||
std::tm t{};
|
||||
std::istringstream input(datetime);
|
||||
|
||||
auto previousLocale = input.imbue(std::locale::classic());
|
||||
input >> std::get_time(&t, format);
|
||||
bool failed = input.fail();
|
||||
input.imbue(previousLocale);
|
||||
|
||||
if (failed)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid date/time string or time format.");
|
||||
}
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return _mkgmtime(&t);
|
||||
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
return timegm(&t);
|
||||
#else
|
||||
return pContext->ThrowNativeError("Platform has no implemented UTC conversion for std::tm to std::time_t");
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPluginIterator *iter = scripts->GetPluginIterator();
|
||||
@@ -264,6 +376,60 @@ static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params)
|
||||
return pPlugin->GetMyHandle();
|
||||
}
|
||||
|
||||
static cell_t PluginIterator_Create(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPluginIterator *iter = new CMMPluginIterator(scripts->ListPlugins());
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
iter->Release();
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t PluginIterator_Next(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent};
|
||||
HandleError err{};
|
||||
IPluginIterator *pIter = nullptr;
|
||||
|
||||
if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
if(!pIter->MorePlugins())
|
||||
return 0;
|
||||
|
||||
pIter->NextPlugin();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t PluginIterator_Plugin_get(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent};
|
||||
HandleError err{};
|
||||
IPluginIterator *pIter = nullptr;
|
||||
|
||||
if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
IPlugin *pPlugin = pIter->GetPlugin();
|
||||
if (!pPlugin)
|
||||
{
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return pPlugin->GetMyHandle();
|
||||
}
|
||||
|
||||
IPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl)
|
||||
{
|
||||
if (hndl == BAD_HANDLE)
|
||||
@@ -967,9 +1133,10 @@ REGISTER_NATIVES(coreNatives)
|
||||
{"ThrowError", ThrowError},
|
||||
{"GetTime", GetTime},
|
||||
{"FormatTime", FormatTime},
|
||||
{"ParseTime", ParseTime},
|
||||
{"GetPluginIterator", GetPluginIterator},
|
||||
{"MorePlugins", MorePlugins},
|
||||
{"ReadPlugin", ReadPlugin},
|
||||
{"ReadPlugin", ReadPlugin},
|
||||
{"GetPluginStatus", GetPluginStatus},
|
||||
{"GetPluginFilename", GetPluginFilename},
|
||||
{"IsPluginDebugging", IsPluginDebugging},
|
||||
@@ -1000,5 +1167,9 @@ REGISTER_NATIVES(coreNatives)
|
||||
{"FrameIterator.LineNumber.get", FrameIterator_LineNumber},
|
||||
{"FrameIterator.GetFunctionName", FrameIterator_GetFunctionName},
|
||||
{"FrameIterator.GetFilePath", FrameIterator_GetFilePath},
|
||||
|
||||
{"PluginIterator.PluginIterator", PluginIterator_Create},
|
||||
{"PluginIterator.Next", PluginIterator_Next},
|
||||
{"PluginIterator.Plugin.get", PluginIterator_Plugin_get},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -1787,10 +1787,10 @@ static cell_t SQL_ExecuteTransaction(IPluginContext *pContext, const cell_t *par
|
||||
|
||||
IPluginFunction *onSuccess = NULL;
|
||||
IPluginFunction *onError = NULL;
|
||||
if (params[3] != -1 && ((onSuccess = pContext->GetFunctionById(params[3])) == NULL))
|
||||
return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
|
||||
if (params[4] != -1 && ((onError = pContext->GetFunctionById(params[4])) == NULL))
|
||||
return pContext->ThrowNativeError("Function id %x is invalid", params[4]);
|
||||
if (!pContext->GetFunctionByIdOrNull(params[3], &onSuccess))
|
||||
return 0;
|
||||
if (!pContext->GetFunctionByIdOrNull(params[4], &onError))
|
||||
return 0;
|
||||
|
||||
cell_t data = params[5];
|
||||
PrioQueueLevel priority = PrioQueue_Normal;
|
||||
|
||||
@@ -244,7 +244,19 @@ static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *para
|
||||
pDataPack->RemoveItem();
|
||||
}
|
||||
|
||||
pDataPack->PackFunction(params[2]);
|
||||
cell_t funcid = params[2];
|
||||
if (pContext->IsNullFunctionId(funcid))
|
||||
{
|
||||
pDataPack->PackFunction(0);
|
||||
}
|
||||
else if (funcid <= 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDataPack->PackFunction(funcid);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -365,7 +377,12 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param
|
||||
return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::Function);
|
||||
}
|
||||
|
||||
return pDataPack->ReadFunction();
|
||||
cell_t funcid = pDataPack->ReadFunction();
|
||||
if (!funcid)
|
||||
{
|
||||
return pContext->GetNullFunctionValue();
|
||||
}
|
||||
return funcid;
|
||||
}
|
||||
|
||||
static cell_t smn_ReadPackCellArray(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* Entity Lump Manager
|
||||
* Copyright (C) 2021-2022 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 "HandleSys.h"
|
||||
#include "common_logic.h"
|
||||
|
||||
#include "LumpManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
HandleType_t g_EntityLumpEntryType;
|
||||
|
||||
std::string g_strMapEntities;
|
||||
bool g_bLumpAvailableForWriting = false;
|
||||
|
||||
static EntityLumpManager s_LumpManager;
|
||||
EntityLumpManager *lumpmanager = &s_LumpManager;
|
||||
|
||||
class LumpManagerNatives :
|
||||
public IHandleTypeDispatch,
|
||||
public SMGlobalClass
|
||||
{
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized()
|
||||
{
|
||||
g_EntityLumpEntryType = handlesys->CreateType("EntityLumpEntry", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
}
|
||||
void OnSourceModShutdown()
|
||||
{
|
||||
handlesys->RemoveType(g_EntityLumpEntryType, g_pCoreIdent);
|
||||
}
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void* object)
|
||||
{
|
||||
if (type == g_EntityLumpEntryType)
|
||||
{
|
||||
delete reinterpret_cast<std::weak_ptr<EntityLumpEntry>*>(object);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static LumpManagerNatives s_LumpManagerNatives;
|
||||
|
||||
cell_t sm_LumpManagerGet(IPluginContext *pContext, const cell_t *params) {
|
||||
int index = params[1];
|
||||
if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* pReference = new std::weak_ptr<EntityLumpEntry>;
|
||||
*pReference = lumpmanager->Get(index);
|
||||
|
||||
return handlesys->CreateHandle(g_EntityLumpEntryType, pReference,
|
||||
pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
}
|
||||
|
||||
cell_t sm_LumpManagerErase(IPluginContext *pContext, const cell_t *params) {
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLump.Erase() outside of OnMapInit");
|
||||
}
|
||||
|
||||
int index = params[1];
|
||||
if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
lumpmanager->Erase(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpManagerInsert(IPluginContext *pContext, const cell_t *params) {
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLump.Insert() outside of OnMapInit");
|
||||
}
|
||||
|
||||
int index = params[1];
|
||||
if (index < 0 || index > static_cast<int>(lumpmanager->Length())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
lumpmanager->Insert(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpManagerAppend(IPluginContext *pContext, const cell_t *params) {
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLump.Append() outside of OnMapInit");
|
||||
}
|
||||
return lumpmanager->Append();
|
||||
}
|
||||
|
||||
cell_t sm_LumpManagerLength(IPluginContext *pContext, const cell_t *params) {
|
||||
return lumpmanager->Length();
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryGet(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
auto entry = entryref->lock();
|
||||
|
||||
int index = params[2];
|
||||
if (index < 0 || index >= static_cast<int>(entry->size())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
const auto& pair = (*entry)[index];
|
||||
|
||||
size_t nBytes;
|
||||
pContext->StringToLocalUTF8(params[3], params[4], pair.first.c_str(), &nBytes);
|
||||
pContext->StringToLocalUTF8(params[5], params[6], pair.second.c_str(), &nBytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryUpdate(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Update() outside of OnMapInit");
|
||||
}
|
||||
|
||||
auto entry = entryref->lock();
|
||||
|
||||
int index = params[2];
|
||||
if (index < 0 || index >= static_cast<int>(entry->size())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
char *key, *value;
|
||||
pContext->LocalToStringNULL(params[3], &key);
|
||||
pContext->LocalToStringNULL(params[4], &value);
|
||||
|
||||
auto& pair = (*entry)[index];
|
||||
if (key != nullptr) {
|
||||
pair.first = key;
|
||||
}
|
||||
if (value != nullptr) {
|
||||
pair.second = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryInsert(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Insert() outside of OnMapInit");
|
||||
}
|
||||
|
||||
auto entry = entryref->lock();
|
||||
|
||||
int index = params[2];
|
||||
if (index < 0 || index > static_cast<int>(entry->size())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
char *key, *value;
|
||||
pContext->LocalToString(params[3], &key);
|
||||
pContext->LocalToString(params[4], &value);
|
||||
|
||||
entry->emplace(entry->begin() + index, key, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryErase(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Erase() outside of OnMapInit");
|
||||
}
|
||||
|
||||
auto entry = entryref->lock();
|
||||
|
||||
int index = params[2];
|
||||
if (index < 0 || index >= static_cast<int>(entry->size())) {
|
||||
return pContext->ThrowNativeError("Invalid index %d", index);
|
||||
}
|
||||
|
||||
entry->erase(entry->begin() + index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryAppend(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
if (!g_bLumpAvailableForWriting) {
|
||||
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Append() outside of OnMapInit");
|
||||
}
|
||||
|
||||
auto entry = entryref->lock();
|
||||
|
||||
char *key, *value;
|
||||
pContext->LocalToString(params[2], &key);
|
||||
pContext->LocalToString(params[3], &value);
|
||||
|
||||
entry->emplace_back(key, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryFindKey(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
// start from the index after the current one
|
||||
int start = params[3] + 1;
|
||||
|
||||
auto entry = entryref->lock();
|
||||
|
||||
if (start < 0 || start >= static_cast<int>(entry->size())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *key;
|
||||
pContext->LocalToString(params[2], &key);
|
||||
|
||||
auto matches_key = [&key](std::pair<std::string,std::string> pair) {
|
||||
return pair.first == key;
|
||||
};
|
||||
|
||||
auto result = std::find_if(entry->begin() + start, entry->end(), matches_key);
|
||||
|
||||
if (result == entry->end()) {
|
||||
return -1;
|
||||
}
|
||||
return std::distance(entry->begin(), result);
|
||||
}
|
||||
|
||||
cell_t sm_LumpEntryLength(IPluginContext *pContext, const cell_t *params) {
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
HandleError err;
|
||||
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
|
||||
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
|
||||
}
|
||||
|
||||
if (entryref->expired()) {
|
||||
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
|
||||
}
|
||||
|
||||
auto entry = entryref->lock();
|
||||
return entry->size();
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(entityLumpNatives)
|
||||
{
|
||||
{ "EntityLump.Get", sm_LumpManagerGet },
|
||||
{ "EntityLump.Erase", sm_LumpManagerErase },
|
||||
{ "EntityLump.Insert", sm_LumpManagerInsert },
|
||||
{ "EntityLump.Append", sm_LumpManagerAppend },
|
||||
{ "EntityLump.Length", sm_LumpManagerLength },
|
||||
|
||||
{ "EntityLumpEntry.Get", sm_LumpEntryGet },
|
||||
{ "EntityLumpEntry.Update", sm_LumpEntryUpdate },
|
||||
{ "EntityLumpEntry.Insert", sm_LumpEntryInsert },
|
||||
{ "EntityLumpEntry.Erase", sm_LumpEntryErase },
|
||||
{ "EntityLumpEntry.Append", sm_LumpEntryAppend },
|
||||
{ "EntityLumpEntry.FindKey", sm_LumpEntryFindKey },
|
||||
{ "EntityLumpEntry.Length.get", sm_LumpEntryLength },
|
||||
|
||||
{NULL, NULL}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2022-2022 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_ENTITYLUMP_H_
|
||||
#define _INCLUDE_SOURCEMOD_ENTITYLUMP_H_
|
||||
|
||||
#include <IHandleSys.h>
|
||||
#include "LumpManager.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
extern std::string g_strMapEntities;
|
||||
extern bool g_bLumpAvailableForWriting;
|
||||
extern EntityLumpManager *lumpmanager;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_ENTITYLUMP_H_
|
||||
@@ -366,6 +366,33 @@ static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
static cell_t GetNativeFunction(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||
{
|
||||
return pContext->ThrowNativeError("Not called from inside a native function");
|
||||
}
|
||||
|
||||
cell_t param = params[1];
|
||||
if (param < 1 || param > s_curparams[0])
|
||||
{
|
||||
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
|
||||
}
|
||||
|
||||
cell_t funcid = s_curparams[param];
|
||||
if (s_curcaller->IsNullFunctionId(funcid))
|
||||
{
|
||||
// see alliedmodders/sourcepawn#912, alliedmodders/sourcemod#2068
|
||||
// convert null function to receiver's expected value so equality checks against INVALID_FUNCTION pass
|
||||
return pContext->GetNullFunctionValue();
|
||||
}
|
||||
else if (funcid <= 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
return funcid;
|
||||
}
|
||||
|
||||
static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if (!s_curnative || (s_curnative->ctx != pContext))
|
||||
@@ -414,7 +441,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
|
||||
DetectExceptions eh(pContext);
|
||||
written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
|
||||
if (eh.HasException())
|
||||
return 0;
|
||||
return pContext->GetLastNativeError();
|
||||
}
|
||||
|
||||
cell_t *addr;
|
||||
@@ -483,7 +510,7 @@ REGISTER_NATIVES(nativeNatives)
|
||||
{"GetNativeArray", GetNativeArray},
|
||||
{"GetNativeCell", GetNativeCell},
|
||||
{"GetNativeCellRef", GetNativeCellRef},
|
||||
{"GetNativeFunction", GetNativeCell},
|
||||
{"GetNativeFunction", GetNativeFunction},
|
||||
{"GetNativeString", GetNativeString},
|
||||
{"GetNativeStringLength", GetNativeStringLength},
|
||||
{"FormatNativeString", FormatNativeString},
|
||||
|
||||
@@ -73,6 +73,7 @@ class FileObject
|
||||
public:
|
||||
virtual ~FileObject()
|
||||
{}
|
||||
virtual size_t Size() = 0;
|
||||
virtual size_t Read(void *pOut, int size) = 0;
|
||||
virtual char *ReadLine(char *pOut, int size) = 0;
|
||||
virtual size_t Write(const void *pData, int size) = 0;
|
||||
@@ -119,6 +120,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Size() override {
|
||||
return (size_t)bridge->filesystem->Size(handle_);
|
||||
}
|
||||
|
||||
size_t Read(void *pOut, int size) override {
|
||||
return (size_t)bridge->filesystem->Read(pOut, size, handle_);
|
||||
}
|
||||
@@ -183,6 +188,30 @@ public:
|
||||
return unlink(path) == 0;
|
||||
}
|
||||
|
||||
size_t Size() override {
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
struct _stat s;
|
||||
int fd = _fileno(fp_);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
if (_fstat(fd, &s) != 0)
|
||||
return -1;
|
||||
if (s.st_mode & S_IFREG)
|
||||
return static_cast<size_t>(s.st_size);
|
||||
return -1;
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
int fd = fileno(fp_);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
if (fstat(fd, &s) != 0)
|
||||
return -1;
|
||||
if (S_ISREG(s.st_mode))
|
||||
return static_cast<size_t>(s.st_size);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t Read(void *pOut, int size) override {
|
||||
return fread(pOut, 1, size, fp_);
|
||||
}
|
||||
@@ -288,6 +317,10 @@ public:
|
||||
}
|
||||
virtual bool LogPrint(const char *msg)
|
||||
{
|
||||
if (!g_pLogHook) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cell_t result = 0;
|
||||
g_pLogHook->PushString(msg);
|
||||
g_pLogHook->Execute(&result);
|
||||
@@ -610,7 +643,7 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
|
||||
g_pSM->BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
|
||||
return (MoveFileExA(old_realpath, new_realpath, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) ? 1 : 0;
|
||||
#elif defined PLATFORM_POSIX
|
||||
return (rename(old_realpath, new_realpath)) ? 0 : 1;
|
||||
#endif
|
||||
@@ -722,6 +755,39 @@ static cell_t sm_SetFilePermissions(IPluginContext *pContext, const cell_t *para
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell_t sm_GetFilePermissions(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *name;
|
||||
char realpath[PLATFORM_MAX_PATH];
|
||||
|
||||
pContext->LocalToString(params[1], &name);
|
||||
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
|
||||
|
||||
cell_t *mask;
|
||||
pContext->LocalToPhysAddr(params[2], &mask);
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
struct _stat buffer;
|
||||
cell_t valid = _stat(realpath, &buffer) == 0;
|
||||
|
||||
if ((buffer.st_mode & _S_IREAD) != 0) {
|
||||
*mask |= (FPERM_U_READ|FPERM_G_READ|FPERM_O_READ)|(FPERM_U_EXEC|FPERM_G_EXEC|FPERM_O_EXEC);
|
||||
}
|
||||
|
||||
if ((buffer.st_mode & _S_IWRITE) != 0) {
|
||||
*mask |= (FPERM_U_WRITE|FPERM_G_WRITE|FPERM_O_WRITE);
|
||||
}
|
||||
|
||||
return valid;
|
||||
#else
|
||||
struct stat buffer;
|
||||
cell_t valid = stat(realpath, &buffer) == 0;
|
||||
|
||||
*mask = buffer.st_mode;
|
||||
return valid;
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *name;
|
||||
@@ -1125,6 +1191,15 @@ static cell_t sm_RemoveGameLogHook(IPluginContext *pContext, const cell_t *param
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t File_Size(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<FileObject> file(pContext, params[1], g_FileType);
|
||||
if (!file.Ok())
|
||||
return -1;
|
||||
|
||||
return file->Size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static cell_t File_ReadTyped(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
@@ -1186,6 +1261,7 @@ REGISTER_NATIVES(filesystem)
|
||||
{"RemoveGameLogHook", sm_RemoveGameLogHook},
|
||||
{"CreateDirectory", sm_CreateDirectory},
|
||||
{"SetFilePermissions", sm_SetFilePermissions},
|
||||
{"GetFilePermissions", sm_GetFilePermissions},
|
||||
|
||||
{"File.ReadLine", sm_ReadFileLine},
|
||||
{"File.Read", sm_ReadFile},
|
||||
@@ -1197,6 +1273,7 @@ REGISTER_NATIVES(filesystem)
|
||||
{"File.Seek", sm_FileSeek},
|
||||
{"File.Flush", sm_FlushFile},
|
||||
{"File.Position.get", sm_FilePosition},
|
||||
{"File.Size", File_Size},
|
||||
{"File.ReadInt8", File_ReadTyped<int8_t>},
|
||||
{"File.ReadUint8", File_ReadTyped<uint8_t>},
|
||||
{"File.ReadInt16", File_ReadTyped<int16_t>},
|
||||
|
||||
@@ -231,6 +231,13 @@ static cell_t sm_FloatFraction(IPluginContext *pCtx, const cell_t *params)
|
||||
return sp_ftoc(val);
|
||||
}
|
||||
|
||||
static cell_t sm_FloatMod(IPluginContext* pCtx, const cell_t* params)
|
||||
{
|
||||
float val = fmodf(sp_ctof(params[1]), sp_ctof(params[2]));
|
||||
|
||||
return sp_ftoc(val);
|
||||
}
|
||||
|
||||
static cell_t sm_Sine(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
float val = sp_ctof(params[1]);
|
||||
@@ -358,10 +365,16 @@ REGISTER_NATIVES(floatnatives)
|
||||
{"FloatAdd", sm_FloatAdd},
|
||||
{"FloatSub", sm_FloatSub},
|
||||
{"FloatFraction", sm_FloatFraction},
|
||||
{"FloatMod", sm_FloatMod},
|
||||
{"RoundToZero", sm_RoundToZero},
|
||||
{"RoundToCeil", sm_RoundToCeil},
|
||||
{"RoundToFloor", sm_RoundToFloor},
|
||||
{"RoundToNearest", sm_RoundToNearest},
|
||||
{"__FLOAT_MUL__", sm_FloatMul},
|
||||
{"__FLOAT_DIV__", sm_FloatDiv},
|
||||
{"__FLOAT_ADD__", sm_FloatAdd},
|
||||
{"__FLOAT_SUB__", sm_FloatSub},
|
||||
{"__FLOAT_MOD__", sm_FloatMod},
|
||||
{"__FLOAT_GT__", sm_FloatGt},
|
||||
{"__FLOAT_GE__", sm_FloatGe},
|
||||
{"__FLOAT_LT__", sm_FloatLt},
|
||||
|
||||
@@ -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,6 +36,9 @@
|
||||
#include <IHandleSys.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <ISourceMod.h>
|
||||
#include <amtl/am-autoptr.h>
|
||||
#include "ShareSys.h"
|
||||
#include "NativeInvoker.h"
|
||||
|
||||
HandleType_t g_GlobalFwdType = 0;
|
||||
HandleType_t g_PrivateFwdType = 0;
|
||||
@@ -44,8 +47,9 @@ static bool s_CallStarted = false;
|
||||
static ICallable *s_pCallable = NULL;
|
||||
static IPluginFunction *s_pFunction = NULL;
|
||||
static IForward *s_pForward = NULL;
|
||||
static NativeInvoker *s_pInvoker = NULL;
|
||||
|
||||
class ForwardNativeHelpers :
|
||||
class ForwardNativeHelpers :
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
{
|
||||
@@ -103,6 +107,9 @@ inline void ResetCall()
|
||||
s_pFunction = NULL;
|
||||
s_pForward = NULL;
|
||||
s_pCallable = NULL;
|
||||
if(s_pInvoker)
|
||||
delete s_pInvoker;
|
||||
s_pInvoker = NULL;
|
||||
}
|
||||
|
||||
static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
|
||||
@@ -131,7 +138,7 @@ static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *param
|
||||
if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND)
|
||||
{
|
||||
/* Return INVALID_FUNCTION if not found */
|
||||
return -1;
|
||||
return pContext->GetNullFunctionValue();
|
||||
}
|
||||
|
||||
/* Return function ID */
|
||||
@@ -148,7 +155,7 @@ static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *par
|
||||
{
|
||||
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
|
||||
}
|
||||
|
||||
|
||||
pContext->LocalToString(params[1], &name);
|
||||
|
||||
cell_t *addr;
|
||||
@@ -228,11 +235,15 @@ static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
}
|
||||
|
||||
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
|
||||
|
||||
cell_t funcid = params[3];
|
||||
if (funcid <= 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(funcid);
|
||||
if (!pFunction)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
|
||||
return pForward->AddFunction(pFunction);
|
||||
@@ -265,11 +276,15 @@ static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *param
|
||||
}
|
||||
}
|
||||
|
||||
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
|
||||
|
||||
cell_t funcid = params[3];
|
||||
if (funcid <= 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(funcid);
|
||||
if (!pFunction)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
|
||||
return pForward->RemoveFunction(pFunction);
|
||||
@@ -327,11 +342,15 @@ static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *param
|
||||
}
|
||||
}
|
||||
|
||||
s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]);
|
||||
|
||||
cell_t funcid = params[2];
|
||||
if (funcid <= 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(funcid);
|
||||
if (!s_pFunction)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
|
||||
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
|
||||
}
|
||||
|
||||
s_pCallable = static_cast<ICallable *>(s_pFunction);
|
||||
@@ -367,6 +386,27 @@ static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_CallStartNative(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
ResetCall();
|
||||
|
||||
char *name;
|
||||
pContext->LocalToString(params[1], &name);
|
||||
|
||||
ke::RefPtr<Native> pNative = g_ShareSys.FindNative(name);
|
||||
|
||||
if (!pNative)
|
||||
return 0;//pContext->ThrowNativeError("Invalid native \"%s\"", name);
|
||||
|
||||
s_pInvoker = new NativeInvoker(pContext, pNative);
|
||||
|
||||
s_pCallable = static_cast<ICallable *>(s_pInvoker);
|
||||
|
||||
s_CallStarted = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int err;
|
||||
@@ -657,6 +697,39 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
|
||||
IForward *pForward = s_pForward;
|
||||
ResetCall();
|
||||
err = pForward->Execute(result, NULL);
|
||||
} else if (s_pInvoker) {
|
||||
err = s_pInvoker->Execute(result);
|
||||
ResetCall();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static cell_t sm_CallFinishEx(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int err = SP_ERROR_NOT_RUNNABLE;
|
||||
cell_t *result;
|
||||
|
||||
if (!s_CallStarted)
|
||||
{
|
||||
return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
|
||||
}
|
||||
|
||||
pContext->LocalToPhysAddr(params[1], &result);
|
||||
|
||||
// Note: Execute() swallows exceptions, so this is okay.
|
||||
if (s_pFunction)
|
||||
{
|
||||
IPluginFunction *pFunction = s_pFunction;
|
||||
ResetCall();
|
||||
err = pFunction->Execute(result, params[2], params[3]);
|
||||
} else if (s_pForward) {
|
||||
IForward *pForward = s_pForward;
|
||||
ResetCall();
|
||||
err = pForward->Execute(result, NULL);
|
||||
} else if (s_pInvoker) {
|
||||
err = s_pInvoker->Execute(result, params[2], params[3]);
|
||||
ResetCall();
|
||||
}
|
||||
|
||||
return err;
|
||||
@@ -743,6 +816,7 @@ REGISTER_NATIVES(functionNatives)
|
||||
{"RemoveAllFromForward", sm_RemoveAllFromForward},
|
||||
{"Call_StartFunction", sm_CallStartFunction},
|
||||
{"Call_StartForward", sm_CallStartForward},
|
||||
{"Call_StartNative", sm_CallStartNative},
|
||||
{"Call_PushCell", sm_CallPushCell},
|
||||
{"Call_PushCellRef", sm_CallPushCellRef},
|
||||
{"Call_PushFloat", sm_CallPushFloat},
|
||||
@@ -754,6 +828,7 @@ REGISTER_NATIVES(functionNatives)
|
||||
{"Call_PushNullVector", sm_CallPushNullVector},
|
||||
{"Call_PushNullString", sm_CallPushNullString},
|
||||
{"Call_Finish", sm_CallFinish},
|
||||
{"Call_FinishEx", sm_CallFinishEx},
|
||||
{"Call_Cancel", sm_CallCancel},
|
||||
{"RequestFrame", sm_AddFrameAction},
|
||||
|
||||
|
||||
@@ -119,5 +119,7 @@ REGISTER_NATIVES(handles)
|
||||
{"CloseHandle", sm_CloseHandle},
|
||||
{"CloneHandle", sm_CloneHandle},
|
||||
{"GetMyHandle", sm_GetMyHandle},
|
||||
{"Handle.Close", sm_CloseHandle},
|
||||
{"Handle.~Handle", sm_CloseHandle},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -144,6 +144,18 @@ static cell_t sm_SetClientLanguage(IPluginContext *pContext, const cell_t *param
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_GetClientOriginalLanguage(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
|
||||
|
||||
if (!player || !player->IsConnected())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index %d", params[1]);
|
||||
}
|
||||
|
||||
return player->GetOriginalLanguageId();
|
||||
}
|
||||
|
||||
static cell_t sm_GetLanguageByCode(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *code;
|
||||
@@ -181,6 +193,7 @@ REGISTER_NATIVES(langNatives)
|
||||
{"GetLanguageCount", sm_GetLanguageCount},
|
||||
{"GetLanguageInfo", sm_GetLanguageInfo},
|
||||
{"SetClientLanguage", sm_SetClientLanguage},
|
||||
{"GetClientOriginalLanguage", sm_GetClientOriginalLanguage},
|
||||
{"GetLanguageByCode", sm_GetLanguageByCode},
|
||||
{"GetLanguageByName", sm_GetLanguageByName},
|
||||
{NULL, NULL},
|
||||
|
||||
@@ -592,7 +592,10 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
if (!libsys->FileTime(pMapList->path, FileTime_LastChange, &last_time)
|
||||
char realpath[PLATFORM_MAX_PATH];
|
||||
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", pMapList->path);
|
||||
|
||||
if (!libsys->FileTime(realpath, FileTime_LastChange, &last_time)
|
||||
|| last_time > pMapList->last_modified_time)
|
||||
{
|
||||
/* Reparse */
|
||||
|
||||
+47
-103
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@@ -141,10 +141,6 @@ public:
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||
bool OnSetHandlerOption(const char *option, const void *data);
|
||||
#if 0
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
|
||||
#endif
|
||||
private:
|
||||
cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0);
|
||||
private:
|
||||
@@ -496,99 +492,51 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *
|
||||
unsigned int winning_votes = results->item_list[0].count;
|
||||
|
||||
DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
|
||||
} else {
|
||||
IPluginContext *pContext = m_pVoteResults->GetParentContext();
|
||||
bool no_call = false;
|
||||
int err;
|
||||
return;
|
||||
}
|
||||
|
||||
/* First array */
|
||||
cell_t client_array_address = -1;
|
||||
cell_t *client_array_base = NULL;
|
||||
cell_t client_array_size = results->num_clients + (results->num_clients * 2);
|
||||
if (client_array_size)
|
||||
{
|
||||
if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
|
||||
no_call = true;
|
||||
} else {
|
||||
cell_t target_offs = sizeof(cell_t) * results->num_clients;
|
||||
cell_t *cur_index = client_array_base;
|
||||
cell_t *cur_array;
|
||||
for (unsigned int i=0; i<results->num_clients; i++)
|
||||
{
|
||||
/* Copy the array index */
|
||||
*cur_index = target_offs;
|
||||
/* Get the current array address */
|
||||
cur_array = (cell_t *)((char *)cur_index + target_offs);
|
||||
/* Store information */
|
||||
cur_array[0] = results->client_list[i].client;
|
||||
cur_array[1] = results->client_list[i].item;
|
||||
/* Adjust for the new target by subtracting one indirection
|
||||
* and adding one array.
|
||||
*/
|
||||
target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
|
||||
cur_index++;
|
||||
}
|
||||
}
|
||||
IPluginContext *pContext = m_pVoteResults->GetParentContext();
|
||||
AutoEnterHeapScope heap_scope(pContext);
|
||||
|
||||
/* First array */
|
||||
cell_t client_array_address = -1;
|
||||
if (cell_t client_array_size = results->num_clients * 2) {
|
||||
auto init = std::make_unique<cell_t[]>(client_array_size);
|
||||
for (unsigned int i = 0; i < results->num_clients; i++) {
|
||||
init[i * 2] = results->client_list[i].client;
|
||||
init[i * 2 + 1] = results->client_list[i].item;
|
||||
}
|
||||
|
||||
/* Second array */
|
||||
cell_t item_array_address = -1;
|
||||
cell_t *item_array_base = NULL;
|
||||
cell_t item_array_size = results->num_items + (results->num_items * 2);
|
||||
if (item_array_size)
|
||||
{
|
||||
if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size);
|
||||
no_call = true;
|
||||
} else {
|
||||
cell_t target_offs = sizeof(cell_t) * results->num_items;
|
||||
cell_t *cur_index = item_array_base;
|
||||
cell_t *cur_array;
|
||||
for (unsigned int i=0; i<results->num_items; i++)
|
||||
{
|
||||
/* Copy the array index */
|
||||
*cur_index = target_offs;
|
||||
/* Get the current array address */
|
||||
cur_array = (cell_t *)((char *)cur_index + target_offs);
|
||||
/* Store information */
|
||||
cur_array[0] = results->item_list[i].item;
|
||||
cur_array[1] = results->item_list[i].count;
|
||||
/* Adjust for the new target by subtracting one indirection
|
||||
* and adding one array.
|
||||
*/
|
||||
target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
|
||||
cur_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, push everything */
|
||||
if (!no_call)
|
||||
{
|
||||
m_pVoteResults->PushCell(menu->GetHandle());
|
||||
m_pVoteResults->PushCell(results->num_votes);
|
||||
m_pVoteResults->PushCell(results->num_clients);
|
||||
m_pVoteResults->PushCell(client_array_address);
|
||||
m_pVoteResults->PushCell(results->num_items);
|
||||
m_pVoteResults->PushCell(item_array_address);
|
||||
m_pVoteResults->Execute(NULL);
|
||||
}
|
||||
|
||||
/* Free what we allocated, in reverse order as required */
|
||||
if (item_array_address != -1)
|
||||
{
|
||||
pContext->HeapPop(item_array_address);
|
||||
}
|
||||
if (client_array_address != -1)
|
||||
{
|
||||
pContext->HeapPop(client_array_address);
|
||||
if (!pContext->HeapAlloc2dArray(results->num_clients, 2, &client_array_address, init.get())) {
|
||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1,
|
||||
"Menu callback could not allocate cells for client list.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Second array */
|
||||
cell_t item_array_address = -1;
|
||||
if (cell_t item_array_size = results->num_items * 2) {
|
||||
auto init = std::make_unique<cell_t[]>(item_array_size);
|
||||
for (unsigned int i = 0; i < results->num_items; i++) {
|
||||
init[i * 2] = results->item_list[i].item;
|
||||
init[i * 2 + 1] = results->item_list[i].count;
|
||||
}
|
||||
if (!pContext->HeapAlloc2dArray(results->num_items, 2, &item_array_address, init.get())) {
|
||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1,
|
||||
"Menu callback could not allocate %d cells for item list.",
|
||||
item_array_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pVoteResults->PushCell(menu->GetHandle());
|
||||
m_pVoteResults->PushCell(results->num_votes);
|
||||
m_pVoteResults->PushCell(results->num_clients);
|
||||
m_pVoteResults->PushCell(client_array_address);
|
||||
m_pVoteResults->PushCell(results->num_items);
|
||||
m_pVoteResults->PushCell(item_array_address);
|
||||
m_pVoteResults->Execute(NULL);
|
||||
}
|
||||
|
||||
bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data)
|
||||
@@ -1014,7 +962,7 @@ static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *para
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
|
||||
return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
|
||||
@@ -1620,15 +1568,11 @@ static cell_t InternalShowMenu(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
IMenuHandler *pHandler;
|
||||
CPanelHandler *pActualHandler = NULL;
|
||||
if (params[5] != -1)
|
||||
{
|
||||
IPluginFunction *pFunction = pContext->GetFunctionById(params[5]);
|
||||
if (pFunction == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function index %x", params[5]);
|
||||
}
|
||||
pActualHandler = g_MenuHelpers.GetPanelHandler(pFunction);
|
||||
}
|
||||
IPluginFunction* func;
|
||||
if (!pContext->GetFunctionByIdOrNull(params[5], &func))
|
||||
return 0;
|
||||
if (func)
|
||||
pActualHandler = g_MenuHelpers.GetPanelHandler(func);
|
||||
|
||||
if (pActualHandler == NULL)
|
||||
{
|
||||
|
||||
+29
-26
@@ -270,18 +270,7 @@ static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params)
|
||||
return playerhelpers->GetNumPlayers();
|
||||
}
|
||||
|
||||
int maxplayers = playerhelpers->GetMaxClients();
|
||||
int count = 0;
|
||||
for (int i = 1; i <= maxplayers; ++i)
|
||||
{
|
||||
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(i);
|
||||
if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame()))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return (playerhelpers->GetNumPlayers() + count);
|
||||
return playerhelpers->GetNumClients();
|
||||
}
|
||||
|
||||
static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params)
|
||||
@@ -1471,24 +1460,23 @@ static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params
|
||||
return pPlayer->IsInKickQueue() ? 1 : 0;
|
||||
}
|
||||
|
||||
cmd_target_info_t g_ProcessTargetString_info;
|
||||
static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cmd_target_info_t info;
|
||||
|
||||
pContext->LocalToString(params[1], (char **) &info.pattern);
|
||||
info.admin = params[2];
|
||||
pContext->LocalToPhysAddr(params[3], &info.targets);
|
||||
info.max_targets = params[4];
|
||||
info.flags = params[5];
|
||||
pContext->LocalToString(params[6], &info.target_name);
|
||||
info.target_name_maxlength = params[7];
|
||||
pContext->LocalToString(params[1], (char **) &g_ProcessTargetString_info.pattern);
|
||||
g_ProcessTargetString_info.admin = params[2];
|
||||
pContext->LocalToPhysAddr(params[3], &g_ProcessTargetString_info.targets);
|
||||
g_ProcessTargetString_info.max_targets = params[4];
|
||||
g_ProcessTargetString_info.flags = params[5];
|
||||
pContext->LocalToString(params[6], &g_ProcessTargetString_info.target_name);
|
||||
g_ProcessTargetString_info.target_name_maxlength = params[7];
|
||||
|
||||
cell_t *tn_is_ml;
|
||||
pContext->LocalToPhysAddr(params[8], &tn_is_ml);
|
||||
|
||||
playerhelpers->ProcessCommandTarget(&info);
|
||||
playerhelpers->ProcessCommandTarget(&g_ProcessTargetString_info);
|
||||
|
||||
if (info.target_name_style == COMMAND_TARGETNAME_ML)
|
||||
if (g_ProcessTargetString_info.target_name_style == COMMAND_TARGETNAME_ML)
|
||||
{
|
||||
*tn_is_ml = 1;
|
||||
}
|
||||
@@ -1497,16 +1485,30 @@ static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params
|
||||
*tn_is_ml = 0;
|
||||
}
|
||||
|
||||
if (info.num_targets == 0)
|
||||
if (g_ProcessTargetString_info.num_targets == 0)
|
||||
{
|
||||
return info.reason;
|
||||
return g_ProcessTargetString_info.reason;
|
||||
}
|
||||
else
|
||||
{
|
||||
return info.num_targets;
|
||||
return g_ProcessTargetString_info.num_targets;
|
||||
}
|
||||
}
|
||||
|
||||
static cell_t GetLastProcessTargetString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *admin, *flags;
|
||||
|
||||
pContext->StringToLocalUTF8(params[1], params[2], g_ProcessTargetString_info.pattern, NULL);
|
||||
pContext->LocalToPhysAddr(params[3], &admin);
|
||||
pContext->LocalToPhysAddr(params[4], &flags);
|
||||
|
||||
*admin = g_ProcessTargetString_info.admin;
|
||||
*flags = g_ProcessTargetString_info.flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t FormatActivitySource(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int value;
|
||||
@@ -1658,6 +1660,7 @@ REGISTER_NATIVES(playernatives)
|
||||
{ "NotifyPostAdminCheck", NotifyPostAdminCheck },
|
||||
{ "IsClientInKickQueue", IsClientInKickQueue },
|
||||
{ "ProcessTargetString", ProcessTargetString },
|
||||
{ "GetLastProcessTargetString", GetLastProcessTargetString },
|
||||
{ "FormatActivitySource", FormatActivitySource },
|
||||
{ "GetClientSerial", sm_GetClientSerial },
|
||||
{ "GetClientFromSerial", sm_GetClientFromSerial },
|
||||
|
||||
+128
-15
@@ -35,6 +35,7 @@
|
||||
#include "common_logic.h"
|
||||
#include "CellArray.h"
|
||||
#include <IHandleSys.h>
|
||||
#include <amtl/am-raii.h>
|
||||
|
||||
/***********************************
|
||||
* About the double array hack *
|
||||
@@ -95,7 +96,7 @@ void sort_random(cell_t *array, cell_t size)
|
||||
{
|
||||
int n = rand() % (i + 1);
|
||||
|
||||
if (array[i] != array[n])
|
||||
if (array[i] != array[n])
|
||||
{
|
||||
array[i] ^= array[n];
|
||||
array[n] ^= array[i];
|
||||
@@ -125,7 +126,7 @@ static cell_t sm_SortIntegers(IPluginContext *pContext, const cell_t *params)
|
||||
if (type == Sort_Ascending)
|
||||
{
|
||||
qsort(array, array_size, sizeof(cell_t), sort_ints_asc);
|
||||
}
|
||||
}
|
||||
else if (type == Sort_Descending)
|
||||
{
|
||||
qsort(array, array_size, sizeof(cell_t), sort_ints_desc);
|
||||
@@ -195,7 +196,7 @@ static cell_t sm_SortFloats(IPluginContext *pContext, const cell_t *params)
|
||||
static cell_t *g_CurStringArray = NULL;
|
||||
static cell_t *g_CurRebaseMap = NULL;
|
||||
|
||||
int sort_strings_asc(const void *blk1, const void *blk2)
|
||||
int sort_strings_asc_legacy(const void *blk1, const void *blk2)
|
||||
{
|
||||
cell_t reloc1 = *(cell_t *)blk1;
|
||||
cell_t reloc2 = *(cell_t *)blk2;
|
||||
@@ -206,7 +207,7 @@ int sort_strings_asc(const void *blk1, const void *blk2)
|
||||
return strcmp(str1, str2);
|
||||
}
|
||||
|
||||
int sort_strings_desc(const void *blk1, const void *blk2)
|
||||
int sort_strings_desc_legacy(const void *blk1, const void *blk2)
|
||||
{
|
||||
cell_t reloc1 = *(cell_t *)blk1;
|
||||
cell_t reloc2 = *(cell_t *)blk2;
|
||||
@@ -217,7 +218,7 @@ int sort_strings_desc(const void *blk1, const void *blk2)
|
||||
return strcmp(str2, str1);
|
||||
}
|
||||
|
||||
static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
|
||||
static cell_t sm_SortStrings_Legacy(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *array;
|
||||
cell_t array_size = params[2];
|
||||
@@ -245,11 +246,11 @@ static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
if (type == Sort_Ascending)
|
||||
{
|
||||
qsort(array, array_size, sizeof(cell_t), sort_strings_asc);
|
||||
}
|
||||
qsort(array, array_size, sizeof(cell_t), sort_strings_asc_legacy);
|
||||
}
|
||||
else if (type == Sort_Descending)
|
||||
{
|
||||
qsort(array, array_size, sizeof(cell_t), sort_strings_desc);
|
||||
qsort(array, array_size, sizeof(cell_t), sort_strings_desc_legacy);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -275,6 +276,69 @@ static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static IPluginContext* sSortContext = nullptr;
|
||||
|
||||
int sort_strings_asc(const void *blk1, const void *blk2)
|
||||
{
|
||||
cell_t str_addr1 = *(cell_t *)blk1;
|
||||
cell_t str_addr2 = *(cell_t *)blk2;
|
||||
|
||||
char *str1;
|
||||
char *str2;
|
||||
if (sSortContext->LocalToString(str_addr1, &str1) != SP_ERROR_NONE ||
|
||||
sSortContext->LocalToString(str_addr2, &str2) != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strcmp(str1, str2);
|
||||
}
|
||||
|
||||
int sort_strings_desc(const void *blk1, const void *blk2)
|
||||
{
|
||||
cell_t str_addr1 = *(cell_t *)blk1;
|
||||
cell_t str_addr2 = *(cell_t *)blk2;
|
||||
|
||||
char *str1;
|
||||
char *str2;
|
||||
if (sSortContext->LocalToString(str_addr1, &str1) != SP_ERROR_NONE ||
|
||||
sSortContext->LocalToString(str_addr2, &str2) != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strcmp(str2, str1);
|
||||
}
|
||||
|
||||
static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
auto rt = pContext->GetRuntime();
|
||||
if (!rt->UsesDirectArrays())
|
||||
return sm_SortStrings_Legacy(pContext, params);
|
||||
|
||||
cell_t *array;
|
||||
cell_t array_size = params[2];
|
||||
cell_t type = params[3];
|
||||
|
||||
pContext->LocalToPhysAddr(params[1], &array);
|
||||
|
||||
ke::SaveAndSet<IPluginContext*> set_context(&sSortContext, pContext);
|
||||
|
||||
if (type == Sort_Ascending)
|
||||
{
|
||||
qsort(array, array_size, sizeof(cell_t), sort_strings_asc);
|
||||
}
|
||||
else if (type == Sort_Descending)
|
||||
{
|
||||
qsort(array, array_size, sizeof(cell_t), sort_strings_desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
sort_random(array, array_size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sort_info
|
||||
{
|
||||
IPluginFunction *pFunc;
|
||||
@@ -335,7 +399,7 @@ static cell_t sm_SortCustom1D(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sort2d_amx_custom(const void *elem1, const void *elem2)
|
||||
static int sort2d_amx_custom_legacy(const void *elem1, const void *elem2)
|
||||
{
|
||||
if (g_SortInfo.eh->HasException())
|
||||
return 0;
|
||||
@@ -361,7 +425,7 @@ int sort2d_amx_custom(const void *elem1, const void *elem2)
|
||||
return result;
|
||||
}
|
||||
|
||||
static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
|
||||
static cell_t sm_SortCustom2D_Legacy(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *array;
|
||||
cell_t array_size = params[2];
|
||||
@@ -401,7 +465,7 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
|
||||
array[i] = i;
|
||||
}
|
||||
|
||||
qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom);
|
||||
qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom_legacy);
|
||||
|
||||
/** Fixup process! */
|
||||
for (int i=0; i<array_size; i++)
|
||||
@@ -419,6 +483,55 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sort2d_amx_custom(const void *elem1, const void *elem2)
|
||||
{
|
||||
if (g_SortInfo.eh->HasException())
|
||||
return 0;
|
||||
|
||||
cell_t iv1 = *(cell_t *)elem1;
|
||||
cell_t iv2 = *(cell_t *)elem2;
|
||||
|
||||
cell_t result = 0;
|
||||
g_SortInfo.pFunc->PushCell(iv1);
|
||||
g_SortInfo.pFunc->PushCell(iv2);
|
||||
g_SortInfo.pFunc->PushCell(g_SortInfo.array_addr);
|
||||
g_SortInfo.pFunc->PushCell(g_SortInfo.hndl);
|
||||
g_SortInfo.pFunc->Invoke(&result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
auto rt = pContext->GetRuntime();
|
||||
if (!rt->UsesDirectArrays())
|
||||
return sm_SortCustom2D_Legacy(pContext, params);
|
||||
|
||||
cell_t *array;
|
||||
cell_t array_size = params[2];
|
||||
IPluginFunction *pFunction;
|
||||
|
||||
pContext->LocalToPhysAddr(params[1], &array);
|
||||
|
||||
if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Function %x is not a valid function", params[3]);
|
||||
}
|
||||
|
||||
sort_info oldinfo = g_SortInfo;
|
||||
|
||||
DetectExceptions eh(pContext);
|
||||
g_SortInfo.pFunc = pFunction;
|
||||
g_SortInfo.hndl = params[4];
|
||||
g_SortInfo.array_addr = params[1];
|
||||
g_SortInfo.eh = &eh;
|
||||
|
||||
qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom);
|
||||
|
||||
g_SortInfo = oldinfo;
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum SortType
|
||||
{
|
||||
Sort_Integer = 0,
|
||||
@@ -454,7 +567,7 @@ static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
@@ -491,7 +604,7 @@ static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_asc);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_desc);
|
||||
}
|
||||
@@ -502,7 +615,7 @@ static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_asc);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_desc);
|
||||
}
|
||||
@@ -545,7 +658,7 @@ static cell_t sm_SortADTArrayCustom(IPluginContext *pContext, const cell_t *para
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
|
||||
@@ -170,7 +170,7 @@ static cell_t Int64ToString(IPluginContext *pCtx, const cell_t *params)
|
||||
char *str;
|
||||
pCtx->LocalToPhysAddr(params[1], &num);
|
||||
pCtx->LocalToString(params[2], &str);
|
||||
size_t res = ke::SafeSprintf(str, params[3], "%" KE_FMT_I64, (int64_t)num[1] << 32ll | (int64_t)num[0]);
|
||||
size_t res = ke::SafeSprintf(str, params[3], "%" KE_FMT_I64, (uint64_t)num[1] << 32ll | (uint32_t)num[0]);
|
||||
|
||||
return static_cast<cell_t>(res);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <ITextParsers.h>
|
||||
#include <ISourceMod.h>
|
||||
@@ -264,6 +266,32 @@ static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params)
|
||||
return (cell_t)p_err;
|
||||
}
|
||||
|
||||
static cell_t SMC_ParseString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
OpenHandle<ParseInfo> parse(pContext, params[1], g_TypeSMC);
|
||||
if (!parse.Ok())
|
||||
return 0;
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
SMCStates states;
|
||||
SMCError p_err = textparsers->ParseSMCStream(str,
|
||||
strlen(str),
|
||||
parse,
|
||||
&states,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
cell_t *c_line, *c_col;
|
||||
pContext->LocalToPhysAddr(params[3], &c_line);
|
||||
pContext->LocalToPhysAddr(params[4], &c_col);
|
||||
|
||||
*c_line = states.line;
|
||||
*c_col = states.col;
|
||||
return (cell_t)p_err;
|
||||
}
|
||||
|
||||
static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
const char *str = textparsers->GetSMCErrorString((SMCError)params[1]);
|
||||
@@ -334,6 +362,7 @@ REGISTER_NATIVES(textNatives)
|
||||
// Transitional syntax support.
|
||||
{"SMCParser.SMCParser", SMC_CreateParser},
|
||||
{"SMCParser.ParseFile", SMC_ParseFile},
|
||||
{"SMCParser.ParseString", SMC_ParseString},
|
||||
{"SMCParser.OnStart.set", SMC_SetParseStart},
|
||||
{"SMCParser.OnEnd.set", SMC_SetParseEnd},
|
||||
{"SMCParser.OnEnterSection.set", SMCParser_OnEnterSection_set},
|
||||
|
||||
@@ -1218,7 +1218,7 @@ reswitch:
|
||||
cell_t *target;
|
||||
pCtx->LocalToString(params[arg++], &key);
|
||||
pCtx->LocalToPhysAddr(params[arg++], &target);
|
||||
res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
|
||||
res = Translate(buf_p, llen + 1, pCtx, key, *target, params, &arg, &error);
|
||||
if (error)
|
||||
{
|
||||
return 0;
|
||||
@@ -1235,7 +1235,7 @@ reswitch:
|
||||
size_t res;
|
||||
cell_t target = bridge->GetGlobalTarget();
|
||||
pCtx->LocalToString(params[arg++], &key);
|
||||
res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
|
||||
res = Translate(buf_p, llen + 1, pCtx, key, target, params, &arg, &error);
|
||||
if (error)
|
||||
{
|
||||
return 0;
|
||||
|
||||
+50
-69
@@ -51,9 +51,6 @@
|
||||
#include <bridge/include/IVEngineServerBridge.h>
|
||||
#include <bridge/include/IPlayerInfoBridge.h>
|
||||
#include <bridge/include/IFileSystemBridge.h>
|
||||
#if PROTOBUF_PROXY_ENABLE
|
||||
# include "pb_handle.h"
|
||||
#endif
|
||||
|
||||
sm_logic_t logicore;
|
||||
|
||||
@@ -105,90 +102,98 @@ public:
|
||||
class VFileSystem_Logic : public IFileSystemBridge
|
||||
{
|
||||
public:
|
||||
const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle)
|
||||
const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) override
|
||||
{
|
||||
return filesystem->FindFirstEx(pWildCard, pPathID, pHandle);
|
||||
}
|
||||
const char *FindNext(FileFindHandle_t handle)
|
||||
const char *FindNext(FileFindHandle_t handle) override
|
||||
{
|
||||
return filesystem->FindNext(handle);
|
||||
}
|
||||
bool FindIsDirectory(FileFindHandle_t handle)
|
||||
bool FindIsDirectory(FileFindHandle_t handle) override
|
||||
{
|
||||
return filesystem->FindIsDirectory(handle);
|
||||
}
|
||||
void FindClose(FileFindHandle_t handle)
|
||||
void FindClose(FileFindHandle_t handle) override
|
||||
{
|
||||
filesystem->FindClose(handle);
|
||||
}
|
||||
FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0)
|
||||
FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) override
|
||||
{
|
||||
return filesystem->Open(pFileName, pOptions, pathID);
|
||||
}
|
||||
void Close(FileHandle_t file)
|
||||
void Close(FileHandle_t file) override
|
||||
{
|
||||
filesystem->Close(file);
|
||||
}
|
||||
char *ReadLine(char *pOutput, int maxChars, FileHandle_t file)
|
||||
char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) override
|
||||
{
|
||||
return filesystem->ReadLine(pOutput, maxChars, file);
|
||||
}
|
||||
bool EndOfFile(FileHandle_t file)
|
||||
bool EndOfFile(FileHandle_t file) override
|
||||
{
|
||||
return filesystem->EndOfFile(file);
|
||||
}
|
||||
bool FileExists(const char *pFileName, const char *pPathID = 0)
|
||||
bool FileExists(const char *pFileName, const char *pPathID = 0) override
|
||||
{
|
||||
return filesystem->FileExists(pFileName, pPathID);
|
||||
}
|
||||
unsigned int Size(const char *pFileName, const char *pPathID = 0)
|
||||
unsigned int Size(FileHandle_t file) override
|
||||
{
|
||||
return filesystem->Size(file);
|
||||
}
|
||||
unsigned int Size(const char *pFileName, const char *pPathID = 0) override
|
||||
{
|
||||
return filesystem->Size(pFileName, pPathID);
|
||||
}
|
||||
int Read(void* pOutput, int size, FileHandle_t file)
|
||||
int Read(void* pOutput, int size, FileHandle_t file) override
|
||||
{
|
||||
return filesystem->Read(pOutput, size, file);
|
||||
}
|
||||
int Write(void const* pInput, int size, FileHandle_t file)
|
||||
int Write(void const* pInput, int size, FileHandle_t file) override
|
||||
{
|
||||
return filesystem->Write(pInput, size, file);
|
||||
}
|
||||
void Seek(FileHandle_t file, int pos, int seekType)
|
||||
void Seek(FileHandle_t file, int pos, int seekType) override
|
||||
{
|
||||
filesystem->Seek(file, pos, (FileSystemSeek_t) seekType);
|
||||
}
|
||||
unsigned int Tell(FileHandle_t file)
|
||||
unsigned int Tell(FileHandle_t file) override
|
||||
{
|
||||
return filesystem->Tell(file);
|
||||
}
|
||||
int FPrint(FileHandle_t file, const char *pData)
|
||||
int FPrint(FileHandle_t file, const char *pData) override
|
||||
{
|
||||
return filesystem->FPrintf(file, "%s", pData);
|
||||
}
|
||||
void Flush(FileHandle_t file)
|
||||
void Flush(FileHandle_t file) override
|
||||
{
|
||||
filesystem->Flush(file);
|
||||
}
|
||||
bool IsOk(FileHandle_t file)
|
||||
bool IsOk(FileHandle_t file) override
|
||||
{
|
||||
return filesystem->IsOk(file);
|
||||
}
|
||||
void RemoveFile(const char *pRelativePath, const char *pathID)
|
||||
void RemoveFile(const char *pRelativePath, const char *pathID) override
|
||||
{
|
||||
filesystem->RemoveFile(pRelativePath, pathID);
|
||||
}
|
||||
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID)
|
||||
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID) override
|
||||
{
|
||||
filesystem->RenameFile(pOldPath, pNewPath, pathID);
|
||||
}
|
||||
bool IsDirectory(const char *pFileName, const char *pathID)
|
||||
bool IsDirectory(const char *pFileName, const char *pathID) override
|
||||
{
|
||||
return filesystem->IsDirectory(pFileName, pathID);
|
||||
}
|
||||
void CreateDirHierarchy(const char *path, const char *pathID)
|
||||
void CreateDirHierarchy(const char *path, const char *pathID) override
|
||||
{
|
||||
filesystem->CreateDirHierarchy(path, pathID);
|
||||
}
|
||||
int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) override
|
||||
{
|
||||
return filesystem->GetSearchPath(pathID, bGetPackFiles, pPath, nMaxLen);
|
||||
}
|
||||
} fs_wrapper;
|
||||
|
||||
class VPlayerInfo_Logic : public IPlayerInfoBridge
|
||||
@@ -374,6 +379,12 @@ void UTIL_ConsolePrint(const char *fmt, ...)
|
||||
#define GAMEFIX "2.csgo"
|
||||
#elif SOURCE_ENGINE == SE_CONTAGION
|
||||
#define GAMEFIX "2.contagion"
|
||||
#elif SOURCE_ENGINE == SE_PVKII
|
||||
#define GAMEFIX "2.pvkii"
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
#define GAMEFIX "2.mcv"
|
||||
#elif SOURCE_ENGINE == SE_MOCK
|
||||
#define GAMEFIX "2.mock"
|
||||
#else
|
||||
#define GAMEFIX "2.ep1"
|
||||
#endif
|
||||
@@ -406,9 +417,6 @@ CoreProviderImpl::CoreProviderImpl()
|
||||
this->GetGlobalTarget = get_global_target;
|
||||
this->gamesuffix = GAMEFIX;
|
||||
this->serverGlobals = &::serverGlobals;
|
||||
this->serverFactory = nullptr;
|
||||
this->engineFactory = nullptr;
|
||||
this->matchmakingDSFactory = nullptr;
|
||||
this->listeners = nullptr;
|
||||
}
|
||||
|
||||
@@ -496,6 +504,12 @@ const char *CoreProviderImpl::GetSourceEngineName()
|
||||
return "doi";
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
return "csgo";
|
||||
#elif SOURCE_ENGINE == SE_MOCK
|
||||
return "mock";
|
||||
#elif SOURCE_ENGINE == SE_PVKII
|
||||
return "pvkii";
|
||||
#elif SOURCE_ENGINE == SE_MCV
|
||||
return "mcv";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -513,7 +527,9 @@ bool CoreProviderImpl::SymbolsAreHidden()
|
||||
|| (SOURCE_ENGINE == SE_INSURGENCY) \
|
||||
|| (SOURCE_ENGINE == SE_DOI) \
|
||||
|| (SOURCE_ENGINE == SE_BLADE) \
|
||||
|| (SOURCE_ENGINE == SE_CSGO)
|
||||
|| (SOURCE_ENGINE == SE_CSGO) \
|
||||
|| (SOURCE_ENGINE == SE_PVKII) \
|
||||
|| (SOURCE_ENGINE == SE_MCV)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
@@ -626,14 +642,8 @@ void CoreProviderImpl::InitializeBridge()
|
||||
::serverGlobals.frametime = &gpGlobals->frametime;
|
||||
::serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick;
|
||||
|
||||
this->engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
|
||||
this->serverFactory = (void *)g_SMAPI->GetServerFactory(false);
|
||||
this->listeners = SMGlobalClass::head;
|
||||
|
||||
if (auto mmlib = ::filesystem->LoadModule("matchmaking_ds" SOURCE_BIN_SUFFIX, "GAMEBIN")) {
|
||||
this->matchmakingDSFactory = (void*)Sys_GetFactory(mmlib);
|
||||
}
|
||||
|
||||
logic_init_(this, &logicore);
|
||||
|
||||
// Join logic's SMGlobalClass instances.
|
||||
@@ -655,41 +665,6 @@ void CoreProviderImpl::InitializeBridge()
|
||||
rootmenu = logicore.rootmenu;
|
||||
}
|
||||
|
||||
bool CoreProviderImpl::LoadProtobufProxy(char *error, size_t maxlength)
|
||||
{
|
||||
#if !defined(PROTOBUF_PROXY_ENABLE)
|
||||
return false;
|
||||
#else
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
|
||||
#if !defined(PROTOBUF_PROXY_BINARY_NAME)
|
||||
# error "No engine suffix defined"
|
||||
#endif
|
||||
|
||||
/* Now it's time to load the logic binary */
|
||||
g_SMAPI->PathFormat(file,
|
||||
sizeof(file),
|
||||
"%s/bin/" PLATFORM_ARCH_FOLDER PROTOBUF_PROXY_BINARY_NAME PLATFORM_LIB_EXT,
|
||||
g_SourceMod.GetSourceModPath());
|
||||
|
||||
char myerror[255];
|
||||
pbproxy_ = ke::SharedLib::Open(file, myerror, sizeof(myerror));
|
||||
if (!pbproxy_) {
|
||||
ke::SafeSprintf(error, maxlength, "failed to load %s: %s", file, myerror);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fn = pbproxy_->get<GetProtobufProxyFn>("GetProtobufProxy");
|
||||
if (!fn) {
|
||||
ke::SafeStrcpy(error, maxlength, "could not find GetProtobufProxy function");
|
||||
return false;
|
||||
}
|
||||
|
||||
gProtobufProxy = fn();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CoreProviderImpl::LoadBridge(char *error, size_t maxlength)
|
||||
{
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
@@ -770,6 +745,12 @@ CoreProviderImpl::DefineCommand(const char *name, const char *help, const Comman
|
||||
commands_.push_back(impl);
|
||||
}
|
||||
|
||||
void CoreProviderImpl::FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength)
|
||||
{
|
||||
bool use_prefix = (!strcasecmp(basename, "tier0") || !strcasecmp(basename, "vstdlib"));
|
||||
ke::SafeSprintf(buffer, maxlength, "%s%s%s%s", use_prefix ? SOURCE_BIN_PREFIX : "", basename, SOURCE_BIN_SUFFIX, SOURCE_BIN_EXT);
|
||||
}
|
||||
|
||||
void CoreProviderImpl::InitializeHooks()
|
||||
{
|
||||
hooks_.Start();
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2020 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$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(PROTOBUF_ENABLE)
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
# include "pb_proxy.h"
|
||||
|
||||
extern IProtobufProxy* gProtobufProxy;
|
||||
#endif
|
||||
|
||||
const google::protobuf::Message *GetMessagePrototype(int msg_type);
|
||||
|
||||
// On SDKs which use protobufs, the engine has objects compiled against a specific
|
||||
// version of protobuf. Normally this is fine, we take care on Linux to use the
|
||||
// same C++ ABI. On macOS however, we use libc++ to enable C++11 functionality,
|
||||
// whereas the protobuf library has been compiled with libstc++. These ABIs are
|
||||
// not compatible.
|
||||
//
|
||||
// To address the problem, we introduce PbHandle. PbHandle is a wrapper around
|
||||
// protobuf::Message with two added pieces of state: whether or not the handle
|
||||
// "owns" the message (and can free it in its destructor), and whether or not
|
||||
// the handle was created by the engine (private) or created by SourceMod
|
||||
// (local).
|
||||
//
|
||||
// Whenever we transfer a protobuf::Message pointer to SourceMod, we must take
|
||||
// care to convert it to a Local version first. Whenever we transfer a protobuf
|
||||
// pointer to the engine, we must convert it to a Private handle.
|
||||
//
|
||||
// For platforms with no ABI differences (almost all of them), the handle is a
|
||||
// no-op. The private and local localities are compatible and no translation
|
||||
// takes place.
|
||||
//
|
||||
// On macOS, CS:GO does require translation. SourceMod loads a tiny shim
|
||||
// library that contains a copy of the protobuf sources compiled against the
|
||||
// game's ABI. It then provides serialization and deserialization methods.
|
||||
// SourceMod must not interact with the game's protobuf objects without first
|
||||
// going through this proxy library.
|
||||
//
|
||||
// Note that PbHandle is not quite like unique_ptr_. It can be converted into a
|
||||
// PbHandle that does not destroy the underlying object. This is mainly because
|
||||
// UserMessages.cpp has rather complex state, so it is useful to track locality
|
||||
// without destroying an object. An unowned PbHandle must not outlive the
|
||||
// owning PbHandle.
|
||||
class PbHandle
|
||||
{
|
||||
public:
|
||||
enum Ownership {
|
||||
Owned,
|
||||
Unowned,
|
||||
};
|
||||
enum Locality {
|
||||
Local,
|
||||
Private,
|
||||
};
|
||||
|
||||
PbHandle() : msg_(nullptr) {}
|
||||
PbHandle(decltype(nullptr)) : msg_(nullptr) {}
|
||||
PbHandle(google::protobuf::Message* msg, Ownership ownership, Locality locality)
|
||||
: msg_(msg),
|
||||
ownership_(ownership),
|
||||
locality_(locality)
|
||||
{}
|
||||
PbHandle(PbHandle&& other)
|
||||
: msg_(other.msg_),
|
||||
ownership_(other.ownership_),
|
||||
locality_(other.locality_)
|
||||
{
|
||||
other.msg_ = nullptr;
|
||||
}
|
||||
PbHandle(const PbHandle&) = delete;
|
||||
|
||||
~PbHandle() {
|
||||
maybe_free();
|
||||
}
|
||||
|
||||
PbHandle& operator =(PbHandle&& other) {
|
||||
if (other.msg_ != msg_)
|
||||
maybe_free();
|
||||
msg_ = other.msg_;
|
||||
ownership_ = other.ownership_;
|
||||
locality_ = other.locality_;
|
||||
other.msg_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
PbHandle& operator =(const PbHandle&) = delete;
|
||||
|
||||
google::protobuf::Message* operator ->() const { return msg_; }
|
||||
|
||||
google::protobuf::Message* GetLocalMessage() {
|
||||
assert(locality_ == Local);
|
||||
return msg_;
|
||||
}
|
||||
google::protobuf::Message* GetPrivateMessage() {
|
||||
assert(locality_ == Private);
|
||||
return msg_;
|
||||
}
|
||||
|
||||
PbHandle ToLocal(int msg_type) {
|
||||
if (locality_ == Local)
|
||||
return AsUnowned();
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
PbHandle local(GetMessagePrototype(msg_type)->New(), Owned, Local);
|
||||
local.CopyFromPrivate(msg_);
|
||||
return local;
|
||||
#else
|
||||
return PbHandle(msg_, Unowned, Local);
|
||||
#endif
|
||||
}
|
||||
|
||||
PbHandle ToPrivate(int msg_type) {
|
||||
if (locality_ == Private)
|
||||
return AsUnowned();
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
PbHandle priv(gProtobufProxy->NewPrototype(msg_type), Owned, Private);
|
||||
priv.CopyFromLocal(msg_);
|
||||
return priv;
|
||||
#else
|
||||
return PbHandle(msg_, Unowned, Private);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CopyFrom(const PbHandle& other) {
|
||||
if (other.msg_ == msg_) {
|
||||
assert(other.locality_ == locality_);
|
||||
return;
|
||||
}
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
if (other.locality_ == Local)
|
||||
CopyFromLocal(other.msg_);
|
||||
else if (other.locality_ == Private)
|
||||
CopyFromPrivate(other.msg_);
|
||||
#else
|
||||
msg_->CopyFrom(*other.msg_);
|
||||
#endif
|
||||
}
|
||||
|
||||
PbHandle AsUnowned() {
|
||||
return PbHandle(msg_, Unowned, locality_);
|
||||
}
|
||||
|
||||
bool is_owned() const { return ownership_ == Owned; }
|
||||
bool is_local() const { return locality_ == Local; }
|
||||
|
||||
private:
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
void CopyFromPrivate(google::protobuf::Message* message) {
|
||||
void* out;
|
||||
size_t len;
|
||||
if (!gProtobufProxy->Serialize(message, &out, &len))
|
||||
return;
|
||||
if (locality_ == Local)
|
||||
msg_->ParsePartialFromArray(out, len);
|
||||
else
|
||||
gProtobufProxy->Deserialize(out, len, msg_);
|
||||
gProtobufProxy->FreeBuffer(out);
|
||||
}
|
||||
|
||||
void CopyFromLocal(google::protobuf::Message* message) {
|
||||
if (locality_ == Local) {
|
||||
msg_->CopyFrom(*message);
|
||||
} else {
|
||||
auto data = message->SerializePartialAsString();
|
||||
gProtobufProxy->Deserialize(data.data(), data.size(), msg_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void maybe_free() {
|
||||
if (ownership_ != Owned)
|
||||
return;
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
if (locality_ == Private) {
|
||||
gProtobufProxy->FreeMessage(msg_);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
delete msg_;
|
||||
}
|
||||
|
||||
private:
|
||||
google::protobuf::Message* msg_ = nullptr;
|
||||
Ownership ownership_ = Unowned;
|
||||
Locality locality_ = Local;
|
||||
};
|
||||
|
||||
#endif // PROTOBUF_ENABLE
|
||||
@@ -1,100 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2020 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 "pb_proxy.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sm_platform.h>
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
# include <cstrike15_usermessage_helpers.h>
|
||||
#else
|
||||
# error "No source engine compatibility"
|
||||
#endif
|
||||
|
||||
class ProtobufProxy : public IProtobufProxy
|
||||
{
|
||||
public:
|
||||
bool Serialize(const google::protobuf::Message* message, void** out, size_t* len);
|
||||
void FreeBuffer(void* data);
|
||||
bool Deserialize(const void* buffer, size_t len, google::protobuf::Message* message);
|
||||
google::protobuf::Message* NewPrototype(int msg_type);
|
||||
void FreeMessage(google::protobuf::Message* message);
|
||||
};
|
||||
|
||||
static ProtobufProxy sProtobufProxy;
|
||||
|
||||
PLATFORM_EXTERN_C IProtobufProxy*
|
||||
GetProtobufProxy()
|
||||
{
|
||||
return &sProtobufProxy;
|
||||
}
|
||||
|
||||
bool
|
||||
ProtobufProxy::Serialize(const google::protobuf::Message* message, void** out, size_t* len)
|
||||
{
|
||||
*len = message->ByteSize();
|
||||
*out = malloc(*len);
|
||||
if (!*out)
|
||||
return false;
|
||||
if (!message->SerializePartialToArray(*out, *len)) {
|
||||
free(*out);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ProtobufProxy::FreeBuffer(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
bool
|
||||
ProtobufProxy::Deserialize(const void* buffer, size_t len, google::protobuf::Message* message)
|
||||
{
|
||||
return message->ParsePartialFromArray(buffer, len);
|
||||
}
|
||||
|
||||
google::protobuf::Message*
|
||||
ProtobufProxy::NewPrototype(int msg_type)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
|
||||
#else
|
||||
# error "No source engine compatibility."
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ProtobufProxy::FreeMessage(google::protobuf::Message* message)
|
||||
{
|
||||
delete message;
|
||||
}
|
||||
+1
-2
@@ -38,7 +38,6 @@ public:
|
||||
|
||||
// Local functions.
|
||||
void InitializeBridge();
|
||||
bool LoadProtobufProxy(char *error, size_t maxlength);
|
||||
bool LoadBridge(char *error, size_t maxlength);
|
||||
void ShutdownBridge();
|
||||
|
||||
@@ -67,6 +66,7 @@ public:
|
||||
int QueryClientConVar(int client, const char *cvar) override;
|
||||
bool IsClientConVarQueryingSupported() override;
|
||||
void DefineCommand(const char *cmd, const char *help, const SourceMod::CommandFunc &callback) override;
|
||||
void FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength) override;
|
||||
|
||||
ke::RefPtr<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
|
||||
ke::RefPtr<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
|
||||
@@ -76,7 +76,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ke::RefPtr<ke::SharedLib> pbproxy_;
|
||||
ke::RefPtr<ke::SharedLib> logic_;
|
||||
LogicInitFunction logic_init_;
|
||||
GameHooks hooks_;
|
||||
|
||||
+68
-9
@@ -51,7 +51,7 @@
|
||||
#include <bridge/include/ILogger.h>
|
||||
#include <ITranslator.h>
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
#include <netmessages.pb.h>
|
||||
#endif
|
||||
|
||||
@@ -827,6 +827,16 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_IsCommandCallback(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
|
||||
|
||||
if (!pCmd)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
|
||||
@@ -979,11 +989,14 @@ static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
|
||||
engine->ServerExecute();
|
||||
|
||||
g_ShouldCatchSpew = true;
|
||||
engine->ServerCommand("sm_conhook_start\n");
|
||||
engine->ServerCommand(buffer);
|
||||
engine->ServerCommand("sm_conhook_stop\n");
|
||||
if (!g_ShouldCatchSpew) {
|
||||
g_ShouldCatchSpew = true;
|
||||
engine->ServerCommand("sm_conhook_start\n");
|
||||
engine->ServerCommand(buffer);
|
||||
engine->ServerCommand("sm_conhook_stop\n");
|
||||
} else {
|
||||
engine->ServerCommand(buffer);
|
||||
}
|
||||
|
||||
engine->ServerExecute();
|
||||
|
||||
@@ -1091,6 +1104,26 @@ static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
|
||||
return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t GetPublicChatTriggers(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
const char *triggers = g_ChatTriggers.GetPublicChatTrigger();
|
||||
pContext->StringToLocalUTF8(params[1], params[2], triggers ? triggers : "", &length);
|
||||
|
||||
return static_cast<cell_t>(length);
|
||||
}
|
||||
|
||||
static cell_t GetSilentChatTriggers(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
const char *triggers = g_ChatTriggers.GetPrivateChatTrigger();
|
||||
pContext->StringToLocalUTF8(params[1], params[2], triggers ? triggers : "", &length);
|
||||
|
||||
return static_cast<cell_t>(length);
|
||||
}
|
||||
|
||||
static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *name;
|
||||
@@ -1209,7 +1242,7 @@ static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
|
||||
char data[256];
|
||||
bf_write buffer(data, sizeof(data));
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CNETMsg_SetConVar msg;
|
||||
CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();
|
||||
|
||||
@@ -1393,7 +1426,7 @@ static cell_t sm_CommandIteratorNext(IPluginContext *pContext, const cell_t *par
|
||||
return iter->iter != cmds.end();
|
||||
}
|
||||
|
||||
static cell_t sm_CommandIteratorFlags(IPluginContext *pContext, const cell_t *params)
|
||||
static cell_t sm_CommandIteratorAdminFlags(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
GlobCmdIter *iter;
|
||||
HandleError err;
|
||||
@@ -1414,6 +1447,27 @@ static cell_t sm_CommandIteratorFlags(IPluginContext *pContext, const cell_t *pa
|
||||
return pInfo->eflags;
|
||||
}
|
||||
|
||||
static cell_t sm_CommandIteratorConVarFlags(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
GlobCmdIter *iter;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
|
||||
}
|
||||
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
|
||||
if (!iter->started || iter->iter == cmds.end())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid CommandIterator position");
|
||||
}
|
||||
|
||||
ConCmdInfo *pInfo = (*(iter->iter));
|
||||
return pInfo->pCmd->m_nFlags;
|
||||
}
|
||||
|
||||
static cell_t sm_CommandIteratorGetDesc(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
GlobCmdIter *iter;
|
||||
@@ -1505,6 +1559,7 @@ REGISTER_NATIVES(consoleNatives)
|
||||
{"GetConVarDefault", GetConVarDefault},
|
||||
{"RegServerCmd", sm_RegServerCmd},
|
||||
{"RegConsoleCmd", sm_RegConsoleCmd},
|
||||
{"IsCommandCallback", sm_IsCommandCallback},
|
||||
{"GetCmdArgString", sm_GetCmdArgString},
|
||||
{"GetCmdArgs", sm_GetCmdArgs},
|
||||
{"GetCmdArg", sm_GetCmdArg},
|
||||
@@ -1514,6 +1569,8 @@ REGISTER_NATIVES(consoleNatives)
|
||||
{"ReadCommandIterator", ReadCommandIterator},
|
||||
{"FakeClientCommandEx", FakeClientCommandEx},
|
||||
{"IsChatTrigger", IsChatTrigger},
|
||||
{"GetPublicChatTriggers", GetPublicChatTriggers},
|
||||
{"GetSilentChatTriggers", GetSilentChatTriggers},
|
||||
{"SetCommandFlags", SetCommandFlags},
|
||||
{"GetCommandFlags", GetCommandFlags},
|
||||
{"FindFirstConCommand", FindFirstConCommand},
|
||||
@@ -1552,7 +1609,9 @@ REGISTER_NATIVES(consoleNatives)
|
||||
{"CommandIterator.Next", sm_CommandIteratorNext},
|
||||
{"CommandIterator.GetDescription", sm_CommandIteratorGetDesc},
|
||||
{"CommandIterator.GetName", sm_CommandIteratorGetName},
|
||||
{"CommandIterator.Flags.get", sm_CommandIteratorFlags},
|
||||
{"CommandIterator.Flags.get", sm_CommandIteratorAdminFlags},
|
||||
{"CommandIterator.AdminFlags.get", sm_CommandIteratorAdminFlags},
|
||||
{"CommandIterator.ConVarFlags.get", sm_CommandIteratorConVarFlags},
|
||||
{"CommandIterator.Plugin.get", sm_CommandIteratorPlugin},
|
||||
|
||||
{NULL, NULL}
|
||||
|
||||
+117
-35
@@ -134,12 +134,10 @@ inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
|
||||
{
|
||||
IServerUnknown *pUnk = (IServerUnknown *)pEntity;
|
||||
IServerNetworkable *pNet = pUnk->GetNetworkable();
|
||||
|
||||
if (!pNet)
|
||||
if (pNet == nullptr)
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pNet->GetEdict();
|
||||
}
|
||||
|
||||
@@ -285,6 +283,11 @@ static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
}
|
||||
|
||||
if (g_HL2.ReferenceToIndex(params[1]) == 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Cannot remove worldspawn (edict 0)");
|
||||
}
|
||||
|
||||
engine->RemoveEdict(pEdict);
|
||||
|
||||
return 1;
|
||||
@@ -298,6 +301,11 @@ static cell_t RemoveEntity(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Entity %d (%d) is not a valid entity", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
}
|
||||
|
||||
if (g_HL2.ReferenceToIndex(params[1]) == 0)
|
||||
{
|
||||
return pContext->ThrowNativeError("Cannot remove worldspawn (entity 0)");
|
||||
}
|
||||
|
||||
// Some games have UTIL_Remove exposed on IServerTools, but for consistence, we'll
|
||||
// use this method for all. Results in DeathNotice( this ) being called on parent,
|
||||
// and parent being cleared (both if any parent) before UTIL_Remove is called.
|
||||
@@ -353,14 +361,20 @@ static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
edict_t *pEdict = GetEdict(params[1]);
|
||||
|
||||
if (!pEdict)
|
||||
IServerUnknown *pUnknown = (IServerUnknown *)g_HL2.ReferenceToEntity(params[1]);
|
||||
if (!pUnknown)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
|
||||
IServerNetworkable *pNet = pUnknown->GetNetworkable();
|
||||
if (!pNet)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
edict_t* edict = pNet->GetEdict();
|
||||
return (edict && !edict->IsFree()) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
|
||||
@@ -426,14 +440,12 @@ static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
}
|
||||
|
||||
IServerNetworkable *pNet = pUnk->GetNetworkable();
|
||||
if (!pNet)
|
||||
ServerClass *pClass = g_HL2.FindEntityServerClass(pEntity);
|
||||
if (!pClass)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ServerClass *pClass = pNet->GetServerClass();
|
||||
|
||||
pContext->StringToLocal(params[2], params[3], pClass->GetName());
|
||||
|
||||
return 1;
|
||||
@@ -706,6 +718,36 @@ static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
|
||||
return g_HL2.EntityToBCompatRef(pHandleEntity);
|
||||
}
|
||||
|
||||
//memory addresses below 0x10000 are automatically considered invalid for dereferencing
|
||||
//this is copied over from smn_core.cpp
|
||||
#define VALID_MINIMUM_MEMORY_ADDRESS 0x10000
|
||||
|
||||
static cell_t LoadEntityFromHandleAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef PLATFORM_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
|
||||
}
|
||||
|
||||
CBaseHandle &hndl = *reinterpret_cast<CBaseHandle*>(addr);
|
||||
CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex());
|
||||
|
||||
if (!pHandleEntity || hndl != reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
|
||||
return -1;
|
||||
|
||||
return g_HL2.EntityToBCompatRef(pHandleEntity);
|
||||
}
|
||||
|
||||
/* THIS GUY IS DEPRECATED. */
|
||||
static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
@@ -791,6 +833,44 @@ static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t StoreEntityToHandleAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef PLATFORM_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
|
||||
}
|
||||
|
||||
CBaseHandle &hndl = *reinterpret_cast<CBaseHandle*>(addr);
|
||||
|
||||
if ((unsigned)params[2] == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
hndl.Set(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
CBaseEntity *pOther = GetEntity(params[2]);
|
||||
|
||||
if (!pOther)
|
||||
{
|
||||
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[2]), params[2]);
|
||||
}
|
||||
|
||||
IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
|
||||
hndl.Set(pHandleEnt);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
edict_t *pEdict = GetEdict(params[1]);
|
||||
@@ -818,6 +898,12 @@ static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Before we added support for DPT_Array props, FindInSendTable would have given us the inner array prop itself.
|
||||
// To maintain compatibility with older plugins still using us, pluck out the inner array prop ourselves.
|
||||
if (pSend->GetType() == DPT_Array && pSend->GetArrayProp()) {
|
||||
return pSend->GetArrayProp()->GetOffset();
|
||||
}
|
||||
|
||||
return pSend->GetOffset();
|
||||
}
|
||||
|
||||
@@ -825,7 +911,7 @@ static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *cls, *prop;
|
||||
sm_sendprop_info_t info;
|
||||
cell_t *pType, *pBits, *pLocal, *pArraySize;
|
||||
cell_t *pType, *pBits, *pLocal, *pArraySize = nullptr;
|
||||
|
||||
pContext->LocalToString(params[1], &cls);
|
||||
pContext->LocalToString(params[2], &prop);
|
||||
@@ -1186,13 +1272,11 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
|
||||
#define FIND_PROP_SEND(type, type_name) \
|
||||
sm_sendprop_info_t info;\
|
||||
SendProp *pProp; \
|
||||
IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
|
||||
IServerNetworkable *pNet = pUnk->GetNetworkable(); \
|
||||
if (!pNet) \
|
||||
{ \
|
||||
return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
|
||||
ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity); \
|
||||
if (pServerClass == nullptr) { \
|
||||
pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]); \
|
||||
} \
|
||||
if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) \
|
||||
if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info)) \
|
||||
{ \
|
||||
const char *class_name = g_HL2.GetEntityClassname(pEntity); \
|
||||
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
|
||||
@@ -1350,13 +1434,13 @@ static cell_t GetEntPropArraySize(IPluginContext *pContext, const cell_t *params
|
||||
{
|
||||
sm_sendprop_info_t info;
|
||||
|
||||
IServerUnknown *pUnk = (IServerUnknown *)pEntity;
|
||||
IServerNetworkable *pNet = pUnk->GetNetworkable();
|
||||
if (!pNet)
|
||||
ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity);
|
||||
if (pServerClass == nullptr)
|
||||
{
|
||||
return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
}
|
||||
if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info))
|
||||
|
||||
if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info))
|
||||
{
|
||||
const char *class_name = g_HL2.GetEntityClassname(pEntity);
|
||||
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)",
|
||||
@@ -1452,7 +1536,8 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
|
||||
// This isn't in CS:S yet, but will be, doesn't hurt to add now, and will save us a build later
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2 \
|
||||
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_PVKII \
|
||||
|| SOURCE_ENGINE == SE_MCV
|
||||
if (pProp->GetFlags() & SPROP_VARINT)
|
||||
{
|
||||
bit_count = sizeof(int) * 8;
|
||||
@@ -1571,7 +1656,8 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
|
||||
// This isn't in CS:S yet, but will be, doesn't hurt to add now, and will save us a build later
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2 \
|
||||
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_PVKII \
|
||||
|| SOURCE_ENGINE == SE_MCV
|
||||
if (pProp->GetFlags() & SPROP_VARINT)
|
||||
{
|
||||
bit_count = sizeof(int) * 8;
|
||||
@@ -1993,13 +2079,7 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
|
||||
edict_t *pOtherEdict = NULL;
|
||||
if (pOther)
|
||||
{
|
||||
IServerNetworkable *pNetworkable = ((IServerUnknown *) pOther)->GetNetworkable();
|
||||
if (!pNetworkable)
|
||||
{
|
||||
return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]);
|
||||
}
|
||||
|
||||
pOtherEdict = pNetworkable->GetEdict();
|
||||
pOtherEdict = BaseEntityToEdict(pOther);
|
||||
if (!pOtherEdict || pOtherEdict->IsFree())
|
||||
{
|
||||
return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]);
|
||||
@@ -2502,7 +2582,7 @@ static int32_t SDKEntFlagToSMEntFlag(int flag)
|
||||
case FL_FREEZING:
|
||||
return ENTFLAG_FREEZING;
|
||||
#elif SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
|
||||
case FL_EP2V_UNKNOWN:
|
||||
return ENTFLAG_EP2V_UNKNOWN1;
|
||||
#endif
|
||||
@@ -2581,7 +2661,7 @@ static int32_t SMEntFlagToSDKEntFlag(int32_t flag)
|
||||
case ENTFLAG_FREEZING:
|
||||
return FL_FREEZING;
|
||||
#elif SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 \
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2
|
||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
|
||||
case ENTFLAG_EP2V_UNKNOWN1:
|
||||
return FL_EP2V_UNKNOWN;
|
||||
#endif
|
||||
@@ -2744,5 +2824,7 @@ REGISTER_NATIVES(entityNatives)
|
||||
{"SetEntPropVector", SetEntPropVector},
|
||||
{"GetEntityAddress", GetEntityAddress},
|
||||
{"FindDataMapInfo", FindDataMapInfo},
|
||||
{"LoadEntityFromHandleAddress", LoadEntityFromHandleAddress},
|
||||
{"StoreEntityToHandleAddress", StoreEntityToHandleAddress},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -505,6 +505,7 @@ static cell_t GuessSDKVersion(IPluginContext *pContext, const cell_t *params)
|
||||
case SOURCE_ENGINE_TF2:
|
||||
case SOURCE_ENGINE_BMS:
|
||||
case SOURCE_ENGINE_SDK2013:
|
||||
case SOURCE_ENGINE_PVKII:
|
||||
return 35;
|
||||
case SOURCE_ENGINE_LEFT4DEAD:
|
||||
return 40;
|
||||
@@ -518,6 +519,7 @@ static cell_t GuessSDKVersion(IPluginContext *pContext, const cell_t *params)
|
||||
return 70;
|
||||
case SOURCE_ENGINE_CSGO:
|
||||
return 80;
|
||||
// Deprecated, and not very useful. Don't bother adding new games
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+28
-1
@@ -41,6 +41,8 @@
|
||||
#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
|
||||
|
||||
#define MAX_HUD_CHANNELS 6
|
||||
@@ -70,6 +72,7 @@ struct hud_text_parms
|
||||
float holdTime;
|
||||
float fxTime;
|
||||
int channel;
|
||||
bool isSet = false;
|
||||
};
|
||||
|
||||
class HudMsgHelpers :
|
||||
@@ -282,6 +285,7 @@ static cell_t SetHudTextParams(IPluginContext *pContext, const cell_t *params)
|
||||
g_hud_params.g2 = 255;
|
||||
g_hud_params.b2 = 250;
|
||||
g_hud_params.a2 = 0;
|
||||
g_hud_params.isSet = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -308,6 +312,7 @@ static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params)
|
||||
g_hud_params.g2 = static_cast<byte>(color2[1]);
|
||||
g_hud_params.b2 = static_cast<byte>(color2[2]);
|
||||
g_hud_params.a2 = static_cast<byte>(color2[3]);
|
||||
g_hud_params.isSet = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -318,8 +323,12 @@ void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *p
|
||||
|
||||
players[0] = client;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
CCSUsrMsg_HudMsg *msg = (CCSUsrMsg_HudMsg *)g_UserMsgs.StartProtobufMessage(g_HudMsgNum, players, 1, 0);
|
||||
if (!msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
msg->set_channel(textparms.channel & 0xFF);
|
||||
|
||||
CMsgVector2D *pos = msg->mutable_pos();
|
||||
@@ -373,13 +382,22 @@ static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params)
|
||||
Handle_t err;
|
||||
CPlayer *pPlayer;
|
||||
hud_syncobj_t *obj;
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
char message_buffer[512];
|
||||
#else
|
||||
char message_buffer[255-36];
|
||||
#endif
|
||||
|
||||
if (!s_HudMsgHelpers.IsSupported())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_hud_params.isSet)
|
||||
{
|
||||
return pContext->ThrowNativeError("ShowSyncHudText first requires a call to SetHudTextParams or SetHudTextParamsEx");
|
||||
}
|
||||
|
||||
if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
|
||||
@@ -453,13 +471,22 @@ static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int client;
|
||||
CPlayer *pPlayer;
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||
char message_buffer[512];
|
||||
#else
|
||||
char message_buffer[255-36];
|
||||
#endif
|
||||
|
||||
if (!s_HudMsgHelpers.IsSupported())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_hud_params.isSet)
|
||||
{
|
||||
return pContext->ThrowNativeError("ShowHudText first requires a call to SetHudTextParams or SetHudTextParamsEx");
|
||||
}
|
||||
|
||||
client = params[1];
|
||||
if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
|
||||
{
|
||||
|
||||
+14
-2
@@ -669,9 +669,21 @@ static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
|
||||
return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
|
||||
}
|
||||
|
||||
while (pStk->pCurRoot.size() > 1)
|
||||
// Older plugins do not have the clearHistory param
|
||||
if (params[0] < 2 || params[2])
|
||||
{
|
||||
pStk->pCurRoot.pop();
|
||||
while (pStk->pCurRoot.size() > 1)
|
||||
{
|
||||
pStk->pCurRoot.pop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto root = pStk->pCurRoot.begin();
|
||||
if (root != pStk->pCurRoot.end())
|
||||
{
|
||||
pStk->pCurRoot.push(*root);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -356,6 +356,27 @@ static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params)
|
||||
return sp_ftoc(value);
|
||||
}
|
||||
|
||||
static cell_t sm_GetClientIClient(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int client = params[1];
|
||||
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
if (!pPlayer)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", client);
|
||||
}
|
||||
else if (!pPlayer->IsConnected())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not connected", client);
|
||||
}
|
||||
else if (pPlayer->IsFakeClient())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is a bot", client);
|
||||
}
|
||||
|
||||
return (cell_t)pPlayer->GetIClient();
|
||||
}
|
||||
|
||||
static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int client = params[1];
|
||||
@@ -392,6 +413,7 @@ REGISTER_NATIVES(playernatives)
|
||||
{"GetClientAvgChoke", GetAvgChoke},
|
||||
{"GetClientAvgData", GetAvgData},
|
||||
{"GetClientAvgPackets", GetAvgPackets},
|
||||
{"GetClientIClient", sm_GetClientIClient },
|
||||
{"RunAdminCacheChecks", RunAdminCacheChecks},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_SDK2013
|
||||
#if SOURCE_ENGINE == SE_SDK2013
|
||||
// Shim to avoid hooking shims
|
||||
engine = (IVEngineServer *)ismm->GetEngineFactory()("VEngineServer023", nullptr);
|
||||
if (!engine)
|
||||
|
||||
+30
-3
@@ -46,6 +46,7 @@
|
||||
#include <amtl/os/am-path.h>
|
||||
#include <bridge/include/IExtensionBridge.h>
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <bridge/include/IProviderCallbacks.h>
|
||||
#include <bridge/include/ILogger.h>
|
||||
|
||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
|
||||
@@ -53,6 +54,7 @@ SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
|
||||
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool);
|
||||
SH_DECL_HOOK1_void(IServerGameDLL, Think, SH_NOATTRIB, false, bool);
|
||||
SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *);
|
||||
SH_DECL_HOOK0(IVEngineServer, GetMapEntitiesString, SH_NOATTRIB, 0, const char *);
|
||||
|
||||
SourceModBase g_SourceMod;
|
||||
|
||||
@@ -277,6 +279,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
|
||||
|
||||
/* Hook this now so we can detect startup without calling StartSourceMod() */
|
||||
SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
|
||||
SH_ADD_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(this, &SourceModBase::GetMapEntitiesString), false);
|
||||
|
||||
/* Only load if we're not late */
|
||||
if (!late)
|
||||
@@ -290,7 +293,6 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
|
||||
void SourceModBase::StartSourceMod(bool late)
|
||||
{
|
||||
SH_ADD_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
|
||||
SH_ADD_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::Think), false);
|
||||
SH_ADD_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
|
||||
|
||||
enginePatch = SH_GET_CALLCLASS(engine);
|
||||
@@ -362,6 +364,8 @@ void SourceModBase::StartSourceMod(bool late)
|
||||
{
|
||||
g_pSourcePawn2->InstallWatchdogTimer(atoi(timeout) * 1000);
|
||||
}
|
||||
|
||||
SH_ADD_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(logicore.callbacks, &IProviderCallbacks::OnThink), false);
|
||||
}
|
||||
|
||||
static bool g_LevelEndBarrier = false;
|
||||
@@ -414,10 +418,32 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
|
||||
|
||||
g_LevelEndBarrier = true;
|
||||
|
||||
int parseError;
|
||||
size_t position;
|
||||
bool success = logicore.ParseEntityLumpString(pMapEntities, parseError, position);
|
||||
|
||||
logicore.SetEntityLumpWritable(true);
|
||||
g_pOnMapInit->PushString(pMapName);
|
||||
g_pOnMapInit->Execute();
|
||||
logicore.SetEntityLumpWritable(false);
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
if (!success)
|
||||
{
|
||||
logger->LogError("Map entity lump parsing for %s failed with error code %d on position %d", pMapName, parseError, position);
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_HANDLED, true, &IServerGameDLL::LevelInit, (pMapName, logicore.GetEntityLumpString(), pOldLevel, pLandmarkName, loadGame, background));
|
||||
}
|
||||
|
||||
const char *SourceModBase::GetMapEntitiesString()
|
||||
{
|
||||
const char *pNewMapEntities = logicore.GetEntityLumpString();
|
||||
if (pNewMapEntities != nullptr)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, pNewMapEntities);
|
||||
}
|
||||
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
void SourceModBase::LevelShutdown()
|
||||
@@ -532,6 +558,7 @@ void SourceModBase::CloseSourceMod()
|
||||
return;
|
||||
|
||||
SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
|
||||
SH_REMOVE_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(this, &SourceModBase::GetMapEntitiesString), false);
|
||||
|
||||
if (g_Loaded)
|
||||
{
|
||||
@@ -596,8 +623,8 @@ void SourceModBase::ShutdownServices()
|
||||
}
|
||||
|
||||
SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
|
||||
SH_REMOVE_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::Think), false);
|
||||
SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
|
||||
SH_REMOVE_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(logicore.callbacks, &IProviderCallbacks::OnThink), false);
|
||||
}
|
||||
|
||||
void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
|
||||
|
||||
@@ -140,6 +140,7 @@ public: // ISourceMod
|
||||
private:
|
||||
void ShutdownServices();
|
||||
private:
|
||||
const char* GetMapEntitiesString();
|
||||
char m_SMBaseDir[PLATFORM_MAX_PATH];
|
||||
char m_SMRelDir[PLATFORM_MAX_PATH];
|
||||
char m_ModDir[32];
|
||||
|
||||
+55
-57
File diff suppressed because one or more lines are too long
@@ -80,8 +80,15 @@ CallWrapper::CallWrapper(const SourceHook::ProtoInfo *protoInfo) : m_FnFlags(0)
|
||||
CallWrapper::CallWrapper(const SourceHook::ProtoInfo *protoInfo, const PassInfo *retInfo,
|
||||
const PassInfo paramInfo[], unsigned int fnFlags) : CallWrapper(protoInfo)
|
||||
{
|
||||
m_RetParam->fields = retInfo->fields;
|
||||
m_RetParam->numFields = retInfo->numFields;
|
||||
if (retInfo)
|
||||
{
|
||||
m_RetParam->fields = retInfo->fields;
|
||||
m_RetParam->numFields = retInfo->numFields;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RetParam = nullptr;
|
||||
}
|
||||
|
||||
unsigned int argnum = protoInfo->numOfParams;
|
||||
for (unsigned int i = 0; i < argnum; i++)
|
||||
|
||||
@@ -725,7 +725,7 @@ inline void Write_PushObject(JitWriter *jit, const SourceHook::PassInfo *info, u
|
||||
ObjectClass classes[MAX_CLASSES];
|
||||
int numWords = ClassifyObject(smInfo, classes);
|
||||
|
||||
if (classes[0] == ObjectClass::Pointer)
|
||||
if (classes[0] == ObjectClass::Pointer || classes[0] == ObjectClass::Memory)
|
||||
goto push_byref;
|
||||
|
||||
int neededIntRegs = 0;
|
||||
@@ -787,7 +787,7 @@ inline void Write_PushObject(JitWriter *jit, const SourceHook::PassInfo *info, u
|
||||
return;
|
||||
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
if (info->size < 64 && (info->size & (info->size - 1)) == 0)
|
||||
if (info->size > 8 || (info->size & (info->size - 1)) != 0)
|
||||
goto push_byref;
|
||||
else {
|
||||
SourceHook::PassInfo podInfo;
|
||||
@@ -1055,7 +1055,11 @@ void *JIT_CallCompile(CallWrapper *pWrapper, FuncAddrMethod method)
|
||||
int numWords;
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
g_StackUsage = 0;
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
g_StackUsage = 32; // Shadow space
|
||||
#endif
|
||||
|
||||
writer.outbase = NULL;
|
||||
writer.outptr = NULL;
|
||||
@@ -1155,8 +1159,12 @@ skip_retbuffer:
|
||||
#endif
|
||||
|
||||
/* Clean up the calling stack */
|
||||
#ifdef PLATFORM_POSIX
|
||||
if (hasParams && g_StackUsage)
|
||||
#endif
|
||||
{
|
||||
Write_RectifyStack(jit, g_StackAlign);
|
||||
}
|
||||
|
||||
/* Copy the return type to the return buffer if the function is not void */
|
||||
if (pRet && !Needs_Retbuf)
|
||||
|
||||
@@ -398,7 +398,7 @@ cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
|
||||
/* User passed a function id for a callback */
|
||||
if (params[4] != -1)
|
||||
if (!pContext->IsNullFunctionId(params[4]))
|
||||
{
|
||||
pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell);
|
||||
pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[4]));
|
||||
|
||||
@@ -9,15 +9,7 @@ project.sources += [
|
||||
'timeleft.cpp',
|
||||
'forwards.cpp',
|
||||
'util_cstrike.cpp',
|
||||
'../../public/smsdk_ext.cpp',
|
||||
'../../public/CDetour/detours.cpp',
|
||||
'../../public/asm/asm.c',
|
||||
'../../public/libudis86/decode.c',
|
||||
'../../public/libudis86/itab.c',
|
||||
'../../public/libudis86/syn-att.c',
|
||||
'../../public/libudis86/syn-intel.c',
|
||||
'../../public/libudis86/syn.c',
|
||||
'../../public/libudis86/udis86.c',
|
||||
'../../public/smsdk_ext.cpp'
|
||||
]
|
||||
|
||||
for sdk_name in ['css', 'csgo']:
|
||||
@@ -29,31 +21,33 @@ for sdk_name in ['css', 'csgo']:
|
||||
project.sources += ['rulesfix.cpp']
|
||||
|
||||
for cxx in builder.targets:
|
||||
if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]:
|
||||
if not cxx.target.arch in sdk['platforms'][cxx.target.platform]:
|
||||
continue
|
||||
|
||||
cxx.defines += ['HAVE_STRING_H']
|
||||
binary = SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk.ext, sdk)
|
||||
binary = SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk['extension'], sdk)
|
||||
SM.AddCDetour(binary)
|
||||
|
||||
if sdk_name == 'csgo':
|
||||
compiler = binary.compiler
|
||||
compiler.cxxincludes += [os.path.join(sdk.path, 'public', 'steam')]
|
||||
compiler.cxxincludes += [os.path.join(sdk['path'], 'public', 'steam')]
|
||||
compiler.defines += ['VERSION_SAFE_STEAM_API_INTERFACES']
|
||||
|
||||
library_name = ''
|
||||
if cxx.target.platform == 'windows':
|
||||
compiler.linkflags += [os.path.join(sdk.path, 'lib', 'public', 'steam_api.lib')]
|
||||
compiler.linkflags += [os.path.join(sdk['path'], 'lib', 'public', 'steam_api.lib')]
|
||||
elif cxx.target.platform == 'linux':
|
||||
library_name = 'libsteam_api.so'
|
||||
if cxx.target.arch == 'x86_64':
|
||||
source_path = os.path.join(sdk.path, 'lib', 'linux64')
|
||||
source_path = os.path.join(sdk['path'], 'lib', 'linux64')
|
||||
else:
|
||||
source_path = os.path.join(sdk.path, 'lib', 'linux')
|
||||
source_path = os.path.join(sdk['path'], 'lib', 'linux')
|
||||
elif cxx.target.platform == 'mac':
|
||||
library_name = 'libsteam_api.dylib'
|
||||
if cxx.target.arch == 'x86_64':
|
||||
source_path = os.path.join(sdk.path, 'lib', 'osx64')
|
||||
source_path = os.path.join(sdk['path'], 'lib', 'osx64')
|
||||
else:
|
||||
source_path = os.path.join(sdk.path, 'lib', 'mac')
|
||||
source_path = os.path.join(sdk['path'], 'lib', 'mac')
|
||||
|
||||
if library_name:
|
||||
source_path = os.path.join(source_path, library_name)
|
||||
|
||||
@@ -100,7 +100,7 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
g_pHandleBuyForward = forwards->CreateForward("CS_OnBuyCommand", ET_Event, 2, NULL, Param_Cell, Param_String);
|
||||
g_pPriceForward = forwards->CreateForward("CS_OnGetWeaponPrice", ET_Event, 3, NULL, Param_Cell, Param_String, Param_CellByRef);
|
||||
g_pTerminateRoundForward = forwards->CreateForward("CS_OnTerminateRound", ET_Event, 2, NULL, Param_FloatByRef, Param_CellByRef);
|
||||
g_pCSWeaponDropForward = forwards->CreateForward("CS_OnCSWeaponDrop", ET_Event, 2, NULL, Param_Cell, Param_Cell);
|
||||
g_pCSWeaponDropForward = forwards->CreateForward("CS_OnCSWeaponDrop", ET_Event, 3, NULL, Param_Cell, Param_Cell, Param_Cell);
|
||||
|
||||
|
||||
m_TerminateRoundDetourEnabled = false;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user