Compare commits
484 Commits
1.10-fork
...
1.11-fork-
Author | SHA1 | Date | |
---|---|---|---|
|
0cf8f2b11f | ||
|
91cc6b300c | ||
|
ec3351a320 | ||
|
aa2a71fc67 | ||
|
142e76bd92 | ||
|
632429700b | ||
|
a8d95ca044 | ||
|
28b4b248f7 | ||
|
964c9ae835 | ||
|
d099dbb659 | ||
|
688e274c30 | ||
|
a5ff53f00f | ||
|
38fc001a1d | ||
|
4b949e8228 | ||
|
080c4bb8e2 | ||
|
149b16cbf3 | ||
|
b940b01be4 | ||
|
45258b8561 | ||
|
ab7b9b231d | ||
|
76c2addeb9 | ||
|
7cb7703cf9 | ||
|
c2b204e810 | ||
|
24c92c021c | ||
|
dd370c3904 | ||
|
384fb668d1 | ||
|
1903c0bd2b | ||
|
13034eff05 | ||
|
a4703722be | ||
|
2e13460823 | ||
|
d356d80537 | ||
|
412759cbc4 | ||
|
08841227a4 | ||
|
18b2ffa786 | ||
|
3e9a48c778 | ||
|
339fd85c6f | ||
|
59144cf868 | ||
|
ad3a44427a | ||
|
737d8c3240 | ||
|
4688783baf | ||
|
ba5c6ad07c | ||
|
69045ccd52 | ||
|
cf39d4b820 | ||
|
cb218a4911 | ||
|
344284196c | ||
|
e7c0726acd | ||
|
d0b34e783d | ||
|
d481e5fcb7 | ||
|
1459c10112 | ||
|
8b9131f6e4 | ||
|
ce1a21ba0b | ||
|
e2237ce875 | ||
|
250bbf5955 | ||
|
0478912d73 | ||
|
d50e4b7a2f | ||
|
abf59a4f4b | ||
|
9b80e46097 | ||
|
bbbaebd32a | ||
|
1204d1fd0f | ||
|
ef34cc67b6 | ||
|
25184aa9c7 | ||
|
b789d30658 | ||
|
305799b441 | ||
|
92fc27f67f | ||
|
5292721f0b | ||
|
4e0c47a1d5 | ||
|
65b6602a19 | ||
|
1723f97202 | ||
|
ec92653bb7 | ||
|
b25d25890a | ||
|
b27243c3ac | ||
|
be648382d7 | ||
|
b5ed266941 | ||
|
2ffaa04130 | ||
|
eddf9cf843 | ||
|
7c1095e4e7 | ||
|
686e8b4d7e | ||
|
edc73649ff | ||
|
1ad8bb4560 | ||
|
7eabeaa384 | ||
|
4547270934 | ||
|
3a2c5cb0f7 | ||
|
7648c7fe03 | ||
|
ffb6d769e8 | ||
|
77f999f810 | ||
|
c5049990a3 | ||
|
0e4894e8db | ||
|
19f1ffa401 | ||
|
c206ac3099 | ||
|
e03320c80e | ||
|
2ae4624344 | ||
|
66c8005666 | ||
|
210219030e | ||
|
370fa8209b | ||
|
88a0a458a6 | ||
|
e4afe31fc0 | ||
|
fb0144900f | ||
|
542b7673d6 | ||
|
cc1c02e3de | ||
|
4fc0a85581 | ||
|
6733c4182d | ||
|
28ef59ada5 | ||
|
647e320b57 | ||
|
cdfbdcc29d | ||
|
4f94b4f900 | ||
|
53be0e0812 | ||
|
88dd142f5c | ||
|
1d5ec7b982 | ||
|
f1a71b0d5a | ||
|
85b8e09e8a | ||
|
df9b0ef1b3 | ||
|
f81412b4fa | ||
|
bd478ebdfc | ||
|
a57573864a | ||
|
6b6436db17 | ||
|
c88b18e520 | ||
|
8c001872a8 | ||
|
5db571bbc6 | ||
|
1f561b54f3 | ||
|
77a0fb4402 | ||
|
c72736dcfa | ||
|
d16f45c4b6 | ||
|
e280d33a28 | ||
|
fb1d501c24 | ||
|
3c0f700a6b | ||
|
45e9da90fc | ||
|
a60c443b29 | ||
|
b064366169 | ||
|
a06a903989 | ||
|
e67fdf2331 | ||
|
e2ca3a9493 | ||
|
9099634b95 | ||
|
f182feed9d | ||
|
02dd6a9c00 | ||
|
b421a0c594 | ||
|
9ec5cb819c | ||
|
f8e664b797 | ||
|
42575f7cc3 | ||
|
aa98f60ca3 | ||
|
d5f47a88e6 | ||
|
62f08a31fc | ||
|
e565c83494 | ||
|
a68ff2a587 | ||
|
377888276e | ||
|
52b8e95aae | ||
|
bb6e6fd3b6 | ||
|
0449342bb0 | ||
|
3171d4fb7b | ||
|
066818fbec | ||
|
255f5ea745 | ||
|
2e763c287c | ||
|
29c33bfcc9 | ||
|
88bdbf4866 | ||
|
1559b75ae7 | ||
|
ff00e3d036 | ||
|
daa1a4df14 | ||
|
4e2ace9d2f | ||
|
ee722d778f | ||
|
e82f0acdb8 | ||
|
383cd81be6 | ||
|
6250db7dba | ||
|
8ae3be7185 | ||
|
64b897822f | ||
|
0ad0d839a0 | ||
|
55382e0a0f | ||
|
d8b00675d6 | ||
|
633298b6a9 | ||
|
656a9fa94f | ||
|
bb7929594d | ||
|
d4545a105e | ||
|
1c788b5c0a | ||
|
7ce8a80bf6 | ||
|
d0c4657b75 | ||
|
167e6d8571 | ||
|
b909ea07ec | ||
|
410eb01f91 | ||
|
f18c6fb9af | ||
|
c66175d64e | ||
|
a3fbbe41f2 | ||
|
ed5713b3fd | ||
|
4b01feea45 | ||
|
800f613f92 | ||
|
4c9e856197 | ||
|
0cb3fcaed8 | ||
|
02e2659ba5 | ||
|
507b09c975 | ||
|
907fa77381 | ||
|
c5c302dccc | ||
|
c49d51206c | ||
|
f48cbaab75 | ||
|
61c634a870 | ||
|
fec978afb4 | ||
|
74ad70ba30 | ||
|
fe27c8810e | ||
|
b4c5726fc2 | ||
|
53c8d5533a | ||
|
4e66452e58 | ||
|
63545eb741 | ||
|
a7af242453 | ||
|
f503139fae | ||
|
5ea096e61e | ||
|
f4ff2ad45a | ||
|
4fb57dc4e3 | ||
|
b8c5303b05 | ||
|
3c79701208 | ||
|
e82f88dfa9 | ||
|
296deb95e6 | ||
|
c6917296d3 | ||
|
b3672916de | ||
|
7c3cb49dfa | ||
|
b383302128 | ||
|
32d951e312 | ||
|
f8f5a18d67 | ||
|
2d241316c7 | ||
|
6a2ac9800b | ||
|
39aa75436e | ||
|
f708842e09 | ||
|
86af9601bd | ||
|
5b7c9c5845 | ||
|
7f2fdf3fe1 | ||
|
70c9a6528a | ||
|
54364d213d | ||
|
4d6b9895d3 | ||
|
f927455778 | ||
|
6928d21bcf | ||
|
38eecd5ece | ||
|
5aedb73aae | ||
|
387b85406e | ||
|
823b55c22a | ||
|
fdfb8837d1 | ||
|
d7c359c412 | ||
|
82c51dbe75 | ||
|
77259acf9e | ||
|
7816379aae | ||
|
d192527707 | ||
|
b0563a493c | ||
|
c38d45b9e7 | ||
|
f603b7aec3 | ||
|
a9d3cf4574 | ||
|
3b2fa89926 | ||
|
0d956b229f | ||
|
d73f4e7eca | ||
|
2778b132f0 | ||
|
1eae765dc3 | ||
|
267eb90da5 | ||
|
8075ce8371 | ||
|
d01c72f79b | ||
|
8f73e5e5a1 | ||
|
62142197c1 | ||
|
ff43e60831 | ||
|
6b9037790a | ||
|
babc6abc64 | ||
|
66d932c79f | ||
|
7be2f50a98 | ||
|
499f7160a4 | ||
|
7aca0cc77f | ||
|
c874703136 | ||
|
e6129ab2d9 | ||
|
4a43ac1bdd | ||
|
6b7fd8c3dc | ||
|
845c20ad93 | ||
|
47c050d5b6 | ||
|
1fbe5e1daa | ||
|
2b1cc43355 | ||
|
62cb6a0458 | ||
|
ca1dcc9bed | ||
|
5a72644486 | ||
|
e552466886 | ||
|
65043baf5d | ||
|
46c54f829c | ||
|
4dd5ab7576 | ||
|
ee27a48714 | ||
|
e5342afe2a | ||
|
3c30f7b971 | ||
|
99c39b1d57 | ||
|
ae485c3115 | ||
|
6c2be9bdcc | ||
|
1a11d92fd9 | ||
|
52c4d08e15 | ||
|
6ea1e39ee4 | ||
|
f9633a5f6f | ||
|
5bc48b2ab3 | ||
|
70b6e96f95 | ||
|
91a1fd074b | ||
|
a615c139e6 | ||
|
978fa6b252 | ||
|
24f90449ad | ||
|
ba8753836e | ||
|
e59fd9de96 | ||
|
6c4079cb94 | ||
|
c2b806563e | ||
|
15d912df38 | ||
|
a191a907e9 | ||
|
0caa349f6a | ||
|
1cd0efad41 | ||
|
9d49bbfaf0 | ||
|
3eb2cd2971 | ||
|
8e7d41ec02 | ||
|
94ea925152 | ||
|
18d93ff677 | ||
|
d48cf93a94 | ||
|
104b6b878a | ||
|
90b68f095f | ||
|
6a4364d404 | ||
|
5e819f6596 | ||
|
eef96da641 | ||
|
c38b392fdf | ||
|
e0d9dfb68e | ||
|
589d6df75d | ||
|
6fd9d1ce11 | ||
|
ef36604666 | ||
|
db56b14637 | ||
|
b14c18ee64 | ||
|
2c94ab3b1c | ||
|
f12b3a2e13 | ||
|
ea3f55f030 | ||
|
6e2c5a66b3 | ||
|
0bed34e0c7 | ||
|
f0d8a70b38 | ||
|
9acf2b5cda | ||
|
d49b92603a | ||
|
aa01a22416 | ||
|
50e43a9f98 | ||
|
ed325c7208 | ||
|
aac2c4a080 | ||
|
785c6aa1cf | ||
|
1b86c8564d | ||
|
031f80f6e1 | ||
|
6f21138489 | ||
|
7bab9cc344 | ||
|
510bd261f8 | ||
|
c5619f887d | ||
|
bb25b03884 | ||
|
9bbbf60268 | ||
|
37355f9c57 | ||
|
af76f757b5 | ||
|
b7650b11d6 | ||
|
a0d06b3209 | ||
|
c52edbd863 | ||
|
7355e34946 | ||
|
5fa25e70ad | ||
|
b8ae4e617b | ||
|
353ced0e41 | ||
|
ed9f214256 | ||
|
939bdaf669 | ||
|
2d2ba818e7 | ||
|
2653a450fc | ||
|
a065773b6d | ||
|
4e0ae0cb5e | ||
|
611bad4036 | ||
|
4a4b9ce7f0 | ||
|
100f1e56ca | ||
|
69ae224938 | ||
|
287628bfee | ||
|
f27dc2f4f4 | ||
|
1282f13442 | ||
|
47514c7708 | ||
|
b364bf8b06 | ||
|
dea3ef70a2 | ||
|
1cc7d37189 | ||
|
3164af7e34 | ||
|
4c8103a4e1 | ||
|
2ebbf2774b | ||
|
15450a6d0c | ||
|
832519ab64 | ||
|
4e2806c951 | ||
|
7e0dd1fd41 | ||
|
2d971a9fb7 | ||
|
3b386379dd | ||
|
7b887ee9f6 | ||
|
67f0e4be60 | ||
|
80acff8d7d | ||
|
d5d4d78023 | ||
|
5d94f0bea8 | ||
|
e5ddbd9886 | ||
|
d525b466ec | ||
|
333227fad8 | ||
|
288a781555 | ||
|
979e410efc | ||
|
75fa198321 | ||
|
49669f6585 | ||
|
acf8782786 | ||
|
6d2e0aa684 | ||
|
032a30f676 | ||
|
c9f574c27b | ||
|
b725196a26 | ||
|
301bafa3f5 | ||
|
7a3e4054c7 | ||
|
7d7253c9cc | ||
|
c2df49ee33 | ||
|
a253e175bb | ||
|
15023777f4 | ||
|
ff018a9a5d | ||
|
f76cb94511 | ||
|
87cc42d348 | ||
|
5177cfdf97 | ||
|
13621a1274 | ||
|
bc89e54f6d | ||
|
5ed2f79217 | ||
|
3696a4cd9e | ||
|
8259bd316a | ||
|
6717f45469 | ||
|
44615b7ade | ||
|
f3200b2232 | ||
|
881cbcd45d | ||
|
30a4032067 | ||
|
5597fc56d3 | ||
|
adcc0efda6 | ||
|
d044b13ce4 | ||
|
d42c304a55 | ||
|
d876f04baf | ||
|
593552f8d6 | ||
|
25462071df | ||
|
1d98c3a782 | ||
|
7f239bb931 | ||
|
23efe26655 | ||
|
ece447182f | ||
|
6465bd83a4 | ||
|
e941c1acea | ||
|
ecad8f25a8 | ||
|
48c3a9f2fa | ||
|
d59edc5d0a | ||
|
17440fc4be | ||
|
bff8585411 | ||
|
6a307bfcee | ||
|
604942f0e7 | ||
|
22eeb2f3a5 | ||
|
cc6059a4b7 | ||
|
91480b6b91 | ||
|
4a8e0799bd | ||
|
bcd5e40842 | ||
|
9fb6430313 | ||
|
68e45f3583 | ||
|
a1ed47be87 | ||
|
ded3867605 | ||
|
2b6833f65d | ||
|
4d38f11367 | ||
|
a3dd25f354 | ||
|
4b0e73ca5a | ||
|
cd37354634 | ||
|
8a5d0a58e4 | ||
|
1a71f4fbde | ||
|
1534f8749b | ||
|
4ea85a9291 | ||
|
739c07ca9b | ||
|
452338dc11 | ||
|
b6a6387f16 | ||
|
4a8c869b7e | ||
|
c052eb3969 | ||
|
48ed38a8c1 | ||
|
fba71ed24d | ||
|
625650c160 | ||
|
9f4c6c61d9 | ||
|
9d978f5581 | ||
|
664b352559 | ||
|
cfa4998ac1 | ||
|
5efe6d0a42 | ||
|
e34fbcce0d | ||
|
8746b2fd7f | ||
|
4328627326 | ||
|
fc6925fa0a | ||
|
b5de3eb588 | ||
|
26422fd425 | ||
|
cd1a296e4f | ||
|
3ddf9f8a0d | ||
|
82df6087af | ||
|
bef8562de5 | ||
|
1000d419fc | ||
|
2a9deb6a64 | ||
|
351e406f85 | ||
|
d6e518838f | ||
|
9e39f18230 | ||
|
3dd1e5a318 | ||
|
23e1c0b71e | ||
|
a1436cd205 | ||
|
0d320b7922 | ||
|
b2a0d0e4da | ||
|
273f058da9 | ||
|
c6f751bb67 | ||
|
00b7ac5a39 | ||
|
c0686dc4f9 | ||
|
7ab3a3cfd9 | ||
|
06d327e76c | ||
|
2e28b036f8 | ||
|
5293815bf6 |
98
.github/workflows/ci.yml
vendored
Normal file
98
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
name: Continuous Integration
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-18.04, ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
os_short: win
|
||||||
|
compiler_cc: msvc
|
||||||
|
- os: ubuntu-latest
|
||||||
|
os_short: linux
|
||||||
|
compiler_cc: clang
|
||||||
|
compiler_cxx: clang++
|
||||||
|
- os: ubuntu-18.04
|
||||||
|
os_short: linux
|
||||||
|
compiler_cc: clang-8
|
||||||
|
compiler_cxx: clang++-8
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
name: ${{ matrix.os_short }}-${{ matrix.compiler_cc }}
|
||||||
|
env:
|
||||||
|
SDKS: '["episode1","css","tf2","l4d2","csgo"]'
|
||||||
|
ARCH: x86,x86_64
|
||||||
|
DEPENDENCIES_FOLDER: dependencies
|
||||||
|
DEPENDENCIES_ROOT: ${{ github.workspace }}/dependencies
|
||||||
|
MYSQL_VERSION: '5.5'
|
||||||
|
MMSOURCE_VERSION: '1.10'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
path: sourcemod
|
||||||
|
|
||||||
|
- name: Cache dependencies
|
||||||
|
uses: actions/cache@v2
|
||||||
|
env:
|
||||||
|
cache-name: hl2sdk-mysql-mmsource
|
||||||
|
with:
|
||||||
|
path: ${{ env.DEPENDENCIES_ROOT }}
|
||||||
|
key: ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-${{ join(fromJSON(env.SDKS), '') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-
|
||||||
|
|
||||||
|
# Setup Python for AMBuild
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
name: Setup Python 3.8
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p ${{ env.DEPENDENCIES_FOLDER }}
|
||||||
|
cd ${{ env.DEPENDENCIES_FOLDER }}
|
||||||
|
|
||||||
|
# Satisfy checkout-deps requirement for a "sourcemod" folder.
|
||||||
|
mkdir -p sourcemod
|
||||||
|
../sourcemod/tools/checkout-deps.sh -s ${{ join(fromJSON(env.SDKS)) }}
|
||||||
|
|
||||||
|
- name: Install Linux dependencies
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||||
|
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||||
|
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||||
|
|
||||||
|
- name: Select clang compiler
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
echo "CC=${{ matrix.compiler_cc }}" >> $GITHUB_ENV
|
||||||
|
echo "CXX=${{ matrix.compiler_cxx }}" >> $GITHUB_ENV
|
||||||
|
${{ matrix.compiler_cc }} --version
|
||||||
|
${{ matrix.compiler_cxx }} --version
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: sourcemod
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
python ../configure.py --enable-optimize --sdks=${{ join(fromJSON(env.SDKS)) }} --targets=${{ env.ARCH }} --mms-path=${{ env.DEPENDENCIES_ROOT }}/mmsource-${{ env.MMSOURCE_VERSION }} --hl2sdk-root=${{ env.DEPENDENCIES_ROOT }} --mysql-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }} --mysql64-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }}-x86_64
|
||||||
|
ambuild
|
79
.github/workflows/scripting.yml
vendored
Normal file
79
.github/workflows/scripting.yml
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
name: SourcePawn scripting
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
paths:
|
||||||
|
- 'plugins/include/*'
|
||||||
|
- 'sourcepawn/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '53 05 01 */3 *' # Artifacts expire every 3 months
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
os_short: linux
|
||||||
|
- os: windows-latest
|
||||||
|
os_short: win
|
||||||
|
- os: macos-latest
|
||||||
|
os_short: mac
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
ARCH: x86,x86_64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
# Setup Python for AMBuild
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
name: Setup Python 3.8
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
- name: Install AMBuild
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
pip install git+https://github.com/alliedmodders/ambuild
|
||||||
|
|
||||||
|
- name: Build only for x64 on macOS
|
||||||
|
if: startsWith(runner.os, 'macOS')
|
||||||
|
run: echo "ARCH=x86_64" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install Linux dependencies
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||||
|
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||||
|
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||||
|
|
||||||
|
- name: Select clang compiler
|
||||||
|
if: startsWith(runner.os, 'Linux') || startsWith(runner.os, 'macOS')
|
||||||
|
run: |
|
||||||
|
echo "CC=clang" >> $GITHUB_ENV
|
||||||
|
echo "CXX=clang++" >> $GITHUB_ENV
|
||||||
|
clang --version
|
||||||
|
clang++ --version
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
python ../configure.py --enable-optimize --scripting-only --targets=${{ env.ARCH }}
|
||||||
|
ambuild
|
||||||
|
echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Archive tooling
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
|
||||||
|
path: build/package
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -28,7 +28,7 @@ LIB-Debug/
|
|||||||
[Tt]humbs.db
|
[Tt]humbs.db
|
||||||
|
|
||||||
# AMBuild build directories
|
# AMBuild build directories
|
||||||
build/
|
build*/
|
||||||
obj-*/
|
obj-*/
|
||||||
*~
|
*~
|
||||||
*.rej
|
*.rej
|
||||||
@ -36,3 +36,7 @@ obj-*/
|
|||||||
*.smx
|
*.smx
|
||||||
*.swp
|
*.swp
|
||||||
*.gdb_history
|
*.gdb_history
|
||||||
|
objdir
|
||||||
|
|
||||||
|
.vs/*
|
||||||
|
.vscode/*
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,6 +1,8 @@
|
|||||||
[submodule "public/amtl"]
|
[submodule "public/amtl"]
|
||||||
path = public/amtl
|
path = public/amtl
|
||||||
url = https://github.com/alliedmodders/amtl
|
url = https://github.com/alliedmodders/amtl
|
||||||
|
shallow = true
|
||||||
[submodule "sourcepawn"]
|
[submodule "sourcepawn"]
|
||||||
path = sourcepawn
|
path = sourcepawn
|
||||||
url = https://github.com/BotoX/sourcepawn.git
|
url = https://github.com/alliedmodders/sourcepawn
|
||||||
|
shallow = true
|
||||||
|
146
.travis.yml
146
.travis.yml
@ -1,118 +1,86 @@
|
|||||||
git:
|
git:
|
||||||
depth: 3
|
depth: 3
|
||||||
|
|
||||||
sudo: false
|
|
||||||
language: cpp
|
language: cpp
|
||||||
os: linux
|
os: linux
|
||||||
dist: trusty
|
dist: xenial
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
- llvm-toolchain-trusty-3.9
|
|
||||||
- llvm-toolchain-trusty-4.0
|
|
||||||
- llvm-toolchain-trusty-5.0
|
|
||||||
packages:
|
|
||||||
- lib32stdc++6
|
|
||||||
- lib32z1-dev
|
|
||||||
- libc6-dev-i386
|
|
||||||
- linux-libc-dev
|
|
||||||
- g++-multilib
|
|
||||||
# - clang-3.6
|
|
||||||
# - clang-3.8
|
|
||||||
# - clang-4.0
|
|
||||||
# - clang-5.0
|
|
||||||
# - g++-6
|
|
||||||
# - g++-6-multilib
|
|
||||||
- clang-3.9
|
|
||||||
- g++-4.8-multilib
|
|
||||||
- g++-4.8
|
|
||||||
- g++-4.9-multilib
|
|
||||||
- g++-4.9
|
|
||||||
- g++-5-multilib
|
|
||||||
- g++-5
|
|
||||||
- g++-7-multilib
|
|
||||||
- g++-7
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- ../mysql-5.0
|
|
||||||
env:
|
|
||||||
- MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9"
|
|
||||||
- MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8"
|
|
||||||
- MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
|
|
||||||
- MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
|
|
||||||
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
|
|
||||||
|
|
||||||
matrix:
|
jobs:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
dist: trusty
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages: ['clang-3.6', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
sources:
|
||||||
cache:
|
- ubuntu-toolchain-r-test
|
||||||
directories: ['../mysql-5.0']
|
packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip']
|
||||||
env: ['MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6"']
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"
|
||||||
|
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||||
|
- MODE=optimize
|
||||||
|
- ARCH=x86,x86_64
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
dist: trusty
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
sources:
|
||||||
cache:
|
- ubuntu-toolchain-r-test
|
||||||
directories: ['../mysql-5.0']
|
packages: ['clang-3.4', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip']
|
||||||
env: ['MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"']
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
|
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||||
|
- MODE=optimize
|
||||||
|
- ARCH=x86,x86_64
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode7.2
|
||||||
|
language: cpp
|
||||||
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
|
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||||
|
- MODE=optimize
|
||||||
|
- ARCH=x86_64,x86
|
||||||
|
|
||||||
|
# # This is a faster test for the latest g++.
|
||||||
|
# - os: linux
|
||||||
|
# dist: bionic
|
||||||
|
# sudo: false
|
||||||
|
# language: cpp
|
||||||
|
# addons:
|
||||||
|
# apt:
|
||||||
|
# packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'g++']
|
||||||
|
# cache:
|
||||||
|
# directories: ['../mysql-5.0']
|
||||||
|
# env:
|
||||||
|
# - MATRIX_EVAL="CC=gcc && CXX=g++"
|
||||||
|
# - SDKS=csgo
|
||||||
|
# # GCC currently fails in opt builds trying to inline stuff in sqlite3.c.
|
||||||
|
# - MODE=debug
|
||||||
|
|
||||||
|
# This is a faster test for the latest clang.
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
dist: bionic
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['llvm-toolchain-trusty-4.0']
|
packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'clang']
|
||||||
packages: ['clang-4.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
env:
|
||||||
cache:
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
directories: ['../mysql-5.0']
|
- SDKS=csgo
|
||||||
env: ['MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"']
|
- MODE=optimize
|
||||||
|
- ARCH=x86
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
language: cpp
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['llvm-toolchain-trusty-5.0']
|
|
||||||
packages: ['clang-5.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
|
||||||
cache:
|
|
||||||
directories: ['../mysql-5.0']
|
|
||||||
env: ['MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"']
|
|
||||||
|
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
language: cpp
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
|
||||||
packages: ['g++-6', 'g++-6-multilib', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
|
||||||
cache:
|
|
||||||
directories: ['../mysql-5.0']
|
|
||||||
env: ['MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"']
|
|
||||||
|
|
||||||
allow_failures:
|
|
||||||
- env: MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7"
|
|
||||||
- env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
|
|
||||||
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
|
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh -s ${SDKS} && cd $CHECKOUT_DIR
|
||||||
script:
|
script:
|
||||||
- mkdir build && cd build
|
- mkdir build && cd build
|
||||||
- PATH="~/.local/bin:$PATH"
|
- PATH="~/.local/bin:$PATH"
|
||||||
- eval "${MATRIX_EVAL}"
|
- eval "${MATRIX_EVAL}"
|
||||||
- python ../configure.py --enable-optimize --sdks=episode1,css,tf2,l4d2,csgo,dota
|
- eval "${CC} --version"
|
||||||
|
- eval "${CXX} --version"
|
||||||
|
- python3 ../configure.py --enable-${MODE} --sdks=${SDKS} --targets=${ARCH}
|
||||||
- ambuild
|
- ambuild
|
||||||
|
539
AMBuildScript
539
AMBuildScript
@ -1,5 +1,8 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
|
import collections
|
||||||
import os, sys
|
import os, sys
|
||||||
|
import subprocess
|
||||||
|
import traceback
|
||||||
|
|
||||||
class SDK(object):
|
class SDK(object):
|
||||||
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
||||||
@ -19,23 +22,33 @@ class SDK(object):
|
|||||||
else:
|
else:
|
||||||
self.platformSpec = platform
|
self.platformSpec = platform
|
||||||
|
|
||||||
def shouldBuild(self, target, archs):
|
def shouldBuild(self, targets):
|
||||||
if target.platform not in self.platformSpec:
|
for cxx in targets:
|
||||||
return False
|
if cxx.target.platform in self.platformSpec:
|
||||||
if not len([i for i in self.platformSpec[target.platform] if i in archs]):
|
if cxx.target.arch in self.platformSpec[cxx.target.platform]:
|
||||||
return False
|
return True
|
||||||
return True
|
return False
|
||||||
|
|
||||||
WinOnly = ['windows']
|
WinOnly = ['windows']
|
||||||
WinLinux = ['windows', 'linux']
|
WinLinux = ['windows', 'linux']
|
||||||
WinLinuxMac = ['windows', 'linux', 'mac']
|
WinLinuxMac = ['windows', 'linux', 'mac']
|
||||||
|
Blade = {
|
||||||
|
'windows': ['x86', 'x86_64'],
|
||||||
|
'linux': ['x86_64'],
|
||||||
|
'mac': ['x86_64']
|
||||||
|
}
|
||||||
CSGO = {
|
CSGO = {
|
||||||
'windows': ['x86'],
|
'windows': ['x86'],
|
||||||
'linux': ['x86', 'x64'],
|
'linux': ['x86', 'x86_64'],
|
||||||
'mac': ['x64']
|
'mac': ['x86_64']
|
||||||
|
}
|
||||||
|
Mock = {
|
||||||
|
'windows': ['x86', 'x86_64'],
|
||||||
|
'linux': ['x86', 'x86_64'],
|
||||||
|
'mac': ['x86_64']
|
||||||
}
|
}
|
||||||
|
|
||||||
PossibleSDKs = {
|
SDKMap = {
|
||||||
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
||||||
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
||||||
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
|
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
|
||||||
@ -52,13 +65,19 @@ PossibleSDKs = {
|
|||||||
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
||||||
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
|
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
|
||||||
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
|
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
|
||||||
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'),
|
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', Blade, 'blade'),
|
||||||
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
||||||
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
|
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
|
||||||
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
|
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
|
||||||
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
|
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
|
||||||
|
'mock': SDK('HL2SDK-MOCK', '2.mock', '999', 'MOCK', Mock, 'mock'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Stable sorting for command equivalence in AMBuild.
|
||||||
|
PossibleSDKs = collections.OrderedDict()
|
||||||
|
for key in sorted(SDKMap.keys()):
|
||||||
|
PossibleSDKs[key] = SDKMap[key]
|
||||||
|
|
||||||
def ResolveEnvPath(env, folder):
|
def ResolveEnvPath(env, folder):
|
||||||
if env in os.environ:
|
if env in os.environ:
|
||||||
path = os.environ[env]
|
path = os.environ[env]
|
||||||
@ -80,32 +99,19 @@ def ResolveEnvPath(env, folder):
|
|||||||
def Normalize(path):
|
def Normalize(path):
|
||||||
return os.path.abspath(os.path.normpath(path))
|
return os.path.abspath(os.path.normpath(path))
|
||||||
|
|
||||||
def SetArchFlags(compiler, arch, platform):
|
def SetArchFlags(compiler):
|
||||||
if compiler.behavior == 'gcc':
|
if compiler.behavior == 'gcc':
|
||||||
if arch == 'x86':
|
if compiler.target.arch == 'x86_64':
|
||||||
compiler.cflags += ['-m32']
|
compiler.cflags += ['-fPIC']
|
||||||
compiler.linkflags += ['-m32']
|
|
||||||
if platform == 'mac':
|
|
||||||
compiler.linkflags += ['-arch', 'i386']
|
|
||||||
elif arch == 'x64':
|
|
||||||
compiler.cflags += ['-m64', '-fPIC']
|
|
||||||
compiler.linkflags += ['-m64']
|
|
||||||
if platform == 'mac':
|
|
||||||
compiler.linkflags += ['-arch', 'x86_64']
|
|
||||||
elif compiler.like('msvc'):
|
elif compiler.like('msvc'):
|
||||||
if builder.target.arch == 'x86':
|
if compiler.target.arch == 'x86_64':
|
||||||
compiler.linkflags += ['/MACHINE:X86']
|
compiler.defines += ['WIN64']
|
||||||
elif builder.target.arch == 'x64':
|
|
||||||
compiler.linkflags += ['/MACHINE:X64']
|
|
||||||
|
|
||||||
def AppendArchSuffix(binary, name, arch):
|
|
||||||
if arch == 'x64':
|
|
||||||
binary.localFolder = name + '.x64'
|
|
||||||
|
|
||||||
class SMConfig(object):
|
class SMConfig(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sdks = {}
|
self.sdks = {}
|
||||||
self.binaries = []
|
self.binaries = []
|
||||||
|
self.spvm = []
|
||||||
self.extensions = []
|
self.extensions = []
|
||||||
self.generated_headers = None
|
self.generated_headers = None
|
||||||
self.mms_root = None
|
self.mms_root = None
|
||||||
@ -114,7 +120,32 @@ class SMConfig(object):
|
|||||||
self.spcomp_bins = None
|
self.spcomp_bins = None
|
||||||
self.smx_files = {}
|
self.smx_files = {}
|
||||||
self.versionlib = None
|
self.versionlib = None
|
||||||
self.archs = builder.target.arch.replace('x86_64', 'x64').split(',')
|
self.all_targets = []
|
||||||
|
self.target_archs = set()
|
||||||
|
self.enable_asan = getattr(builder.options, 'enable_asan', False)
|
||||||
|
self.asan_libs = {}
|
||||||
|
|
||||||
|
if builder.options.targets:
|
||||||
|
target_archs = builder.options.targets.split(',')
|
||||||
|
else:
|
||||||
|
target_archs = ['x86']
|
||||||
|
if builder.backend != 'amb2':
|
||||||
|
target_archs.append('x86_64')
|
||||||
|
|
||||||
|
for arch in target_archs:
|
||||||
|
try:
|
||||||
|
cxx = builder.DetectCxx(target_arch = arch)
|
||||||
|
self.target_archs.add(cxx.target.arch)
|
||||||
|
except Exception as e:
|
||||||
|
# Error if archs were manually overridden.
|
||||||
|
if builder.options.targets:
|
||||||
|
raise
|
||||||
|
print('Skipping target {}: {}'.format(arch, e))
|
||||||
|
continue
|
||||||
|
self.all_targets.append(cxx)
|
||||||
|
|
||||||
|
if not self.all_targets:
|
||||||
|
raise Exception('No suitable C/C++ compiler was found.')
|
||||||
|
|
||||||
def use_auto_versioning(self):
|
def use_auto_versioning(self):
|
||||||
if builder.backend != 'amb2':
|
if builder.backend != 'amb2':
|
||||||
@ -143,32 +174,34 @@ class SMConfig(object):
|
|||||||
|
|
||||||
def detectSDKs(self):
|
def detectSDKs(self):
|
||||||
sdk_list = builder.options.sdks.split(',')
|
sdk_list = builder.options.sdks.split(',')
|
||||||
|
use_none = sdk_list[0] == 'none'
|
||||||
use_all = sdk_list[0] == 'all'
|
use_all = sdk_list[0] == 'all'
|
||||||
use_present = sdk_list[0] == 'present'
|
use_present = sdk_list[0] == 'present'
|
||||||
|
|
||||||
for sdk_name in PossibleSDKs:
|
for sdk_name in PossibleSDKs:
|
||||||
sdk = PossibleSDKs[sdk_name]
|
sdk = PossibleSDKs[sdk_name]
|
||||||
if sdk.shouldBuild(builder.target, self.archs):
|
if sdk.shouldBuild(self.all_targets):
|
||||||
if builder.options.hl2sdk_root:
|
if builder.options.hl2sdk_root:
|
||||||
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
||||||
else:
|
else:
|
||||||
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
||||||
if sdk_path is None or not os.path.isdir(sdk_path):
|
if sdk_path is None or not os.path.isdir(sdk_path):
|
||||||
if use_all or sdk_name in sdk_list:
|
if (use_all and sdk_name != 'mock') or sdk_name in sdk_list:
|
||||||
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
||||||
continue
|
continue
|
||||||
if use_all or use_present or sdk_name in sdk_list:
|
if use_all or use_present or sdk_name in sdk_list:
|
||||||
sdk.path = Normalize(sdk_path)
|
sdk.path = Normalize(sdk_path)
|
||||||
self.sdks[sdk_name] = sdk
|
self.sdks[sdk_name] = sdk
|
||||||
|
|
||||||
if len(self.sdks) < 1 and len(sdk_list):
|
if len(self.sdks) < 1 and len(sdk_list) and not use_none:
|
||||||
raise Exception('No SDKs were found that build on {0}-{1}, nothing to do.'.format(
|
raise Exception('No applicable SDKs were found, nothing to do')
|
||||||
builder.target.platform, builder.target.arch))
|
|
||||||
|
|
||||||
if builder.options.mms_path:
|
if builder.options.mms_path:
|
||||||
self.mms_root = builder.options.mms_path
|
self.mms_root = builder.options.mms_path
|
||||||
else:
|
else:
|
||||||
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
self.mms_root = ResolveEnvPath('MMSOURCE111', 'mmsource-1.11')
|
||||||
|
if not self.mms_root:
|
||||||
|
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
||||||
if not self.mms_root:
|
if not self.mms_root:
|
||||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||||
if not self.mms_root:
|
if not self.mms_root:
|
||||||
@ -179,40 +212,49 @@ class SMConfig(object):
|
|||||||
self.mms_root = Normalize(self.mms_root)
|
self.mms_root = Normalize(self.mms_root)
|
||||||
|
|
||||||
if builder.options.hasMySql:
|
if builder.options.hasMySql:
|
||||||
if builder.options.mysql_path:
|
if 'x86' in self.target_archs:
|
||||||
self.mysql_root['x86'] = builder.options.mysql_path
|
if builder.options.mysql_path:
|
||||||
else:
|
self.mysql_root['x86'] = builder.options.mysql_path
|
||||||
for i in range(10):
|
|
||||||
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
|
|
||||||
if self.mysql_root['x86']:
|
|
||||||
break
|
|
||||||
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
|
|
||||||
raise Exception('Could not find a path to MySQL!')
|
|
||||||
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
|
|
||||||
|
|
||||||
# For now, ignore 64-bit MySQL on Windows
|
|
||||||
if 'x64' in self.archs and builder.target.platform != 'windows':
|
|
||||||
if builder.options.mysql64_path:
|
|
||||||
self.mysql_root['x64'] = builder.options.mysql64_path
|
|
||||||
else:
|
else:
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
self.mysql_root['x64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
|
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
|
||||||
if self.mysql_root['x64']:
|
if self.mysql_root['x86']:
|
||||||
break
|
break
|
||||||
if not self.mysql_root['x64'] or not os.path.isdir(self.mysql_root['x64']):
|
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
|
||||||
|
raise Exception('Could not find a path to MySQL. Configure with --no-mysql to disable it.')
|
||||||
|
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
|
||||||
|
|
||||||
|
if 'x86_64' in self.target_archs:
|
||||||
|
if builder.options.mysql64_path:
|
||||||
|
self.mysql_root['x86_64'] = builder.options.mysql64_path
|
||||||
|
else:
|
||||||
|
for i in range(10):
|
||||||
|
self.mysql_root['x86_64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
|
||||||
|
if self.mysql_root['x86_64']:
|
||||||
|
break
|
||||||
|
if not self.mysql_root['x86_64'] or not os.path.isdir(self.mysql_root['x86_64']):
|
||||||
raise Exception('Could not find a path to 64-bit MySQL!')
|
raise Exception('Could not find a path to 64-bit MySQL!')
|
||||||
self.mysql_root['x64'] = Normalize(self.mysql_root['x64'])
|
self.mysql_root['x86_64'] = Normalize(self.mysql_root['x86_64'])
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
builder.AddConfigureFile('pushbuild.txt')
|
builder.AddConfigureFile('pushbuild.txt')
|
||||||
|
|
||||||
if not set(self.archs).issubset(['x86', 'x64']):
|
if not set(self.target_archs).issubset(['x86', 'x86_64']):
|
||||||
raise Exception('Unknown target architecture: {0}'.format(builder.target.arch))
|
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
|
||||||
|
|
||||||
cxx = builder.DetectCxx()
|
for cxx in self.all_targets:
|
||||||
|
self.configure_cxx(cxx)
|
||||||
if cxx.like('msvc') and len(self.archs) > 1:
|
|
||||||
raise Exception('Building multiple archs with MSVC is not currently supported')
|
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.like('gcc'):
|
if cxx.like('gcc'):
|
||||||
self.configure_gcc(cxx)
|
self.configure_gcc(cxx)
|
||||||
@ -228,11 +270,11 @@ class SMConfig(object):
|
|||||||
cxx.defines += ['DEBUG', '_DEBUG']
|
cxx.defines += ['DEBUG', '_DEBUG']
|
||||||
|
|
||||||
# Platform-specifics
|
# Platform-specifics
|
||||||
if builder.target.platform == 'linux':
|
if cxx.target.platform == 'linux':
|
||||||
self.configure_linux(cxx)
|
self.configure_linux(cxx)
|
||||||
elif builder.target.platform == 'mac':
|
elif cxx.target.platform == 'mac':
|
||||||
self.configure_mac(cxx)
|
self.configure_mac(cxx)
|
||||||
elif builder.target.platform == 'windows':
|
elif cxx.target.platform == 'windows':
|
||||||
self.configure_windows(cxx)
|
self.configure_windows(cxx)
|
||||||
|
|
||||||
# Finish up.
|
# Finish up.
|
||||||
@ -270,9 +312,13 @@ class SMConfig(object):
|
|||||||
'-msse',
|
'-msse',
|
||||||
'-fvisibility=hidden',
|
'-fvisibility=hidden',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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 += [
|
cxx.cxxflags += [
|
||||||
'-std=c++11',
|
|
||||||
'-fno-exceptions',
|
|
||||||
'-fno-threadsafe-statics',
|
'-fno-threadsafe-statics',
|
||||||
'-Wno-non-virtual-dtor',
|
'-Wno-non-virtual-dtor',
|
||||||
'-Wno-overloaded-virtual',
|
'-Wno-overloaded-virtual',
|
||||||
@ -281,11 +327,11 @@ class SMConfig(object):
|
|||||||
|
|
||||||
have_gcc = cxx.family == 'gcc'
|
have_gcc = cxx.family == 'gcc'
|
||||||
have_clang = cxx.family == 'clang'
|
have_clang = cxx.family == 'clang'
|
||||||
if cxx.version >= 'clang-3.9':
|
if cxx.version >= 'clang-3.9' or cxx.version == 'clang-3.4' or cxx.version > 'apple-clang-6.0':
|
||||||
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
||||||
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
||||||
cxx.cflags += ['-Wno-varargs']
|
cxx.cflags += ['-Wno-varargs']
|
||||||
if cxx.version >= 'clang-3.6' or cxx.version >= 'apple-clang-7.0':
|
if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0':
|
||||||
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
||||||
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
||||||
cxx.cxxflags += ['-Wno-null-dereference']
|
cxx.cxxflags += ['-Wno-null-dereference']
|
||||||
@ -305,14 +351,35 @@ class SMConfig(object):
|
|||||||
cxx.cxxflags += ['-Wno-deprecated']
|
cxx.cxxflags += ['-Wno-deprecated']
|
||||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||||
|
|
||||||
|
if self.enable_asan:
|
||||||
|
if not have_clang:
|
||||||
|
raise Exception('--enable-asan only supported when using Clang')
|
||||||
|
self.configure_asan(cxx)
|
||||||
|
|
||||||
|
# Work around SDK warnings.
|
||||||
|
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
|
||||||
|
cxx.cflags += [
|
||||||
|
'-Wno-implicit-int-float-conversion',
|
||||||
|
'-Wno-tautological-overlap-compare',
|
||||||
|
]
|
||||||
|
|
||||||
if have_gcc:
|
if have_gcc:
|
||||||
cxx.cflags += ['-mfpmath=sse']
|
cxx.cflags += ['-mfpmath=sse']
|
||||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||||
|
|
||||||
if builder.options.opt == '1':
|
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):
|
def configure_msvc(self, cxx):
|
||||||
|
if self.enable_asan:
|
||||||
|
raise Exception('--enable-asan only supported when using Clang')
|
||||||
|
|
||||||
if builder.options.debug == '1':
|
if builder.options.debug == '1':
|
||||||
cxx.cflags += ['/MTd']
|
cxx.cflags += ['/MTd']
|
||||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||||
@ -358,6 +425,29 @@ class SMConfig(object):
|
|||||||
# Don't omit the frame pointer.
|
# Don't omit the frame pointer.
|
||||||
cxx.cflags += ['/Oy-']
|
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):
|
def configure_linux(self, cxx):
|
||||||
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||||
cxx.linkflags += ['-lm']
|
cxx.linkflags += ['-lm']
|
||||||
@ -365,22 +455,33 @@ class SMConfig(object):
|
|||||||
cxx.linkflags += ['-static-libgcc']
|
cxx.linkflags += ['-static-libgcc']
|
||||||
elif cxx.family == 'clang':
|
elif cxx.family == 'clang':
|
||||||
cxx.linkflags += ['-lgcc_eh']
|
cxx.linkflags += ['-lgcc_eh']
|
||||||
|
cxx.linkflags += ['-static-libstdc++']
|
||||||
|
|
||||||
def configure_mac(self, cxx):
|
def configure_mac(self, cxx):
|
||||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
cxx.cflags += ['-mmacosx-version-min=10.7']
|
||||||
cxx.linkflags += [
|
cxx.linkflags += [
|
||||||
'-mmacosx-version-min=10.5',
|
'-mmacosx-version-min=10.7',
|
||||||
'-lstdc++',
|
'-stdlib=libc++',
|
||||||
'-stdlib=libstdc++',
|
'-lc++',
|
||||||
]
|
]
|
||||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
cxx.cxxflags += ['-stdlib=libc++']
|
||||||
|
|
||||||
def configure_windows(self, cxx):
|
def configure_windows(self, cxx):
|
||||||
cxx.defines += ['WIN32', '_WINDOWS']
|
cxx.defines += ['WIN32', '_WINDOWS']
|
||||||
|
|
||||||
def AddVersioning(self, binary, arch):
|
def add_libamtl(self):
|
||||||
if builder.target.platform == 'windows':
|
# Add libamtl.
|
||||||
|
self.libamtl = {}
|
||||||
|
for cxx in self.all_targets:
|
||||||
|
def get_configure_fn(cxx):
|
||||||
|
return lambda builder, name: self.StaticLibrary(builder, cxx, name)
|
||||||
|
extra_vars = {'Configure': get_configure_fn(cxx)}
|
||||||
|
libamtl = builder.Build('public/amtl/amtl/AMBuilder', extra_vars)
|
||||||
|
self.libamtl[cxx.target.arch] = libamtl.binary
|
||||||
|
|
||||||
|
def AddVersioning(self, binary):
|
||||||
|
if binary.compiler.target.platform == 'windows':
|
||||||
binary.sources += ['version.rc']
|
binary.sources += ['version.rc']
|
||||||
binary.compiler.rcdefines += [
|
binary.compiler.rcdefines += [
|
||||||
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
||||||
@ -388,31 +489,38 @@ class SMConfig(object):
|
|||||||
]
|
]
|
||||||
if self.use_auto_versioning():
|
if self.use_auto_versioning():
|
||||||
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
||||||
elif builder.target.platform == 'mac':
|
elif binary.compiler.target.platform == 'mac':
|
||||||
if binary.type == 'library':
|
if binary.type == 'library':
|
||||||
binary.compiler.postlink += [
|
binary.compiler.postlink += [
|
||||||
'-compatibility_version', '1.0.0',
|
'-compatibility_version', '1.0.0',
|
||||||
'-current_version', self.productVersion
|
'-current_version', self.productVersion
|
||||||
]
|
]
|
||||||
if self.use_auto_versioning():
|
if self.use_auto_versioning():
|
||||||
binary.compiler.linkflags += [self.versionlib[arch]]
|
binary.compiler.postlink += [self.versionlib[binary.compiler.target.arch]]
|
||||||
binary.compiler.sourcedeps += SM.generated_headers
|
binary.compiler.sourcedeps += SM.generated_headers
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def LibraryBuilder(self, compiler, name, arch):
|
def LibraryBuilder(self, compiler, name):
|
||||||
binary = compiler.Library(name)
|
binary = compiler.Library(name)
|
||||||
AppendArchSuffix(binary, name, arch)
|
self.AddVersioning(binary)
|
||||||
self.AddVersioning(binary, arch)
|
|
||||||
if binary.compiler.like('msvc'):
|
if binary.compiler.like('msvc'):
|
||||||
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
||||||
|
|
||||||
|
# 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
|
return binary
|
||||||
|
|
||||||
def ProgramBuilder(self, compiler, name, arch):
|
def ProgramBuilder(self, compiler, name):
|
||||||
binary = compiler.Program(name)
|
binary = compiler.Program(name)
|
||||||
AppendArchSuffix(binary, name, arch)
|
self.AddVersioning(binary)
|
||||||
self.AddVersioning(binary, arch)
|
|
||||||
if '-static-libgcc' in binary.compiler.linkflags:
|
if '-static-libgcc' in binary.compiler.linkflags:
|
||||||
binary.compiler.linkflags.remove('-static-libgcc')
|
binary.compiler.linkflags.remove('-static-libgcc')
|
||||||
|
if self.enable_asan:
|
||||||
|
binary.compiler.linkflags.append('-static-libsan')
|
||||||
if '-lgcc_eh' in binary.compiler.linkflags:
|
if '-lgcc_eh' in binary.compiler.linkflags:
|
||||||
binary.compiler.linkflags.remove('-lgcc_eh')
|
binary.compiler.linkflags.remove('-lgcc_eh')
|
||||||
if binary.compiler.like('gcc'):
|
if binary.compiler.like('gcc'):
|
||||||
@ -421,25 +529,23 @@ class SMConfig(object):
|
|||||||
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
|
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def StaticLibraryBuilder(self, compiler, name, arch):
|
def StaticLibraryBuilder(self, compiler, name):
|
||||||
binary = compiler.StaticLibrary(name)
|
return compiler.StaticLibrary(name)
|
||||||
AppendArchSuffix(binary, name, arch)
|
|
||||||
return binary;
|
|
||||||
|
|
||||||
def Library(self, context, name, arch):
|
def Library(self, context, compiler, name):
|
||||||
compiler = context.cxx.clone()
|
compiler = compiler.clone()
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
SetArchFlags(compiler)
|
||||||
return self.LibraryBuilder(compiler, name, arch)
|
return self.LibraryBuilder(compiler, name)
|
||||||
|
|
||||||
def Program(self, context, name, arch):
|
def Program(self, context, compiler, name):
|
||||||
compiler = context.cxx.clone()
|
compiler = compiler.clone()
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
SetArchFlags(compiler)
|
||||||
return self.ProgramBuilder(compiler, name, arch)
|
return self.ProgramBuilder(compiler, name)
|
||||||
|
|
||||||
def StaticLibrary(self, context, name, arch):
|
def StaticLibrary(self, context, compiler, name):
|
||||||
compiler = context.cxx.clone()
|
compiler = compiler.clone()
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
SetArchFlags(compiler)
|
||||||
return self.StaticLibraryBuilder(compiler, name, arch)
|
return self.StaticLibraryBuilder(compiler, name)
|
||||||
|
|
||||||
def ConfigureForExtension(self, context, compiler):
|
def ConfigureForExtension(self, context, compiler):
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
@ -452,15 +558,15 @@ class SMConfig(object):
|
|||||||
]
|
]
|
||||||
return compiler
|
return compiler
|
||||||
|
|
||||||
def ExtLibrary(self, context, name, arch):
|
def ExtLibrary(self, context, compiler, name):
|
||||||
binary = self.Library(context, name, arch)
|
binary = self.Library(context, compiler, name)
|
||||||
|
SetArchFlags(compiler)
|
||||||
self.ConfigureForExtension(context, binary.compiler)
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def ConfigureForHL2(self, binary, sdk, arch):
|
def ConfigureForHL2(self, context, binary, sdk):
|
||||||
compiler = binary.compiler
|
compiler = binary.compiler
|
||||||
|
SetArchFlags(compiler)
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
|
||||||
|
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
os.path.join(self.mms_root, 'core'),
|
os.path.join(self.mms_root, 'core'),
|
||||||
@ -497,13 +603,16 @@ class SMConfig(object):
|
|||||||
compiler.defines.remove('_vsnprintf=vsnprintf')
|
compiler.defines.remove('_vsnprintf=vsnprintf')
|
||||||
|
|
||||||
if compiler.like('msvc'):
|
if compiler.like('msvc'):
|
||||||
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
|
compiler.defines += ['COMPILER_MSVC']
|
||||||
if compiler.version >= 1900:
|
if compiler.target.arch == 'x86':
|
||||||
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
compiler.defines += ['COMPILER_MSVC32']
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
compiler.defines += ['COMPILER_MSVC64']
|
||||||
|
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
||||||
else:
|
else:
|
||||||
compiler.defines += ['COMPILER_GCC']
|
compiler.defines += ['COMPILER_GCC']
|
||||||
|
|
||||||
if arch == 'x64':
|
if compiler.target.arch == 'x86_64':
|
||||||
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
|
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
|
||||||
|
|
||||||
# For everything after Swarm, this needs to be defined for entity networking
|
# For everything after Swarm, this needs to be defined for entity networking
|
||||||
@ -512,107 +621,142 @@ class SMConfig(object):
|
|||||||
compiler.defines += ['NETWORK_VARS_ENABLED']
|
compiler.defines += ['NETWORK_VARS_ENABLED']
|
||||||
|
|
||||||
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
|
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
|
||||||
if builder.target.platform in ['linux', 'mac']:
|
if compiler.target.platform in ['linux', 'mac']:
|
||||||
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||||
|
|
||||||
if sdk.name == 'csgo' and builder.target.platform == 'linux':
|
if compiler.target.platform == 'linux':
|
||||||
compiler.linkflags += ['-lstdc++']
|
if sdk.name in ['csgo', 'blade']:
|
||||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
compiler.linkflags.remove('-static-libstdc++')
|
||||||
|
compiler.linkflags += ['-lstdc++']
|
||||||
|
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||||
|
elif compiler.target.platform == 'mac':
|
||||||
|
if sdk.name in ['csgo']:
|
||||||
|
# Switch libc++ to libstdc++ for protobuf linkage.
|
||||||
|
compiler.cxxflags.remove('-stdlib=libc++')
|
||||||
|
compiler.linkflags.remove('-stdlib=libc++')
|
||||||
|
compiler.linkflags.remove('-lc++')
|
||||||
|
|
||||||
|
compiler.cxxflags += ['-stdlib=libstdc++']
|
||||||
|
compiler.linkflags += ['-stdlib=libstdc++']
|
||||||
|
compiler.linkflags += ['-lstdc++']
|
||||||
|
|
||||||
|
if 'c++1y' in compiler.cxxflags:
|
||||||
|
compiler.cxxflags.remove('-std=c++1y')
|
||||||
|
compiler.cxxflags += ['-std=c++11']
|
||||||
|
elif 'c++14' in compiler.cxxflags:
|
||||||
|
compiler.cxxflags.remove('-std=c++14')
|
||||||
|
compiler.cxxflags += ['-std=c++11']
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||||
|
|
||||||
if builder.target.platform == 'linux':
|
if compiler.target.platform == 'linux':
|
||||||
if sdk.name == 'episode1':
|
if sdk.name == 'episode1':
|
||||||
lib_folder = os.path.join(sdk.path, 'linux_sdk')
|
lib_folder = os.path.join(sdk.path, 'linux_sdk')
|
||||||
elif sdk.name in ['sdk2013', 'bms']:
|
elif sdk.name in ['sdk2013', 'bms']:
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
||||||
elif arch == 'x64':
|
elif compiler.target.arch == 'x86_64':
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
|
||||||
else:
|
else:
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
||||||
elif builder.target.platform == 'mac':
|
elif compiler.target.platform == 'mac':
|
||||||
if sdk.name in ['sdk2013', 'bms']:
|
if sdk.name in ['sdk2013', 'bms']:
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
||||||
elif arch == 'x64':
|
elif compiler.target.arch == 'x86_64':
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
|
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
|
||||||
else:
|
else:
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
||||||
|
|
||||||
if builder.target.platform in ['linux', 'mac']:
|
if compiler.target.platform in ['linux', 'mac']:
|
||||||
if sdk.name in ['sdk2013', 'bms'] or arch == 'x64':
|
if sdk.name in ['sdk2013', 'bms'] or compiler.target.arch == 'x86_64':
|
||||||
compiler.postlink += [
|
compiler.postlink += [
|
||||||
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
|
os.path.join(lib_folder, 'tier1.a'),
|
||||||
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
|
os.path.join(lib_folder, 'mathlib.a')
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
compiler.postlink += [
|
compiler.postlink += [
|
||||||
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
|
os.path.join(lib_folder, 'tier1_i486.a'),
|
||||||
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
|
os.path.join(lib_folder, 'mathlib_i486.a')
|
||||||
]
|
]
|
||||||
|
|
||||||
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
||||||
if arch == 'x64':
|
if compiler.target.arch == 'x86_64':
|
||||||
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces.a'))]
|
compiler.postlink += [os.path.join(lib_folder, 'interfaces.a')]
|
||||||
else:
|
else:
|
||||||
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
|
compiler.postlink += [os.path.join(lib_folder, 'interfaces_i486.a')]
|
||||||
|
|
||||||
dynamic_libs = []
|
dynamic_libs = []
|
||||||
if builder.target.platform == 'linux':
|
if compiler.target.platform == 'linux':
|
||||||
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
|
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
|
||||||
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
||||||
elif arch == 'x64' and sdk.name == 'csgo':
|
elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'mock']:
|
||||||
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
|
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
|
||||||
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
|
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
|
||||||
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
||||||
else:
|
else:
|
||||||
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
||||||
elif builder.target.platform == 'mac':
|
elif compiler.target.platform == 'mac':
|
||||||
compiler.linkflags.append('-liconv')
|
compiler.linkflags.append('-liconv')
|
||||||
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
||||||
elif builder.target.platform == 'windows':
|
elif compiler.target.platform == 'windows':
|
||||||
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||||
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
|
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
|
||||||
libs.append('interfaces')
|
libs.append('interfaces')
|
||||||
for lib in libs:
|
for lib in libs:
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
|
if compiler.target.arch == 'x86':
|
||||||
compiler.linkflags.append(compiler.Dep(lib_path))
|
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:
|
for library in dynamic_libs:
|
||||||
source_path = os.path.join(lib_folder, library)
|
source_path = os.path.join(lib_folder, library)
|
||||||
output_path = os.path.join(binary.localFolder, library)
|
output_path = os.path.join(binary.localFolder, library)
|
||||||
|
|
||||||
def make_linker(source_path, output_path):
|
# Ensure the output path exists.
|
||||||
def link(context, binary):
|
context.AddFolder(binary.localFolder)
|
||||||
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
|
output = context.AddSymlink(source_path, output_path)
|
||||||
return output
|
|
||||||
return link
|
|
||||||
|
|
||||||
linker = make_linker(source_path, output_path)
|
compiler.weaklinkdeps += [output]
|
||||||
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
|
compiler.linkflags[0:0] = [library]
|
||||||
|
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def HL2Library(self, context, name, sdk, arch):
|
def HL2Library(self, context, compiler, name, sdk):
|
||||||
binary = self.Library(context, name, arch)
|
binary = self.Library(context, compiler, name)
|
||||||
self.ConfigureForExtension(context, binary.compiler)
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
return self.ConfigureForHL2(binary, sdk, arch)
|
return self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
|
||||||
def HL2Project(self, context, name):
|
def HL2Config(self, project, context, compiler, name, sdk):
|
||||||
project = context.cxx.LibraryProject(name)
|
binary = project.Configure(compiler, name,
|
||||||
self.ConfigureForExtension(context, project.compiler)
|
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
|
||||||
return project
|
self.AddVersioning(binary)
|
||||||
|
return self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
|
||||||
def HL2Config(self, project, name, sdk, arch):
|
def HL2ExtConfig(self, project, context, compiler, name, sdk):
|
||||||
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
|
binary = project.Configure(compiler, name,
|
||||||
AppendArchSuffix(binary, name, arch)
|
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
|
||||||
self.AddVersioning(binary, arch)
|
self.AddVersioning(binary)
|
||||||
return self.ConfigureForHL2(binary, sdk, arch)
|
self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
|
return binary
|
||||||
|
|
||||||
|
if getattr(builder, 'target', None) is not None:
|
||||||
|
sys.stderr.write("Your output folder was configured for AMBuild 2.1, and SourceMod is now\n")
|
||||||
|
sys.stderr.write("configured to use AMBuild 2.2. Please remove your output folder and\n")
|
||||||
|
sys.stderr.write("reconfigure to continue.\n")
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
SM = SMConfig()
|
SM = SMConfig()
|
||||||
SM.detectProductVersion()
|
SM.detectProductVersion()
|
||||||
SM.detectSDKs()
|
if not getattr(builder.options, 'scripting_only', False):
|
||||||
|
SM.detectSDKs()
|
||||||
SM.configure()
|
SM.configure()
|
||||||
|
SM.add_libamtl()
|
||||||
|
|
||||||
|
# This will clone the list and each cxx object as we recurse, preventing child
|
||||||
|
# scripts from messing up global state.
|
||||||
|
builder.targets = builder.CloneableList(SM.all_targets)
|
||||||
|
|
||||||
if SM.use_auto_versioning():
|
if SM.use_auto_versioning():
|
||||||
SM.generated_headers = builder.Build(
|
SM.generated_headers = builder.Build(
|
||||||
@ -624,46 +768,79 @@ if SM.use_auto_versioning():
|
|||||||
{ 'SM': SM }
|
{ 'SM': SM }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class SPRoot(object):
|
||||||
|
# SourcePawn's build scripts are always one-offs, and attach the current target
|
||||||
|
# to the builder, so we have to provide a shim to our StaticLibrary() method.
|
||||||
|
def StaticLibrary(self, builder, name):
|
||||||
|
return SM.StaticLibrary(builder, builder.cxx, name)
|
||||||
|
def Program(self, builder, name):
|
||||||
|
return SM.Program(builder, builder.cxx, name)
|
||||||
|
def Library(self, builder, name):
|
||||||
|
return SM.Library(builder, builder.cxx, name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def targets(self):
|
||||||
|
return SM.all_targets
|
||||||
|
|
||||||
|
@property
|
||||||
|
def libamtl(self):
|
||||||
|
return SM.libamtl
|
||||||
|
|
||||||
|
SP_build_parts = ['core']
|
||||||
|
if getattr(builder.options, 'scripting_only', False):
|
||||||
|
SP_build_parts = ['spcomp']
|
||||||
|
|
||||||
# Build SourcePawn externally.
|
# Build SourcePawn externally.
|
||||||
SP = builder.Build('sourcepawn/AMBuildScript', {
|
SP = builder.Build('sourcepawn/AMBuildScript', {
|
||||||
'external_root': SM,
|
'external_root': SPRoot(),
|
||||||
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||||
'external_build': ['core'],
|
'external_build': SP_build_parts,
|
||||||
})
|
})
|
||||||
if len(SP.spcomp) > 1:
|
if len(SP.spcomp) > 1:
|
||||||
SM.spcomp = SP.spcomp['x86']
|
SM.spcomp = SP.spcomp['x86']
|
||||||
else:
|
else:
|
||||||
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
|
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
|
||||||
SM.spcomp_bins = list(SP.spcomp.values())
|
SM.spcomp_bins = list(SP.spcomp.values())
|
||||||
for arch in SM.archs:
|
|
||||||
SM.binaries += [
|
if not getattr(builder.options, 'scripting_only', False):
|
||||||
SP.libsourcepawn[arch]
|
for cxx in SM.all_targets:
|
||||||
|
SM.spvm += [
|
||||||
|
SP.libsourcepawn[cxx.target.arch]
|
||||||
|
]
|
||||||
|
|
||||||
|
if getattr(builder.options, 'scripting_only', False):
|
||||||
|
BuildScripts = [
|
||||||
|
'tools/buildbot/PackageHelpers',
|
||||||
|
'tools/buildbot/ToolsPackageScript',
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
BuildScripts = [
|
||||||
|
'loader/AMBuilder',
|
||||||
|
'core/AMBuilder',
|
||||||
|
'core/logic/AMBuilder',
|
||||||
|
'extensions/bintools/AMBuilder',
|
||||||
|
'extensions/clientprefs/AMBuilder',
|
||||||
|
'extensions/curl/AMBuilder',
|
||||||
|
'extensions/cstrike/AMBuilder',
|
||||||
|
'extensions/dhooks/AMBuilder',
|
||||||
|
'extensions/geoip/AMBuilder',
|
||||||
|
'extensions/mysql/AMBuilder',
|
||||||
|
'extensions/pgsql/AMBuilder',
|
||||||
|
'extensions/regex/AMBuilder',
|
||||||
|
'extensions/sdkhooks/AMBuilder',
|
||||||
|
'extensions/sdktools/AMBuilder',
|
||||||
|
'extensions/sqlite/AMBuilder',
|
||||||
|
'extensions/tf2/AMBuilder',
|
||||||
|
'extensions/topmenus/AMBuilder',
|
||||||
|
'extensions/updater/AMBuilder',
|
||||||
]
|
]
|
||||||
|
|
||||||
BuildScripts = [
|
if builder.backend == 'amb2':
|
||||||
'loader/AMBuilder',
|
BuildScripts += [
|
||||||
'core/AMBuilder',
|
'plugins/AMBuilder',
|
||||||
'core/logic/AMBuilder',
|
'tools/buildbot/PackageHelpers',
|
||||||
'extensions/bintools/AMBuilder',
|
'tools/buildbot/PackageScript',
|
||||||
'extensions/clientprefs/AMBuilder',
|
]
|
||||||
'extensions/curl/AMBuilder',
|
|
||||||
'extensions/cstrike/AMBuilder',
|
|
||||||
'extensions/geoip/AMBuilder',
|
|
||||||
'extensions/mysql/AMBuilder',
|
|
||||||
'extensions/regex/AMBuilder',
|
|
||||||
'extensions/sdkhooks/AMBuilder',
|
|
||||||
'extensions/sdktools/AMBuilder',
|
|
||||||
'extensions/sqlite/AMBuilder',
|
|
||||||
'extensions/tf2/AMBuilder',
|
|
||||||
'extensions/topmenus/AMBuilder',
|
|
||||||
'extensions/updater/AMBuilder',
|
|
||||||
]
|
|
||||||
|
|
||||||
if builder.backend == 'amb2':
|
|
||||||
BuildScripts += [
|
|
||||||
'plugins/AMBuilder',
|
|
||||||
'tools/buildbot/PackageScript',
|
|
||||||
]
|
|
||||||
|
|
||||||
builder.Build(BuildScripts, { 'SM': SM })
|
builder.Build(BuildScripts, { 'SM': SM })
|
||||||
|
|
||||||
|
17
appveyor.yml
Normal file
17
appveyor.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
version: 1.0.{build}
|
||||||
|
image: Visual Studio 2015
|
||||||
|
clone_folder: c:/projects/sourcemod
|
||||||
|
clone_depth: 1
|
||||||
|
install:
|
||||||
|
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
|
||||||
|
- cmd: git submodule update --init --recursive
|
||||||
|
- cmd: git pull --recurse-submodules
|
||||||
|
- cmd: cd ..
|
||||||
|
- ps: sourcemod/tools/checkout-deps.ps1 -SDKs episode1,css,tf2,l4d2,csgo
|
||||||
|
- cmd: cd sourcemod
|
||||||
|
build_script:
|
||||||
|
- cmd: call "%VS140COMNTOOLS%/vsvars32.bat"
|
||||||
|
- cmd: mkdir build
|
||||||
|
- cmd: cd build
|
||||||
|
- cmd: python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
|
||||||
|
- cmd: ambuild
|
@ -67,7 +67,7 @@ struct DatabaseInfo;
|
|||||||
class IPlayerInfoBridge;
|
class IPlayerInfoBridge;
|
||||||
class ICommandArgs;
|
class ICommandArgs;
|
||||||
|
|
||||||
typedef ke::Lambda<bool(int client, const ICommandArgs*)> CommandFunc;
|
typedef ke::Function<bool(int client, const ICommandArgs*)> CommandFunc;
|
||||||
|
|
||||||
class CoreProvider
|
class CoreProvider
|
||||||
{
|
{
|
||||||
@ -115,6 +115,8 @@ public:
|
|||||||
virtual void ConsolePrint(const char *fmt, ...) = 0;
|
virtual void ConsolePrint(const char *fmt, ...) = 0;
|
||||||
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 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.
|
// Game engine helper functions.
|
||||||
virtual bool IsClientConVarQueryingSupported() = 0;
|
virtual bool IsClientConVarQueryingSupported() = 0;
|
||||||
virtual int QueryClientConVar(int client, const char *cvar) = 0;
|
virtual int QueryClientConVar(int client, const char *cvar) = 0;
|
||||||
|
@ -73,6 +73,9 @@ struct sm_logic_t
|
|||||||
void (*FreeCellArray)(ICellArray *arr);
|
void (*FreeCellArray)(ICellArray *arr);
|
||||||
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
|
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
|
||||||
uint32_t (*ToPseudoAddress)(void *addr);
|
uint32_t (*ToPseudoAddress)(void *addr);
|
||||||
|
void (*SetEntityLumpWritable)(bool writable);
|
||||||
|
bool (*ParseEntityLumpString)(const char *entityString, int &status, size_t &position);
|
||||||
|
const char * (*GetEntityLumpString)();
|
||||||
IScriptManager *scripts;
|
IScriptManager *scripts;
|
||||||
IShareSys *sharesys;
|
IShareSys *sharesys;
|
||||||
IExtensionSys *extsys;
|
IExtensionSys *extsys;
|
||||||
|
@ -145,5 +145,15 @@
|
|||||||
* Disable this option at your own risk.
|
* Disable this option at your own risk.
|
||||||
*/
|
*/
|
||||||
"FollowCSGOServerGuidelines" "yes"
|
"FollowCSGOServerGuidelines" "yes"
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls whether the SourcePawn runtime will generate additional metadata about
|
||||||
|
* JIT-compiled functions for performance profiling or debugging purposes.
|
||||||
|
*
|
||||||
|
* "none" - Don't generate any additional JIT metadata
|
||||||
|
* "default" - Generate basic perf metadata (on Linux) and delete it automatically on quit
|
||||||
|
* "perf" - Generate basic perf metadata (Linux only - function names)
|
||||||
|
* "jitdump" - Generate extended perf metadata (Linux only - function names, bytecode, and source information)
|
||||||
|
*/
|
||||||
|
"JITMetadata" "default"
|
||||||
|
}
|
||||||
|
Binary file not shown.
41
configs/sql-init-scripts/pgsql/clientprefs-pgsql.sql
Normal file
41
configs/sql-init-scripts/pgsql/clientprefs-pgsql.sql
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS sm_cookies
|
||||||
|
(
|
||||||
|
id serial,
|
||||||
|
name varchar(30) NOT NULL UNIQUE,
|
||||||
|
description varchar(255),
|
||||||
|
access INTEGER,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS sm_cookie_cache
|
||||||
|
(
|
||||||
|
player varchar(65) NOT NULL,
|
||||||
|
cookie_id int NOT NULL,
|
||||||
|
value varchar(100),
|
||||||
|
timestamp int NOT NULL,
|
||||||
|
PRIMARY KEY (player, cookie_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
LOOP
|
||||||
|
-- first try to update the it.
|
||||||
|
UPDATE sm_cookie_cache SET value = in_value, timestamp = in_time WHERE player = in_player AND cookie_id = in_cookie;
|
||||||
|
IF found THEN
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
-- not there, so try to insert.
|
||||||
|
-- if someone else inserts the same key concurrently, we could get a unique-key failure.
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES (in_player, in_cookie, in_value, in_time);
|
||||||
|
RETURN;
|
||||||
|
EXCEPTION WHEN unique_violation THEN
|
||||||
|
-- do nothing... loop again, and we'll update.
|
||||||
|
END;
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
LANGUAGE plpgsql;
|
65
configs/sql-init-scripts/pgsql/create_admins.sql
Normal file
65
configs/sql-init-scripts/pgsql/create_admins.sql
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
CREATE TABLE sm_admins (
|
||||||
|
id serial,
|
||||||
|
authtype varchar(6) NOT NULL,
|
||||||
|
CHECK (authtype in ('steam', 'name', 'ip')),
|
||||||
|
identity varchar(65) NOT NULL,
|
||||||
|
password varchar(65),
|
||||||
|
flags varchar(30) NOT NULL,
|
||||||
|
name varchar(65) NOT NULL,
|
||||||
|
immunity int NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_groups (
|
||||||
|
id serial,
|
||||||
|
flags varchar(30) NOT NULL,
|
||||||
|
name varchar(120) NOT NULL,
|
||||||
|
immunity_level int NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_group_immunity (
|
||||||
|
group_id int NOT NULL,
|
||||||
|
other_id int NOT NULL,
|
||||||
|
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (other_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY (group_id, other_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_group_overrides (
|
||||||
|
group_id int NOT NULL,
|
||||||
|
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
type varchar(10) NOT NULL,
|
||||||
|
CHECK (type in ('command', 'group')),
|
||||||
|
name varchar(32) NOT NULL,
|
||||||
|
access varchar(5) NOT NULL,
|
||||||
|
CHECK (access in ('allow', 'deny')),
|
||||||
|
PRIMARY KEY (group_id, type, name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_overrides (
|
||||||
|
type varchar(10) NOT NULL,
|
||||||
|
CHECK (type in ('command', 'group')),
|
||||||
|
name varchar(32) NOT NULL,
|
||||||
|
flags varchar(30) NOT NULL,
|
||||||
|
PRIMARY KEY (type,name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_admins_groups (
|
||||||
|
admin_id int NOT NULL,
|
||||||
|
group_id int NOT NULL,
|
||||||
|
FOREIGN KEY (admin_id) REFERENCES sm_admins(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
inherit_order int NOT NULL,
|
||||||
|
PRIMARY KEY (admin_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- side note, this is pgsql module, sm_config will not exist if the above stuff exists... and it's being left to the admin
|
||||||
|
-- to figure out if it exists.
|
||||||
|
CREATE TABLE sm_config (
|
||||||
|
cfg_key varchar(32) NOT NULL,
|
||||||
|
cfg_value varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (cfg_key)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');
|
67
configure.py
67
configure.py
@ -1,42 +1,49 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet:
|
# vim: set ts=2 sw=2 tw=99 noet:
|
||||||
import sys
|
import sys
|
||||||
try:
|
try:
|
||||||
from ambuild2 import run, util
|
from ambuild2 import run, util
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
import ambuild
|
import ambuild
|
||||||
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
|
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')
|
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
|
||||||
except:
|
except:
|
||||||
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
||||||
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def make_objdir_name(p):
|
# Hack to show a decent upgrade message, which wasn't done until 2.2.
|
||||||
return 'obj-' + util.Platform() + '-' + p.target_arch
|
ambuild_version = getattr(run, 'CURRENT_API', '2.1')
|
||||||
|
if ambuild_version.startswith('2.1'):
|
||||||
|
sys.stderr.write("AMBuild 2.2 or higher is required; please update\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
parser = run.BuildParser(sourcePath=sys.path[0], api='2.1')
|
parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
||||||
parser.default_arch = 'x86'
|
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||||
parser.default_build_folder = make_objdir_name
|
help='Root search folder for HL2SDKs')
|
||||||
parser.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
parser.options.add_argument('--mysql-path', type=str, dest='mysql_path', default=None,
|
||||||
help='Root search folder for HL2SDKs')
|
help='Path to MySQL 5')
|
||||||
parser.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
|
parser.options.add_argument('--mysql64-path', type=str, dest='mysql64_path', default=None,
|
||||||
help='Path to MySQL 5')
|
help='Path to 64-bit MySQL 5')
|
||||||
parser.options.add_option('--mysql64-path', type=str, dest='mysql64_path', default=None,
|
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||||
help='Path to 64-bit MySQL 5')
|
|
||||||
parser.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
|
|
||||||
help='Path to Metamod:Source')
|
help='Path to Metamod:Source')
|
||||||
parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
|
||||||
help='Enable debugging symbols')
|
help='Enable debugging symbols')
|
||||||
parser.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||||
help='Enable optimization')
|
help='Enable optimization')
|
||||||
parser.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
|
parser.options.add_argument('--no-mysql', action='store_false', default=True, dest='hasMySql',
|
||||||
help='Disable building MySQL extension')
|
help='Disable building MySQL extension')
|
||||||
parser.options.add_option('-s', '--sdks', default='all', dest='sdks',
|
parser.options.add_argument('-s', '--sdks', default='present', dest='sdks',
|
||||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
help='Build against specified SDKs; valid args are "none", "all", "present",'
|
||||||
'comma-delimited list of engine names (default: %default)')
|
' or comma-delimited list of engine names')
|
||||||
parser.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
|
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_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
|
parser.options.add_argument('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
|
||||||
default=False, help='Disable the auto versioning script')
|
default=False, help='Disable the auto versioning script')
|
||||||
|
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
|
||||||
|
help="Override the target architecture (use commas to separate multiple targets).")
|
||||||
|
parser.options.add_argument('--scripting-only', action='store_true', dest='scripting_only', default=False,
|
||||||
|
help="Only build and package the files required for scripting in SourcePawn.")
|
||||||
|
parser.options.add_argument('--enable-asan', action='store_true', dest='enable_asan',
|
||||||
|
default=False, help='Enable ASAN (clang only)')
|
||||||
parser.Configure()
|
parser.Configure()
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os
|
||||||
|
|
||||||
project = SM.HL2Project(builder, 'sourcemod')
|
project = builder.LibraryProject('sourcemod')
|
||||||
|
|
||||||
project.sources += [
|
project.sources += [
|
||||||
'MenuStyle_Valve.cpp',
|
'MenuStyle_Valve.cpp',
|
||||||
'logic_bridge.cpp',
|
'logic_bridge.cpp',
|
||||||
@ -37,22 +38,22 @@ project.sources += [
|
|||||||
'MenuStyle_Radio.cpp',
|
'MenuStyle_Radio.cpp',
|
||||||
'sm_autonatives.cpp',
|
'sm_autonatives.cpp',
|
||||||
'ConsoleDetours.cpp',
|
'ConsoleDetours.cpp',
|
||||||
'vprof_tool.cpp',
|
|
||||||
'smn_commandline.cpp',
|
'smn_commandline.cpp',
|
||||||
'GameHooks.cpp',
|
'GameHooks.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
for sdk_name in SM.sdks:
|
for sdk_name in SM.sdks:
|
||||||
sdk = SM.sdks[sdk_name]
|
sdk = SM.sdks[sdk_name]
|
||||||
for arch in SM.archs:
|
for cxx in builder.targets:
|
||||||
if not arch in sdk.platformSpec[builder.target.platform]:
|
if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
binary_name = 'sourcemod.' + sdk.ext
|
binary_name = 'sourcemod.' + sdk.ext
|
||||||
|
|
||||||
binary = SM.HL2Config(project, binary_name, sdk, arch)
|
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
|
||||||
compiler = binary.compiler
|
SM.ConfigureForExtension(builder, binary.compiler)
|
||||||
|
|
||||||
|
compiler = binary.compiler
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
builder.sourcePath
|
builder.sourcePath
|
||||||
]
|
]
|
||||||
@ -63,51 +64,72 @@ for sdk_name in SM.sdks:
|
|||||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
||||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
|
||||||
]
|
]
|
||||||
|
elif sdk.name == 'blade':
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf')
|
||||||
|
]
|
||||||
|
|
||||||
if compiler.like('msvc'):
|
if compiler.like('msvc'):
|
||||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||||
if builder.target.platform == 'linux':
|
if cxx.target.platform == 'linux':
|
||||||
compiler.postlink += ['-lpthread', '-lrt']
|
compiler.postlink += ['-lpthread', '-lrt']
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
if sdk.name in ['csgo', 'blade']:
|
||||||
if builder.target.platform == 'linux':
|
if compiler.target.platform == 'linux':
|
||||||
if arch == 'x86':
|
if compiler.target.arch == 'x86':
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
|
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
|
||||||
elif arch == 'x64':
|
elif compiler.target.arch == 'x86_64':
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a')
|
lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a')
|
||||||
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
||||||
elif builder.target.platform == 'mac':
|
elif compiler.target.platform == 'mac':
|
||||||
if arch == 'x86':
|
if compiler.target.arch == 'x86':
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||||
elif arch == 'x64':
|
elif compiler.target.arch == 'x86_64':
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
|
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||||
elif builder.target.platform == 'windows':
|
elif compiler.target.platform == 'windows':
|
||||||
msvc_ver = compiler.version
|
msvc_ver = compiler.version
|
||||||
vs_year = ''
|
vs_year = ''
|
||||||
if msvc_ver == 1800:
|
platform = ''
|
||||||
vs_year = '2013'
|
if compiler.target.arch == 'x86':
|
||||||
elif 1900 <= msvc_ver < 2000:
|
platform = 'win32'
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
platform = 'win64'
|
||||||
|
|
||||||
|
if 1900 <= msvc_ver < 2000:
|
||||||
vs_year = '2015'
|
vs_year = '2015'
|
||||||
else:
|
else:
|
||||||
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
||||||
|
|
||||||
if 'DEBUG' in compiler.defines:
|
if 'DEBUG' in compiler.defines:
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
lib_path = os.path.join(sdk.path, 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||||
else:
|
else:
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
lib_path = os.path.join(sdk.path, 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||||
compiler.linkflags.insert(0, binary.Dep(lib_path))
|
compiler.linkflags.insert(0, lib_path)
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
if sdk.name in ['csgo', 'blade']:
|
||||||
binary.sources += ['smn_protobuf.cpp']
|
binary.sources += ['smn_protobuf.cpp']
|
||||||
else:
|
else:
|
||||||
binary.sources += ['smn_bitbuffer.cpp']
|
binary.sources += ['smn_bitbuffer.cpp']
|
||||||
|
|
||||||
|
if sdk.name != 'blade':
|
||||||
|
binary.sources += [
|
||||||
|
'vprof_tool.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
if sdk.name == 'csgo':
|
||||||
binary.sources += [
|
binary.sources += [
|
||||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
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_usermessages.pb.cc'),
|
||||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
||||||
]
|
]
|
||||||
|
elif sdk.name == 'blade':
|
||||||
|
binary.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'),
|
||||||
|
]
|
||||||
|
|
||||||
SM.binaries += builder.Add(project)
|
SM.binaries += builder.Add(project)
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <ITextParsers.h>
|
#include <ITextParsers.h>
|
||||||
#include "ChatTriggers.h"
|
#include "ChatTriggers.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
@ -64,7 +66,7 @@ ChatTriggers::~ChatTriggers()
|
|||||||
|
|
||||||
void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
|
void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
|
||||||
{
|
{
|
||||||
ke::AutoPtr<char[]> filtered(new char[strlen(value) + 1]);
|
std::unique_ptr<char[]> filtered(new char[strlen(value) + 1]);
|
||||||
|
|
||||||
const char *src = value;
|
const char *src = value;
|
||||||
char *dest = filtered.get();
|
char *dest = filtered.get();
|
||||||
@ -135,26 +137,26 @@ void ChatTriggers::OnSourceModGameInitialized()
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (ConCommand *say = FindCommand("say")) {
|
if (ConCommand *say = FindCommand("say")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say, post_hook));
|
||||||
}
|
}
|
||||||
if (ConCommand *say_team = FindCommand("say_team")) {
|
if (ConCommand *say_team = FindCommand("say_team")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say_team, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_team, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
||||||
if (m_bIsINS) {
|
if (m_bIsINS) {
|
||||||
if (ConCommand *say2 = FindCommand("say2")) {
|
if (ConCommand *say2 = FindCommand("say2")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say2, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say2, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say2, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say2, post_hook));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||||
if (ConCommand *say_squad = FindCommand("say_squad")) {
|
if (ConCommand *say_squad = FindCommand("say_squad")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -275,10 +277,10 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
|||||||
bool is_silent = false;
|
bool is_silent = false;
|
||||||
|
|
||||||
// Prefer the silent trigger in case of clashes.
|
// Prefer the silent trigger in case of clashes.
|
||||||
if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) {
|
if (strchr(m_PrivTrigger.c_str(), m_ArgSBackup[0])) {
|
||||||
is_trigger = true;
|
is_trigger = true;
|
||||||
is_silent = true;
|
is_silent = true;
|
||||||
} else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) {
|
} else if (strchr(m_PubTrigger.c_str(), m_ArgSBackup[0])) {
|
||||||
is_trigger = true;
|
is_trigger = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +363,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
|||||||
if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
|
if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
|
||||||
{
|
{
|
||||||
/* Check if we had an "sm_" prefix */
|
/* Check if we had an "sm_" prefix */
|
||||||
if (strncmp(cmd_buf, "sm_", 3) == 0)
|
if (strncasecmp(cmd_buf, "sm_", 3) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -385,15 +387,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
|||||||
/* See if we need to do extra string manipulation */
|
/* See if we need to do extra string manipulation */
|
||||||
if (prepended)
|
if (prepended)
|
||||||
{
|
{
|
||||||
size_t len;
|
ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
|
||||||
|
|
||||||
/* Check if we need to prepend sm_ */
|
|
||||||
if (prepended)
|
|
||||||
{
|
|
||||||
len = ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
|
|
||||||
} else {
|
|
||||||
len = ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
||||||
}
|
}
|
||||||
|
@ -73,9 +73,9 @@ private:
|
|||||||
bool ClientIsFlooding(int client);
|
bool ClientIsFlooding(int client);
|
||||||
cell_t CallOnClientSayCommand(int client);
|
cell_t CallOnClientSayCommand(int client);
|
||||||
private:
|
private:
|
||||||
ke::Vector<ke::RefPtr<CommandHook>> hooks_;
|
std::vector<ke::RefPtr<CommandHook>> hooks_;
|
||||||
ke::AString m_PubTrigger;
|
std::string m_PubTrigger;
|
||||||
ke::AString m_PrivTrigger;
|
std::string m_PrivTrigger;
|
||||||
bool m_bWillProcessInPost;
|
bool m_bWillProcessInPost;
|
||||||
bool m_bIsChatTrigger;
|
bool m_bIsChatTrigger;
|
||||||
bool m_bWasFloodedMessage;
|
bool m_bWasFloodedMessage;
|
||||||
|
@ -30,21 +30,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ConCmdManager.h"
|
#include "ConCmdManager.h"
|
||||||
#include "sm_stringutil.h"
|
|
||||||
#include "PlayerManager.h"
|
|
||||||
#include "HalfLife2.h"
|
|
||||||
#include "ChatTriggers.h"
|
|
||||||
#include "logic_bridge.h"
|
|
||||||
#include "sourcemod.h"
|
|
||||||
#include "provider.h"
|
|
||||||
#include "command_args.h"
|
|
||||||
#include <bridge/include/IScriptManager.h>
|
#include <bridge/include/IScriptManager.h>
|
||||||
|
#include "ChatTriggers.h"
|
||||||
|
#include "HalfLife2.h"
|
||||||
|
#include "PlayerManager.h"
|
||||||
|
#include "command_args.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
#include "provider.h"
|
||||||
|
#include "sm_stringutil.h"
|
||||||
|
#include "sourcemod.h"
|
||||||
|
|
||||||
using namespace ke;
|
using namespace ke;
|
||||||
|
|
||||||
ConCmdManager g_ConCmds;
|
ConCmdManager g_ConCmds;
|
||||||
|
|
||||||
typedef ke::LinkedList<CmdHook *> PluginHookList;
|
typedef std::list<CmdHook *> PluginHookList;
|
||||||
void RegisterInPlugin(CmdHook *hook);
|
void RegisterInPlugin(CmdHook *hook);
|
||||||
|
|
||||||
ConCmdManager::ConCmdManager()
|
ConCmdManager::ConCmdManager()
|
||||||
@ -120,8 +121,13 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
|
|||||||
if (hook->admin)
|
if (hook->admin)
|
||||||
hook->admin->group->hooks.remove(hook);
|
hook->admin->group->hooks.remove(hook);
|
||||||
|
|
||||||
if (hook->info->hooks.empty())
|
if (hook->info->hooks.empty()) {
|
||||||
RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true);
|
RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true);
|
||||||
|
}
|
||||||
|
else { // update plugin reference to next hook in line
|
||||||
|
auto next = *hook->info->hooks.begin();
|
||||||
|
next->info->pPlugin = next->plugin;
|
||||||
|
}
|
||||||
|
|
||||||
iter = pList->erase(iter);
|
iter = pList->erase(iter);
|
||||||
delete hook;
|
delete hook;
|
||||||
@ -147,30 +153,13 @@ ConCmdInfo *ConCmdManager::FindInTrie(const char *name)
|
|||||||
return pInfo;
|
return pInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConCmdList::iterator ConCmdManager::FindInList(const char *cmd)
|
|
||||||
{
|
|
||||||
List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
|
|
||||||
|
|
||||||
while (iter != m_CmdList.end())
|
|
||||||
{
|
|
||||||
if (strcasecmp((*iter)->pCmd->GetName(), cmd) == 0)
|
|
||||||
break;
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
|
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
|
||||||
{
|
{
|
||||||
ConCmdInfo *pInfo;
|
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||||
|
|
||||||
if ((pInfo = FindInTrie(cmd)) == NULL)
|
if (pInfo == NULL)
|
||||||
{
|
{
|
||||||
ConCmdList::iterator item = FindInList(cmd);
|
return type;
|
||||||
if (item == m_CmdList.end())
|
|
||||||
return type;
|
|
||||||
pInfo = *item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t result = type;
|
cell_t result = type;
|
||||||
@ -181,7 +170,7 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int
|
|||||||
if (hook->type == CmdHook::Server || !hook->pf->IsRunnable())
|
if (hook->type == CmdHook::Server || !hook->pf->IsRunnable())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (hook->admin && !CheckAccess(client, cmd, hook->admin))
|
if (hook->admin && !CheckAccess(client, cmd, hook->admin.get()))
|
||||||
{
|
{
|
||||||
if (result < Pl_Handled)
|
if (result < Pl_Handled)
|
||||||
result = Pl_Handled;
|
result = Pl_Handled;
|
||||||
@ -225,17 +214,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
|||||||
ConCmdInfo *pInfo = FindInTrie(cmd);
|
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||||
if (pInfo == NULL)
|
if (pInfo == NULL)
|
||||||
{
|
{
|
||||||
/* Unfortunately, we now have to do a slow lookup because Valve made client commands
|
return false;
|
||||||
* case-insensitive. We can't even use our sortedness.
|
|
||||||
*/
|
|
||||||
if (client == 0 && !engine->IsDedicatedServer())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ConCmdList::iterator item = FindInList(cmd);
|
|
||||||
if (item == m_CmdList.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pInfo = *item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a hack to prevent say triggers from firing on messages that were
|
/* This is a hack to prevent say triggers from firing on messages that were
|
||||||
@ -271,7 +250,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
|||||||
} else {
|
} else {
|
||||||
// Check admin rights if needed. realClient isn't needed since we
|
// Check admin rights if needed. realClient isn't needed since we
|
||||||
// should bypass admin checks if client == 0 anyway.
|
// should bypass admin checks if client == 0 anyway.
|
||||||
if (client && hook->admin && !CheckAccess(client, cmd, hook->admin))
|
if (client && hook->admin && !CheckAccess(client, cmd, hook->admin.get()))
|
||||||
{
|
{
|
||||||
if (result < Pl_Handled)
|
if (result < Pl_Handled)
|
||||||
result = Pl_Handled;
|
result = Pl_Handled;
|
||||||
@ -359,8 +338,8 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
|||||||
}
|
}
|
||||||
RefPtr<CommandGroup> cmdgroup = i->value;
|
RefPtr<CommandGroup> cmdgroup = i->value;
|
||||||
|
|
||||||
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description);
|
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description, pPlugin);
|
||||||
pHook->admin = new AdminCmdInfo(cmdgroup, adminflags);
|
pHook->admin = std::make_unique<AdminCmdInfo>(cmdgroup, adminflags);
|
||||||
|
|
||||||
/* First get the command group override, if any */
|
/* First get the command group override, if any */
|
||||||
bool override = adminsys->GetCommandOverride(group,
|
bool override = adminsys->GetCommandOverride(group,
|
||||||
@ -380,7 +359,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
|||||||
pHook->admin->eflags = pHook->admin->flags;
|
pHook->admin->eflags = pHook->admin->flags;
|
||||||
pInfo->eflags = pHook->admin->eflags;
|
pInfo->eflags = pHook->admin->eflags;
|
||||||
|
|
||||||
cmdgroup->hooks.append(pHook);
|
cmdgroup->hooks.push_back(pHook);
|
||||||
pInfo->hooks.append(pHook);
|
pInfo->hooks.append(pHook);
|
||||||
RegisterInPlugin(pHook);
|
RegisterInPlugin(pHook);
|
||||||
return true;
|
return true;
|
||||||
@ -398,7 +377,7 @@ bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
|
|||||||
if (!pInfo)
|
if (!pInfo)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description);
|
CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description, pPlugin);
|
||||||
|
|
||||||
pInfo->hooks.append(pHook);
|
pInfo->hooks.append(pHook);
|
||||||
RegisterInPlugin(pHook);
|
RegisterInPlugin(pHook);
|
||||||
@ -425,13 +404,13 @@ void RegisterInPlugin(CmdHook *hook)
|
|||||||
const char *cmd = (*iter)->info->pCmd->GetName();
|
const char *cmd = (*iter)->info->pCmd->GetName();
|
||||||
if (strcmp(orig, cmd) < 0)
|
if (strcmp(orig, cmd) < 0)
|
||||||
{
|
{
|
||||||
pList->insertBefore(iter, hook);
|
pList->emplace(iter, hook);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pList->append(hook);
|
pList->emplace_back(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConCmdManager::AddToCmdList(ConCmdInfo *info)
|
void ConCmdManager::AddToCmdList(ConCmdInfo *info)
|
||||||
@ -495,7 +474,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
|
|||||||
for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++)
|
for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++)
|
||||||
{
|
{
|
||||||
CmdHook *hook = *iter;
|
CmdHook *hook = *iter;
|
||||||
if (remove)
|
if (!remove)
|
||||||
hook->admin->eflags = bits;
|
hook->admin->eflags = bits;
|
||||||
else
|
else
|
||||||
hook->admin->eflags = hook->admin->flags;
|
hook->admin->eflags = hook->admin->flags;
|
||||||
@ -562,10 +541,6 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
|
|||||||
ConCmdInfo *pInfo;
|
ConCmdInfo *pInfo;
|
||||||
if (!m_Cmds.retrieve(name, &pInfo))
|
if (!m_Cmds.retrieve(name, &pInfo))
|
||||||
{
|
{
|
||||||
ConCmdList::iterator item = FindInList(name);
|
|
||||||
if (item != m_CmdList.end())
|
|
||||||
return *item;
|
|
||||||
|
|
||||||
pInfo = new ConCmdInfo();
|
pInfo = new ConCmdInfo();
|
||||||
/* Find the commandopan */
|
/* Find the commandopan */
|
||||||
ConCommand *pCmd = FindCommand(name);
|
ConCommand *pCmd = FindCommand(name);
|
||||||
@ -648,7 +623,7 @@ void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
|||||||
|
|
||||||
name = hook->info->pCmd->GetName();
|
name = hook->info->pCmd->GetName();
|
||||||
if (hook->helptext.length())
|
if (hook->helptext.length())
|
||||||
help = hook->helptext.chars();
|
help = hook->helptext.c_str();
|
||||||
else
|
else
|
||||||
help = hook->info->pCmd->GetHelpText();
|
help = hook->info->pCmd->GetHelpText();
|
||||||
UTIL_ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
|
UTIL_ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
|
||||||
|
@ -32,6 +32,14 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
#ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||||
#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <am-inlinelist.h>
|
||||||
|
#include <am-refcounting.h>
|
||||||
|
#include <am-utility.h>
|
||||||
|
#include <sm_stringhashmap.h>
|
||||||
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
@ -41,12 +49,7 @@
|
|||||||
#include <IAdminSystem.h>
|
#include <IAdminSystem.h>
|
||||||
#include "concmd_cleaner.h"
|
#include "concmd_cleaner.h"
|
||||||
#include "GameHooks.h"
|
#include "GameHooks.h"
|
||||||
#include <am-autoptr.h>
|
#include <sm_namehashset.h>
|
||||||
#include <sm_stringhashmap.h>
|
|
||||||
#include <am-utility.h>
|
|
||||||
#include <am-inlinelist.h>
|
|
||||||
#include <am-linkedlist.h>
|
|
||||||
#include <am-refcounting.h>
|
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
@ -55,7 +58,7 @@ struct ConCmdInfo;
|
|||||||
|
|
||||||
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
||||||
{
|
{
|
||||||
ke::LinkedList<CmdHook *> hooks;
|
std::list<CmdHook *> hooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AdminCmdInfo
|
struct AdminCmdInfo
|
||||||
@ -78,10 +81,11 @@ struct CmdHook : public ke::InlineListNode<CmdHook>
|
|||||||
Client
|
Client
|
||||||
};
|
};
|
||||||
|
|
||||||
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description)
|
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description, IPlugin *plugin)
|
||||||
: type(type),
|
: type(type),
|
||||||
info(cmd),
|
info(cmd),
|
||||||
pf(fun),
|
pf(fun),
|
||||||
|
plugin(plugin),
|
||||||
helptext(description)
|
helptext(description)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -89,8 +93,9 @@ struct CmdHook : public ke::InlineListNode<CmdHook>
|
|||||||
Type type;
|
Type type;
|
||||||
ConCmdInfo *info;
|
ConCmdInfo *info;
|
||||||
IPluginFunction *pf; /* function hook */
|
IPluginFunction *pf; /* function hook */
|
||||||
ke::AString helptext; /* help text */
|
IPlugin *plugin; /* owning plugin */
|
||||||
ke::AutoPtr<AdminCmdInfo> admin; /* admin requirements, if any */
|
std::string helptext; /* help text */
|
||||||
|
std::unique_ptr<AdminCmdInfo> admin; /* admin requirements, if any */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ke::InlineList<CmdHook> CmdHookList;
|
typedef ke::InlineList<CmdHook> CmdHookList;
|
||||||
@ -104,12 +109,32 @@ struct ConCmdInfo
|
|||||||
pCmd = nullptr;
|
pCmd = nullptr;
|
||||||
eflags = 0;
|
eflags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
||||||
ConCommand *pCmd; /**< Pointer to the command itself */
|
ConCommand *pCmd; /**< Pointer to the command itself */
|
||||||
CmdHookList hooks; /**< Hook list */
|
CmdHookList hooks; /**< Hook list */
|
||||||
FlagBits eflags; /**< Effective admin flags */
|
FlagBits eflags; /**< Effective admin flags */
|
||||||
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
|
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
|
||||||
IPlugin *pPlugin; /**< Owning plugin handle. */
|
IPlugin *pPlugin; /**< Owning plugin handle. */
|
||||||
|
|
||||||
|
struct ConCmdPolicy
|
||||||
|
{
|
||||||
|
static inline bool matches(const char *name, ConCmdInfo *info)
|
||||||
|
{
|
||||||
|
const char *conCmdChars = info->pCmd->GetName();
|
||||||
|
|
||||||
|
std::string concmdName = ke::Lowercase(conCmdChars);
|
||||||
|
std::string input = ke::Lowercase(name);
|
||||||
|
|
||||||
|
return concmdName == input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
|
{
|
||||||
|
std::string lower = ke::Lowercase(key.c_str());
|
||||||
|
return detail::CharsAndLength(lower.c_str()).hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef List<ConCmdInfo *> ConCmdList;
|
typedef List<ConCmdInfo *> ConCmdList;
|
||||||
@ -153,11 +178,6 @@ private:
|
|||||||
void AddToCmdList(ConCmdInfo *info);
|
void AddToCmdList(ConCmdInfo *info);
|
||||||
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
|
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
|
||||||
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
||||||
|
|
||||||
// Case insensitive
|
|
||||||
ConCmdList::iterator FindInList(const char *name);
|
|
||||||
|
|
||||||
// Case sensitive
|
|
||||||
ConCmdInfo *FindInTrie(const char *name);
|
ConCmdInfo *FindInTrie(const char *name);
|
||||||
public:
|
public:
|
||||||
inline const List<ConCmdInfo *> & GetCommandList()
|
inline const List<ConCmdInfo *> & GetCommandList()
|
||||||
@ -167,7 +187,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap;
|
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap;
|
||||||
|
|
||||||
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */
|
NameHashSet<ConCmdInfo *, ConCmdInfo::ConCmdPolicy> m_Cmds; /* command lookup */
|
||||||
GroupMap m_CmdGrps; /* command group map */
|
GroupMap m_CmdGrps; /* command group map */
|
||||||
ConCmdList m_CmdList; /* command list */
|
ConCmdList m_CmdList; /* command list */
|
||||||
};
|
};
|
||||||
|
@ -41,7 +41,11 @@ ConVarManager g_ConVarManager;
|
|||||||
|
|
||||||
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
||||||
typedef List<const ConVar *> ConVarList;
|
typedef List<const ConVar *> ConVarList;
|
||||||
NameHashSet<ConVarInfo *> convar_cache;
|
NameHashSet<ConVarInfo *, ConVarInfo::ConVarPolicy> convar_cache;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
eQueryCvarValueStatus_Cancelled = -1,
|
||||||
|
};
|
||||||
|
|
||||||
class ConVarReentrancyGuard
|
class ConVarReentrancyGuard
|
||||||
{
|
{
|
||||||
@ -206,18 +210,27 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
|||||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||||
{
|
{
|
||||||
ConVarList *pConVarList;
|
ConVarList *pConVarList;
|
||||||
List<ConVarQuery>::iterator iter;
|
|
||||||
|
|
||||||
/* If plugin has a convar list, free its memory */
|
/* If plugin has a convar list, free its memory */
|
||||||
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
||||||
{
|
{
|
||||||
delete pConVarList;
|
delete pConVarList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear any references to this plugin as the convar creator */
|
||||||
|
for (List<ConVarInfo *>::iterator iter = m_ConVars.begin(); iter != m_ConVars.end(); ++iter)
|
||||||
|
{
|
||||||
|
ConVarInfo *pInfo = (*iter);
|
||||||
|
|
||||||
|
if (pInfo->pPlugin == plugin)
|
||||||
|
{
|
||||||
|
pInfo->pPlugin = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
||||||
|
|
||||||
/* Remove convar queries for this plugin that haven't returned results yet */
|
/* Remove convar queries for this plugin that haven't returned results yet */
|
||||||
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||||
{
|
{
|
||||||
ConVarQuery &query = (*iter);
|
ConVarQuery &query = (*iter);
|
||||||
if (query.pCallback->GetParentRuntime() == pRuntime)
|
if (query.pCallback->GetParentRuntime() == pRuntime)
|
||||||
@ -238,6 +251,19 @@ void ConVarManager::OnClientDisconnected(int client)
|
|||||||
ConVarQuery &query = (*iter);
|
ConVarQuery &query = (*iter);
|
||||||
if (query.client == client)
|
if (query.client == client)
|
||||||
{
|
{
|
||||||
|
IPluginFunction *pCallback = query.pCallback;
|
||||||
|
if (pCallback)
|
||||||
|
{
|
||||||
|
cell_t ret;
|
||||||
|
|
||||||
|
pCallback->PushCell(query.cookie);
|
||||||
|
pCallback->PushCell(client);
|
||||||
|
pCallback->PushCell(eQueryCvarValueStatus_Cancelled);
|
||||||
|
pCallback->PushString("");
|
||||||
|
pCallback->PushString("");
|
||||||
|
pCallback->PushCell(query.value);
|
||||||
|
pCallback->Execute(&ret);
|
||||||
|
}
|
||||||
iter = m_ConVarQueries.erase(iter);
|
iter = m_ConVarQueries.erase(iter);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -330,6 +356,8 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
ConVarInfo *pInfo = NULL;
|
ConVarInfo *pInfo = NULL;
|
||||||
Handle_t hndl = 0;
|
Handle_t hndl = 0;
|
||||||
|
|
||||||
|
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
||||||
|
|
||||||
/* Find out if the convar exists already */
|
/* Find out if the convar exists already */
|
||||||
pConVar = icvar->FindVar(name);
|
pConVar = icvar->FindVar(name);
|
||||||
|
|
||||||
@ -337,11 +365,16 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
if (pConVar)
|
if (pConVar)
|
||||||
{
|
{
|
||||||
/* Add convar to plugin's list */
|
/* Add convar to plugin's list */
|
||||||
AddConVarToPluginList(pContext, pConVar);
|
AddConVarToPluginList(plugin, pConVar);
|
||||||
|
|
||||||
/* First find out if we already have a handle to it */
|
/* First find out if we already have a handle to it */
|
||||||
if (convar_cache_lookup(name, &pInfo))
|
if (convar_cache_lookup(name, &pInfo))
|
||||||
{
|
{
|
||||||
|
/* If the convar doesn't have an owning plugin, but SM created it, adopt it */
|
||||||
|
if (pInfo->sourceMod && pInfo->pPlugin == nullptr) {
|
||||||
|
pInfo->pPlugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
return pInfo->handle;
|
return pInfo->handle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -382,6 +415,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
pInfo->handle = hndl;
|
pInfo->handle = hndl;
|
||||||
pInfo->sourceMod = true;
|
pInfo->sourceMod = true;
|
||||||
pInfo->pChangeForward = NULL;
|
pInfo->pChangeForward = NULL;
|
||||||
|
pInfo->pPlugin = plugin;
|
||||||
|
|
||||||
/* Create a handle from the new convar */
|
/* Create a handle from the new convar */
|
||||||
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||||
@ -398,7 +432,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
pInfo->pVar = pConVar;
|
pInfo->pVar = pConVar;
|
||||||
|
|
||||||
/* Add convar to plugin's list */
|
/* Add convar to plugin's list */
|
||||||
AddConVarToPluginList(pContext, pConVar);
|
AddConVarToPluginList(plugin, pConVar);
|
||||||
|
|
||||||
/* Insert struct into caches */
|
/* Insert struct into caches */
|
||||||
m_ConVars.push_back(pInfo);
|
m_ConVars.push_back(pInfo);
|
||||||
@ -552,15 +586,13 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
|
|||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar)
|
void ConVarManager::AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar)
|
||||||
{
|
{
|
||||||
ConVarList *pConVarList;
|
ConVarList *pConVarList;
|
||||||
ConVarList::iterator iter;
|
ConVarList::iterator iter;
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
const char *orig = pConVar->GetName();
|
const char *orig = pConVar->GetName();
|
||||||
|
|
||||||
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
|
||||||
|
|
||||||
/* Check plugin for an existing convar list */
|
/* Check plugin for an existing convar list */
|
||||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||||
{
|
{
|
||||||
@ -679,7 +711,7 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin)
|
||||||
{
|
{
|
||||||
ConVarInfo *pInfo;
|
ConVarInfo *pInfo;
|
||||||
HandleError error;
|
HandleError error;
|
||||||
@ -694,5 +726,10 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
|||||||
*pVar = pInfo->pVar;
|
*pVar = pInfo->pVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ppPlugin)
|
||||||
|
{
|
||||||
|
*ppPlugin = pInfo->pPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -62,16 +62,27 @@ struct ConVarInfo
|
|||||||
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
|
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
|
||||||
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
||||||
ConVar *pVar; /**< The actual convar */
|
ConVar *pVar; /**< The actual convar */
|
||||||
|
IPlugin *pPlugin; /**< Originally owning plugin */
|
||||||
List<IConVarChangeListener *> changeListeners;
|
List<IConVarChangeListener *> changeListeners;
|
||||||
|
|
||||||
static inline bool matches(const char *name, const ConVarInfo *info)
|
struct ConVarPolicy
|
||||||
{
|
{
|
||||||
return strcmp(name, info->pVar->GetName()) == 0;
|
static inline bool matches(const char *name, ConVarInfo *info)
|
||||||
}
|
{
|
||||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
const char *conVarChars = info->pVar->GetName();
|
||||||
{
|
|
||||||
return key.hash();
|
std::string convarName = ke::Lowercase(conVarChars);
|
||||||
}
|
std::string input = ke::Lowercase(name);
|
||||||
|
|
||||||
|
return convarName == input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
|
{
|
||||||
|
std::string lower = ke::Lowercase(key.c_str());
|
||||||
|
return detail::CharsAndLength(lower.c_str()).hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,7 +155,7 @@ public:
|
|||||||
|
|
||||||
bool IsQueryingSupported();
|
bool IsQueryingSupported();
|
||||||
|
|
||||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
|
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin = nullptr);
|
||||||
|
|
||||||
// Called via game hooks.
|
// Called via game hooks.
|
||||||
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||||
@ -161,7 +172,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Adds a convar to a plugin's list.
|
* Adds a convar to a plugin's list.
|
||||||
*/
|
*/
|
||||||
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
|
static void AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar);
|
||||||
private:
|
private:
|
||||||
HandleType_t m_ConVarType;
|
HandleType_t m_ConVarType;
|
||||||
List<ConVarInfo *> m_ConVars;
|
List<ConVarInfo *> m_ConVars;
|
||||||
|
@ -307,7 +307,7 @@ bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
|
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||||
IChangeableForward *forward;
|
IChangeableForward *forward;
|
||||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||||
{
|
{
|
||||||
@ -329,7 +329,7 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
|
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||||
IChangeableForward *forward;
|
IChangeableForward *forward;
|
||||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||||
return false;
|
return false;
|
||||||
|
@ -290,18 +290,18 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
|
|||||||
pBase = pBase->m_pGlobalClassNext;
|
pBase = pBase->m_pGlobalClassNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::AString vstr(value);
|
std::string vstr(value);
|
||||||
m_KeyValues.replace(option, ke::Move(vstr));
|
m_KeyValues.replace(option, std::move(vstr));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
||||||
{
|
{
|
||||||
StringHashMap<ke::AString>::Result r = m_KeyValues.find(key);
|
StringHashMap<std::string>::Result r = m_KeyValues.find(key);
|
||||||
if (!r.found())
|
if (!r.found())
|
||||||
return NULL;
|
return NULL;
|
||||||
return r->value.chars();
|
return r->value.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SM_AreConfigsExecuted()
|
bool SM_AreConfigsExecuted()
|
||||||
|
@ -68,7 +68,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
||||||
private:
|
private:
|
||||||
StringHashMap<ke::AString> m_KeyValues;
|
StringHashMap<std::string> m_KeyValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool SM_AreConfigsExecuted();
|
extern bool SM_AreConfigsExecuted();
|
||||||
|
@ -484,7 +484,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
pForward->PushCell(BAD_HANDLE);
|
pForward->PushCell(BAD_HANDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pForward->PushString(pHook->name.chars());
|
pForward->PushString(pHook->name.c_str());
|
||||||
pForward->PushCell(bDontBroadcast);
|
pForward->PushCell(bDontBroadcast);
|
||||||
pForward->Execute(NULL);
|
pForward->Execute(NULL);
|
||||||
|
|
||||||
@ -505,7 +505,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
{
|
{
|
||||||
assert(pHook->pPostHook == NULL);
|
assert(pHook->pPostHook == NULL);
|
||||||
assert(pHook->pPreHook == NULL);
|
assert(pHook->pPreHook == NULL);
|
||||||
m_EventHooks.remove(pHook->name.chars());
|
m_EventHooks.remove(pHook->name.c_str());
|
||||||
delete pHook;
|
delete pHook;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,11 @@ struct EventHook
|
|||||||
IChangeableForward *pPostHook;
|
IChangeableForward *pPostHook;
|
||||||
bool postCopy;
|
bool postCopy;
|
||||||
unsigned int refCount;
|
unsigned int refCount;
|
||||||
ke::AString name;
|
std::string name;
|
||||||
|
|
||||||
static inline bool matches(const char *name, const EventHook *hook)
|
static inline bool matches(const char *name, const EventHook *hook)
|
||||||
{
|
{
|
||||||
return strcmp(name, hook->name.chars()) == 0;
|
return strcmp(name, hook->name.c_str()) == 0;
|
||||||
}
|
}
|
||||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +91,7 @@ void GameHooks::OnVSPReceived()
|
|||||||
|
|
||||||
void GameHooks::Shutdown()
|
void GameHooks::Shutdown()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < hooks_.length(); i++)
|
for (size_t i = 0; i < hooks_.size(); i++)
|
||||||
SH_REMOVE_HOOK_ID(hooks_[i]);
|
SH_REMOVE_HOOK_ID(hooks_[i]);
|
||||||
hooks_.clear();
|
hooks_.clear();
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla
|
|||||||
const char *cvarName, const char *cvarValue){
|
const char *cvarName, const char *cvarValue){
|
||||||
int client = IndexOfEdict(pPlayer);
|
int client = IndexOfEdict(pPlayer);
|
||||||
|
|
||||||
# if SOURCE_ENGINE == SE_CSGO
|
# if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
|
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
|
||||||
return;
|
return;
|
||||||
# endif
|
# endif
|
||||||
|
@ -63,7 +63,7 @@ class CommandHook : public ke::Refcounted<CommandHook>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
|
// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
|
||||||
typedef ke::Lambda<bool(int, const ICommandArgs *)> Callback;
|
typedef ke::Function<bool(int, const ICommandArgs *)> Callback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
|
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
|
||||||
@ -114,11 +114,11 @@ private:
|
|||||||
void SetCommandClient(int client);
|
void SetCommandClient(int client);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class HookList : public ke::Vector<int>
|
class HookList : public std::vector<int>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HookList &operator += (int hook_id) {
|
HookList &operator += (int hook_id) {
|
||||||
this->append(hook_id);
|
this->push_back(hook_id);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -45,9 +45,10 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
#include <cstrike15_usermessages.pb.h>
|
#include <cstrike15_usermessages.pb.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
#include <berimbau_usermessages.pb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef ICommandLine *(*FakeGetCommandLine)();
|
typedef ICommandLine *(*FakeGetCommandLine)();
|
||||||
|
|
||||||
#define TIER0_NAME FORMAT_SOURCE_BIN_NAME("tier0")
|
#define TIER0_NAME FORMAT_SOURCE_BIN_NAME("tier0")
|
||||||
@ -59,6 +60,7 @@ ConVar *sv_lan = NULL;
|
|||||||
static void *g_EntList = NULL;
|
static void *g_EntList = NULL;
|
||||||
static void **g_pEntInfoList = NULL;
|
static void **g_pEntInfoList = NULL;
|
||||||
static int entInfoOffset = -1;
|
static int entInfoOffset = -1;
|
||||||
|
static int utlVecOffsetOffset = -1;
|
||||||
|
|
||||||
static CEntInfo *EntInfoArray()
|
static CEntInfo *EntInfoArray()
|
||||||
{
|
{
|
||||||
@ -143,6 +145,7 @@ void CHalfLife2::OnSourceModAllInitialized_Post()
|
|||||||
m_CSGOBadList.add("m_nActiveCoinRank");
|
m_CSGOBadList.add("m_nActiveCoinRank");
|
||||||
m_CSGOBadList.add("m_nMusicID");
|
m_CSGOBadList.add("m_nMusicID");
|
||||||
#endif
|
#endif
|
||||||
|
g_pGameConf->GetOffset("CSendPropExtra_UtlVector::m_Offset", &utlVecOffsetOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult CHalfLife2::OnSourceModConfigChanged(const char *key, const char *value,
|
ConfigResult CHalfLife2::OnSourceModConfigChanged(const char *key, const char *value,
|
||||||
@ -180,6 +183,7 @@ void CHalfLife2::InitLogicalEntData()
|
|||||||
|| SOURCE_ENGINE == SE_CSS \
|
|| SOURCE_ENGINE == SE_CSS \
|
||||||
|| SOURCE_ENGINE == SE_SDK2013 \
|
|| SOURCE_ENGINE == SE_SDK2013 \
|
||||||
|| SOURCE_ENGINE == SE_BMS \
|
|| SOURCE_ENGINE == SE_BMS \
|
||||||
|
|| SOURCE_ENGINE == SE_BLADE \
|
||||||
|| SOURCE_ENGINE == SE_NUCLEARDAWN
|
|| SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||||
|
|
||||||
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
|
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
|
||||||
@ -317,23 +321,41 @@ bool UTIL_FindInSendTable(SendTable *pTable,
|
|||||||
sm_sendprop_info_t *info,
|
sm_sendprop_info_t *info,
|
||||||
unsigned int offset)
|
unsigned int offset)
|
||||||
{
|
{
|
||||||
const char *pname;
|
|
||||||
int props = pTable->GetNumProps();
|
int props = pTable->GetNumProps();
|
||||||
SendProp *prop;
|
for (int i = 0; i < props; i++)
|
||||||
|
|
||||||
for (int i=0; i<props; i++)
|
|
||||||
{
|
{
|
||||||
prop = pTable->GetProp(i);
|
SendProp *prop = pTable->GetProp(i);
|
||||||
pname = prop->GetName();
|
|
||||||
|
// Skip InsideArray props (SendPropArray / SendPropArray2),
|
||||||
|
// we'll find them later by their containing array.
|
||||||
|
if (prop->IsInsideArray()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *pname = prop->GetName();
|
||||||
|
SendTable *pInnerTable = prop->GetDataTable();
|
||||||
|
|
||||||
if (pname && strcmp(name, pname) == 0)
|
if (pname && strcmp(name, pname) == 0)
|
||||||
{
|
{
|
||||||
|
// get true offset of CUtlVector
|
||||||
|
if (utlVecOffsetOffset != -1 && prop->GetOffset() == 0 && pInnerTable && pInnerTable->GetNumProps())
|
||||||
|
{
|
||||||
|
SendProp *pLengthProxy = pInnerTable->GetProp(0);
|
||||||
|
const char *ipname = pLengthProxy->GetName();
|
||||||
|
if (ipname && strcmp(ipname, "lengthproxy") == 0 && pLengthProxy->GetExtraData())
|
||||||
|
{
|
||||||
|
info->prop = prop;
|
||||||
|
info->actual_offset = offset + *reinterpret_cast<size_t *>(reinterpret_cast<intptr_t>(pLengthProxy->GetExtraData()) + utlVecOffsetOffset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
info->prop = prop;
|
info->prop = prop;
|
||||||
info->actual_offset = offset + info->prop->GetOffset();
|
info->actual_offset = offset + info->prop->GetOffset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (prop->GetDataTable())
|
if (pInnerTable)
|
||||||
{
|
{
|
||||||
if (UTIL_FindInSendTable(prop->GetDataTable(),
|
if (UTIL_FindInSendTable(pInnerTable,
|
||||||
name,
|
name,
|
||||||
info,
|
info,
|
||||||
offset + prop->GetOffset())
|
offset + prop->GetOffset())
|
||||||
@ -516,7 +538,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
char buffer[253];
|
char buffer[253];
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
|
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
CCSUsrMsg_SayText *pMsg;
|
CCSUsrMsg_SayText *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -543,7 +565,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
CCSUsrMsg_TextMsg *pMsg;
|
CCSUsrMsg_TextMsg *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -580,7 +602,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
|||||||
{
|
{
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
CCSUsrMsg_HintText *pMsg;
|
CCSUsrMsg_HintText *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -610,7 +632,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
|||||||
|
|
||||||
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
CCSUsrMsg_HintText *pMsg;
|
CCSUsrMsg_HintText *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -645,7 +667,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
CCSUsrMsg_VGUIMenu *pMsg;
|
CCSUsrMsg_VGUIMenu *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -670,7 +692,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
|||||||
SubKey = data->GetFirstSubKey();
|
SubKey = data->GetFirstSubKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
pMsg->set_name(name);
|
pMsg->set_name(name);
|
||||||
pMsg->set_show(show);
|
pMsg->set_show(show);
|
||||||
|
|
||||||
@ -1212,6 +1234,45 @@ bool IsWindowsReservedDeviceName(const char *pMapname)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#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 >
|
||||||
|
class CUtlMemoryGlobalMalloc : public CUtlMemory< T, I >
|
||||||
|
{
|
||||||
|
typedef CUtlMemory< T, I > BaseClass;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using BaseClass::BaseClass;
|
||||||
|
|
||||||
|
void Purge()
|
||||||
|
{
|
||||||
|
if (!IsExternallyAllocated())
|
||||||
|
{
|
||||||
|
if (m_pMemory)
|
||||||
|
{
|
||||||
|
UTLMEMORY_TRACK_FREE();
|
||||||
|
g_pMemAlloc->Free((void*)m_pMemory);
|
||||||
|
m_pMemory = 0;
|
||||||
|
}
|
||||||
|
m_nAllocationCount = 0;
|
||||||
|
}
|
||||||
|
BaseClass::Purge();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void CHalfLife2::FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec)
|
||||||
|
{
|
||||||
|
CUtlMemoryGlobalMalloc<unsigned char> *pMemory;
|
||||||
|
FOR_EACH_VEC(vec, i)
|
||||||
|
{
|
||||||
|
pMemory = (CUtlMemoryGlobalMalloc<unsigned char> *) &vec[i].m_Storage.m_Memory;
|
||||||
|
pMemory->Purge();
|
||||||
|
vec[i].m_Storage.SetLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax)
|
SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax)
|
||||||
{
|
{
|
||||||
/* We need to ensure user input does not contain reserved device names on windows */
|
/* We need to ensure user input does not contain reserved device names on windows */
|
||||||
@ -1245,8 +1306,13 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
|
|||||||
|
|
||||||
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> results;
|
||||||
|
pHelperCmd->AutoCompleteSuggest(pMapName, *(CUtlVector<CUtlString, CUtlMemory<CUtlString>>*)&results);
|
||||||
|
#else
|
||||||
CUtlVector<CUtlString> results;
|
CUtlVector<CUtlString> results;
|
||||||
pHelperCmd->AutoCompleteSuggest(pMapName, results);
|
pHelperCmd->AutoCompleteSuggest(pMapName, results);
|
||||||
|
#endif
|
||||||
if (results.Count() == 0)
|
if (results.Count() == 0)
|
||||||
return SMFindMapResult::NotFound;
|
return SMFindMapResult::NotFound;
|
||||||
|
|
||||||
@ -1258,11 +1324,17 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
|
|||||||
bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
|
bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
|
||||||
if (bExactMatch)
|
if (bExactMatch)
|
||||||
{
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
FreeUtlVectorUtlString(results);
|
||||||
|
#endif
|
||||||
return SMFindMapResult::Found;
|
return SMFindMapResult::Found;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]);
|
ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]);
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
FreeUtlVectorUtlString(results);
|
||||||
|
#endif
|
||||||
return SMFindMapResult::FuzzyMatch;
|
return SMFindMapResult::FuzzyMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1316,8 +1388,36 @@ bool CHalfLife2::IsMapValid(const char *map)
|
|||||||
return FindMap(map) == SMFindMapResult::Found;
|
return FindMap(map) == SMFindMapResult::Found;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add ep1 support for this. (No IServerTools available there)
|
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
class VKeyValuesSS_Helper {};
|
||||||
|
static bool VKeyValuesSS(CBaseEntity* pThisPtr, const char *pszKey, const char *pszValue, int offset)
|
||||||
|
{
|
||||||
|
void** this_ptr = *reinterpret_cast<void***>(&pThisPtr);
|
||||||
|
void** vtable = *reinterpret_cast<void***>(pThisPtr);
|
||||||
|
void* vfunc = vtable[offset];
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool (VKeyValuesSS_Helper::* mfpnew)(const char *, const char *);
|
||||||
|
#ifndef PLATFORM_POSIX
|
||||||
|
void* addr;
|
||||||
|
} u;
|
||||||
|
u.addr = vfunc;
|
||||||
|
#else
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
void* addr;
|
||||||
|
intptr_t adjustor;
|
||||||
|
} s;
|
||||||
|
} u;
|
||||||
|
u.s.addr = vfunc;
|
||||||
|
u.s.adjustor = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (bool)(reinterpret_cast<VKeyValuesSS_Helper*>(this_ptr)->*u.mfpnew)(pszKey, pszValue);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
string_t CHalfLife2::AllocPooledString(const char *pszValue)
|
string_t CHalfLife2::AllocPooledString(const char *pszValue)
|
||||||
{
|
{
|
||||||
// This is admittedly a giant hack, but it's a relatively safe method for
|
// This is admittedly a giant hack, but it's a relatively safe method for
|
||||||
@ -1327,28 +1427,58 @@ string_t CHalfLife2::AllocPooledString(const char *pszValue)
|
|||||||
// current targetname string_t, set it to our string to insert via SetKeyValue,
|
// current targetname string_t, set it to our string to insert via SetKeyValue,
|
||||||
// read back the new targetname value, restore the old value, and return the new one.
|
// read back the new targetname value, restore the old value, and return the new one.
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||||
|
CBaseEntity* pEntity = nullptr;
|
||||||
|
for (int i = 0; i < gpGlobals->maxEntities; ++i)
|
||||||
|
{
|
||||||
|
pEntity = ReferenceToEntity(i);
|
||||||
|
if (pEntity)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pEntity)
|
||||||
|
{
|
||||||
|
logger->LogError("Failed to locate a valid entity for AllocPooledString.");
|
||||||
|
return NULL_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity();
|
CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity();
|
||||||
|
#endif
|
||||||
auto *pDataMap = GetDataMap(pEntity);
|
auto *pDataMap = GetDataMap(pEntity);
|
||||||
assert(pDataMap);
|
assert(pDataMap);
|
||||||
|
|
||||||
static int offset = -1;
|
static int iNameOffset = -1;
|
||||||
if (offset == -1)
|
if (iNameOffset == -1)
|
||||||
{
|
{
|
||||||
sm_datatable_info_t info;
|
sm_datatable_info_t info;
|
||||||
bool found = FindDataMapInfo(pDataMap, "m_iName", &info);
|
bool found = FindDataMapInfo(pDataMap, "m_iName", &info);
|
||||||
assert(found);
|
assert(found);
|
||||||
offset = info.actual_offset;
|
iNameOffset = info.actual_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t *pProp = (string_t *) ((intp) pEntity + offset);
|
string_t* pProp = (string_t*)((intp)pEntity + iNameOffset);
|
||||||
string_t backup = *pProp;
|
string_t backup = *pProp;
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||||
|
static int iFuncOffset;
|
||||||
|
if (!g_pGameConf->GetOffset("DispatchKeyValue", &iFuncOffset) || !iFuncOffset)
|
||||||
|
{
|
||||||
|
logger->LogError("Failed to locate DispatchKeyValue in core gamedata. AllocPooledString unsupported.");
|
||||||
|
return NULL_STRING;
|
||||||
|
}
|
||||||
|
VKeyValuesSS(pEntity, "targetname", pszValue, iFuncOffset);
|
||||||
|
#else
|
||||||
servertools->SetKeyValue(pEntity, "targetname", pszValue);
|
servertools->SetKeyValue(pEntity, "targetname", pszValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
string_t newString = *pProp;
|
string_t newString = *pProp;
|
||||||
*pProp = backup;
|
*pProp = backup;
|
||||||
|
|
||||||
return newString;
|
return newString;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const
|
bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const
|
||||||
{
|
{
|
||||||
|
@ -179,6 +179,12 @@ enum class SMFindMapResult : cell_t {
|
|||||||
PossiblyAvailable
|
PossiblyAvailable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS
|
||||||
|
template< class T, class I = int >
|
||||||
|
class CUtlMemoryGlobalMalloc;
|
||||||
|
class CUtlString;
|
||||||
|
#endif
|
||||||
|
|
||||||
class CHalfLife2 :
|
class CHalfLife2 :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IGameHelpers
|
public IGameHelpers
|
||||||
@ -229,10 +235,11 @@ public: //IGameHelpers
|
|||||||
bool IsMapValid(const char *map);
|
bool IsMapValid(const char *map);
|
||||||
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
|
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
|
||||||
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
|
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
|
||||||
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
void FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec);
|
||||||
string_t AllocPooledString(const char *pszValue);
|
|
||||||
#endif
|
#endif
|
||||||
|
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
|
||||||
|
string_t AllocPooledString(const char *pszValue);
|
||||||
bool GetServerSteam3Id(char *pszOut, size_t len) const override;
|
bool GetServerSteam3Id(char *pszOut, size_t len) const override;
|
||||||
uint64_t GetServerSteamId64() const override;
|
uint64_t GetServerSteamId64() const override;
|
||||||
public:
|
public:
|
||||||
@ -271,7 +278,7 @@ public:
|
|||||||
return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName);
|
return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
ke::HashSet<ke::AString, detail::StringHashMapPolicy> m_CSGOBadList;
|
ke::HashSet<std::string, detail::StringHashMapPolicy> m_CSGOBadList;
|
||||||
bool m_bFollowCSGOServerGuidelines = true;
|
bool m_bFollowCSGOServerGuidelines = true;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include "CellRecipientFilter.h"
|
#include "CellRecipientFilter.h"
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
#include "Logger.h"
|
#include <bridge/include/ILogger.h>
|
||||||
#endif
|
#endif
|
||||||
#include "logic_bridge.h"
|
#include "logic_bridge.h"
|
||||||
#include "AutoHandleRooter.h"
|
#include "AutoHandleRooter.h"
|
||||||
@ -59,7 +59,7 @@ Handle_t BaseMenuStyle::GetHandle()
|
|||||||
void BaseMenuStyle::AddClientToWatch(int client)
|
void BaseMenuStyle::AddClientToWatch(int client)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
|
logger->LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
|
||||||
#endif
|
#endif
|
||||||
m_WatchList.push_back(client);
|
m_WatchList.push_back(client);
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ void BaseMenuStyle::AddClientToWatch(int client)
|
|||||||
void BaseMenuStyle::RemoveClientFromWatch(int client)
|
void BaseMenuStyle::RemoveClientFromWatch(int client)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
|
logger->LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
|
||||||
#endif
|
#endif
|
||||||
m_WatchList.remove(client);
|
m_WatchList.remove(client);
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ void BaseMenuStyle::RemoveClientFromWatch(int client)
|
|||||||
void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
|
void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
|
logger->LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
menu_states_t &states = player->states;
|
menu_states_t &states = player->states;
|
||||||
@ -115,7 +115,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool
|
|||||||
void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
|
logger->LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
|
||||||
#endif
|
#endif
|
||||||
int maxClients = g_Players.GetMaxClients();
|
int maxClients = g_Players.GetMaxClients();
|
||||||
for (int i=1; i<=maxClients; i++)
|
for (int i=1; i<=maxClients; i++)
|
||||||
@ -135,7 +135,7 @@ void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
|||||||
bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
|
bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
|
logger->LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
|
||||||
#endif
|
#endif
|
||||||
if (client < 1 || client > g_Players.MaxClients())
|
if (client < 1 || client > g_Players.MaxClients())
|
||||||
{
|
{
|
||||||
@ -191,7 +191,7 @@ MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
|
|||||||
void BaseMenuStyle::OnClientDisconnected(int client)
|
void BaseMenuStyle::OnClientDisconnected(int client)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
|
logger->LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
if (!player->bInMenu)
|
if (!player->bInMenu)
|
||||||
@ -214,7 +214,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_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_Size,
|
||||||
m_WatchList.m_FirstLink,
|
m_WatchList.m_FirstLink,
|
||||||
m_WatchList.m_FreeNodes,
|
m_WatchList.m_FreeNodes,
|
||||||
@ -232,7 +232,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
if (total)
|
if (total)
|
||||||
{
|
{
|
||||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
|
logger->LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
client = do_lookup[i];
|
client = do_lookup[i];
|
||||||
player = GetMenuPlayer(client);
|
player = GetMenuPlayer(client);
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
|
logger->LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
|
||||||
client,
|
client,
|
||||||
player->bInMenu,
|
player->bInMenu,
|
||||||
player->menuHoldTime,
|
player->menuHoldTime,
|
||||||
@ -254,7 +254,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
if (!player->bInMenu || !player->menuHoldTime)
|
if (!player->bInMenu || !player->menuHoldTime)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
|
logger->LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
|
||||||
#endif
|
#endif
|
||||||
m_WatchList.remove(client);
|
m_WatchList.remove(client);
|
||||||
continue;
|
continue;
|
||||||
@ -269,7 +269,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
|
logger->LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
|
|
||||||
@ -412,7 +412,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
|||||||
bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
|
bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
|
logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
|
||||||
client,
|
client,
|
||||||
menu,
|
menu,
|
||||||
mh,
|
mh,
|
||||||
@ -475,7 +475,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
unsigned int time)
|
unsigned int time)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
|
logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
|
||||||
client,
|
client,
|
||||||
menu,
|
menu,
|
||||||
mh,
|
mh,
|
||||||
@ -487,7 +487,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
|
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
||||||
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
||||||
@ -498,7 +498,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (player->bAutoIgnore)
|
if (player->bAutoIgnore)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
|
||||||
#endif
|
#endif
|
||||||
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
||||||
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
||||||
@ -517,7 +517,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (player->bInMenu)
|
if (player->bInMenu)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
_CancelClientMenu(client, MenuCancel_Interrupted, true);
|
_CancelClientMenu(client, MenuCancel_Interrupted, true);
|
||||||
}
|
}
|
||||||
@ -532,7 +532,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (!display)
|
if (!display)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
player->bAutoIgnore = false;
|
player->bAutoIgnore = false;
|
||||||
player->bInMenu = false;
|
player->bInMenu = false;
|
||||||
@ -562,7 +562,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
player->bAutoIgnore = false;
|
player->bAutoIgnore = false;
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -571,7 +571,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
|
logger->LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
menu_states_t &states = player->states;
|
menu_states_t &states = player->states;
|
||||||
@ -581,7 +581,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
|||||||
if (!display)
|
if (!display)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
|
logger->LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
|
||||||
#endif
|
#endif
|
||||||
if (player->menuHoldTime)
|
if (player->menuHoldTime)
|
||||||
{
|
{
|
||||||
@ -598,7 +598,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
|||||||
player->bAutoIgnore = false;
|
player->bAutoIgnore = false;
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
|
logger->LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -628,49 +628,49 @@ Handle_t CBaseMenu::GetHandle()
|
|||||||
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
||||||
{
|
{
|
||||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
||||||
&& m_items.length() >= m_pStyle->GetMaxPageItems())
|
&& m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CItem item(m_items.length());
|
CItem item(m_items.size());
|
||||||
|
|
||||||
item.info = info;
|
item.info = info;
|
||||||
if (draw.display)
|
if (draw.display)
|
||||||
item.display = new ke::AString(draw.display);
|
item.display = std::make_unique<std::string>(draw.display);
|
||||||
item.style = draw.style;
|
item.style = draw.style;
|
||||||
|
|
||||||
m_items.append(ke::Move(item));
|
m_items.push_back(std::move(item));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
||||||
{
|
{
|
||||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
|
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
|
||||||
m_items.length() >= m_pStyle->GetMaxPageItems())
|
m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position >= m_items.length())
|
if (position >= m_items.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CItem item(position);
|
CItem item(position);
|
||||||
item.info = info;
|
item.info = info;
|
||||||
if (draw.display)
|
if (draw.display)
|
||||||
item.display = new ke::AString(draw.display);
|
item.display = std::make_unique<std::string>(draw.display);
|
||||||
item.style = draw.style;
|
item.style = draw.style;
|
||||||
|
|
||||||
m_items.insert(position, ke::Move(item));
|
m_items.emplace(m_items.begin() + position, std::move(item));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::RemoveItem(unsigned int position)
|
bool CBaseMenu::RemoveItem(unsigned int position)
|
||||||
{
|
{
|
||||||
if (position >= m_items.length())
|
if (position >= m_items.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_items.remove(position);
|
m_items.erase(m_items.begin() + position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,21 +681,21 @@ void CBaseMenu::RemoveAllItems()
|
|||||||
|
|
||||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
|
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
|
||||||
{
|
{
|
||||||
if (position >= m_items.length())
|
if (position >= m_items.size())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (client > 0 && position < m_RandomMaps[client].length())
|
if (client > 0 && position < m_RandomMaps[client].size())
|
||||||
{
|
{
|
||||||
position = m_RandomMaps[client][position];
|
position = m_RandomMaps[client][position];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draw)
|
if (draw)
|
||||||
{
|
{
|
||||||
draw->display = m_items[position].display->chars();
|
draw->display = m_items[position].display->c_str();
|
||||||
draw->style = m_items[position].style;
|
draw->style = m_items[position].style;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_items[position].info.chars();
|
return m_items[position].info.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBaseMenu::ShufflePerClient(int start, int stop)
|
void CBaseMenu::ShufflePerClient(int start, int stop)
|
||||||
@ -705,7 +705,7 @@ void CBaseMenu::ShufflePerClient(int start, int stop)
|
|||||||
if (stop >= 0)
|
if (stop >= 0)
|
||||||
length = MIN(length, stop);
|
length = MIN(length, stop);
|
||||||
|
|
||||||
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
|
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
// populate per-client map ...
|
// populate per-client map ...
|
||||||
m_RandomMaps[i].resize(length);
|
m_RandomMaps[i].resize(length);
|
||||||
@ -735,9 +735,9 @@ void CBaseMenu::SetClientMapping(int client, int *array, int length)
|
|||||||
|
|
||||||
bool CBaseMenu::IsPerClientShuffled()
|
bool CBaseMenu::IsPerClientShuffled()
|
||||||
{
|
{
|
||||||
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
|
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if(m_RandomMaps[i].length() > 0)
|
if(m_RandomMaps[i].size() > 0)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -745,7 +745,7 @@ bool CBaseMenu::IsPerClientShuffled()
|
|||||||
|
|
||||||
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
||||||
{
|
{
|
||||||
if (client > 0 && position < m_RandomMaps[client].length())
|
if (client > 0 && position < m_RandomMaps[client].size())
|
||||||
{
|
{
|
||||||
position = m_RandomMaps[client][position];
|
position = m_RandomMaps[client][position];
|
||||||
return m_items[position].index;
|
return m_items[position].index;
|
||||||
@ -756,7 +756,7 @@ unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
|||||||
|
|
||||||
unsigned int CBaseMenu::GetItemCount()
|
unsigned int CBaseMenu::GetItemCount()
|
||||||
{
|
{
|
||||||
return m_items.length();
|
return m_items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
||||||
@ -794,7 +794,7 @@ void CBaseMenu::SetDefaultTitle(const char *message)
|
|||||||
|
|
||||||
const char *CBaseMenu::GetDefaultTitle()
|
const char *CBaseMenu::GetDefaultTitle()
|
||||||
{
|
{
|
||||||
return m_Title.chars();
|
return m_Title.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBaseMenu::Cancel()
|
void CBaseMenu::Cancel()
|
||||||
@ -805,7 +805,7 @@ void CBaseMenu::Cancel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
logger->LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
||||||
this,
|
this,
|
||||||
m_bShouldDelete);
|
m_bShouldDelete);
|
||||||
#endif
|
#endif
|
||||||
@ -829,7 +829,7 @@ void CBaseMenu::Destroy(bool releaseHandle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
|
logger->LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
|
||||||
this,
|
this,
|
||||||
releaseHandle,
|
releaseHandle,
|
||||||
m_bCancelling,
|
m_bCancelling,
|
||||||
@ -886,5 +886,5 @@ IMenuHandler *CBaseMenu::GetHandler()
|
|||||||
|
|
||||||
unsigned int CBaseMenu::GetBaseMemUsage()
|
unsigned int CBaseMenu::GetBaseMemUsage()
|
||||||
{
|
{
|
||||||
return m_Title.length() + (m_items.length() * sizeof(CItem));
|
return m_Title.size() + (m_items.size() * sizeof(CItem));
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,11 @@
|
|||||||
#ifndef _INCLUDE_MENUSTYLE_BASE_H
|
#ifndef _INCLUDE_MENUSTYLE_BASE_H
|
||||||
#define _INCLUDE_MENUSTYLE_BASE_H
|
#define _INCLUDE_MENUSTYLE_BASE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <IMenuManager.h>
|
#include <IMenuManager.h>
|
||||||
#include <IPlayerHelpers.h>
|
#include <IPlayerHelpers.h>
|
||||||
#include <am-autoptr.h>
|
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include "sm_fastlink.h"
|
#include "sm_fastlink.h"
|
||||||
@ -51,8 +53,8 @@ public:
|
|||||||
access = 0;
|
access = 0;
|
||||||
}
|
}
|
||||||
CItem(CItem &&other)
|
CItem(CItem &&other)
|
||||||
: info(ke::Move(other.info)),
|
: info(std::move(other.info)),
|
||||||
display(ke::Move(other.display))
|
display(std::move(other.display))
|
||||||
{
|
{
|
||||||
index = other.index;
|
index = other.index;
|
||||||
style = other.style;
|
style = other.style;
|
||||||
@ -61,8 +63,8 @@ public:
|
|||||||
CItem & operator =(CItem &&other)
|
CItem & operator =(CItem &&other)
|
||||||
{
|
{
|
||||||
index = other.index;
|
index = other.index;
|
||||||
info = ke::Move(other.info);
|
info = std::move(other.info);
|
||||||
display = ke::Move(other.display);
|
display = std::move(other.display);
|
||||||
style = other.style;
|
style = other.style;
|
||||||
access = other.access;
|
access = other.access;
|
||||||
return *this;
|
return *this;
|
||||||
@ -70,8 +72,8 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
ke::AString info;
|
std::string info;
|
||||||
ke::AutoPtr<ke::AString> display;
|
std::unique_ptr<std::string> display;
|
||||||
unsigned int style;
|
unsigned int style;
|
||||||
unsigned int access;
|
unsigned int access;
|
||||||
|
|
||||||
@ -164,10 +166,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
void InternalDelete();
|
void InternalDelete();
|
||||||
protected:
|
protected:
|
||||||
ke::AString m_Title;
|
std::string m_Title;
|
||||||
IMenuStyle *m_pStyle;
|
IMenuStyle *m_pStyle;
|
||||||
unsigned int m_Pagination;
|
unsigned int m_Pagination;
|
||||||
ke::Vector<CItem> m_items;
|
std::vector<CItem> m_items;
|
||||||
bool m_bShouldDelete;
|
bool m_bShouldDelete;
|
||||||
bool m_bCancelling;
|
bool m_bCancelling;
|
||||||
IdentityToken_t *m_pOwner;
|
IdentityToken_t *m_pOwner;
|
||||||
@ -176,7 +178,7 @@ protected:
|
|||||||
Handle_t m_hHandle;
|
Handle_t m_hHandle;
|
||||||
IMenuHandler *m_pHandler;
|
IMenuHandler *m_pHandler;
|
||||||
unsigned int m_nFlags;
|
unsigned int m_nFlags;
|
||||||
ke::Vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
|
std::vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_MENUSTYLE_BASE_H
|
#endif //_INCLUDE_MENUSTYLE_BASE_H
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include <IGameConfigs.h>
|
#include <IGameConfigs.h>
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
#include "Logger.h"
|
#include <bridge/include/ILogger.h>
|
||||||
#endif
|
#endif
|
||||||
#include "logic_bridge.h"
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
@ -45,6 +45,8 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
|
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
#include <game/shared/berimbau/protobuf/berimbau_usermessages.pb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const char *g_RadioNumTable[];
|
extern const char *g_RadioNumTable[];
|
||||||
@ -59,7 +61,7 @@ unsigned int g_RadioMenuTimeout = 0;
|
|||||||
#define MAX_MENUSLOT_KEYS 10
|
#define MAX_MENUSLOT_KEYS 10
|
||||||
|
|
||||||
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
||||||
|
static bool s_RadioClosesOnInvalidSlot = false;
|
||||||
|
|
||||||
CRadioStyle::CRadioStyle()
|
CRadioStyle::CRadioStyle()
|
||||||
{
|
{
|
||||||
@ -122,6 +124,12 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *closes = g_pGameConf->GetKeyValue("RadioMenuClosesOnInvalidSlot");
|
||||||
|
if (closes != nullptr && strcmp(closes, "yes") == 0)
|
||||||
|
{
|
||||||
|
s_RadioClosesOnInvalidSlot = true;
|
||||||
|
}
|
||||||
|
|
||||||
g_Menus.SetDefaultStyle(this);
|
g_Menus.SetDefaultStyle(this);
|
||||||
|
|
||||||
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
|
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
|
||||||
@ -174,7 +182,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
|
|||||||
{
|
{
|
||||||
int count = pFilter->GetRecipientCount();
|
int count = pFilter->GetRecipientCount();
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||||
#else
|
#else
|
||||||
bf_read br(bf->GetBasePointer(), 3);
|
bf_read br(bf->GetBasePointer(), 3);
|
||||||
@ -197,7 +205,7 @@ void CRadioStyle::OnUserMessageSent(int msg_id)
|
|||||||
{
|
{
|
||||||
int client = g_last_clients[i];
|
int client = g_last_clients[i];
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
logger->LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
||||||
client,
|
client,
|
||||||
m_players[client].bInExternMenu);
|
m_players[client].bInExternMenu);
|
||||||
#endif
|
#endif
|
||||||
@ -462,7 +470,16 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
|||||||
sizeof(display_pkt),
|
sizeof(display_pkt),
|
||||||
text);
|
text);
|
||||||
}
|
}
|
||||||
display_keys = keys;
|
|
||||||
|
// Some games have implemented CHudMenu::SelectMenuItem to close the menu
|
||||||
|
// even if an invalid slot has been selected, which causes us a problem as
|
||||||
|
// we'll never get any notification from the client and we'll keep the menu
|
||||||
|
// alive on our end indefinitely. For these games, pretend that every slot
|
||||||
|
// is valid for selection so we're guaranteed to get a menuselect command.
|
||||||
|
// We don't want to do this for every game as the common SelectMenuItem
|
||||||
|
// implementation ignores invalid selections and keeps the menu open, which
|
||||||
|
// is a much nicer user experience.
|
||||||
|
display_keys = s_RadioClosesOnInvalidSlot ? 0x7ff : keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRadioMenuPlayer::Radio_Refresh()
|
void CRadioMenuPlayer::Radio_Refresh()
|
||||||
@ -483,9 +500,13 @@ void CRadioMenuPlayer::Radio_Refresh()
|
|||||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
// TODO: find what happens past 240 on CS:GO
|
// TODO: find what happens past 240 on CS:GO
|
||||||
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
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_bits_valid_slots(display_keys);
|
||||||
msg->set_display_time(time);
|
msg->set_display_time(time);
|
||||||
msg->set_menu_string(ptr);
|
msg->set_menu_string(ptr);
|
||||||
@ -576,7 +597,7 @@ bool CRadioMenu::DisplayAtItem(int client,
|
|||||||
IMenuHandler *alt_handler)
|
IMenuHandler *alt_handler)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
logger->LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
||||||
this,
|
this,
|
||||||
client,
|
client,
|
||||||
time);
|
time);
|
||||||
|
@ -63,11 +63,7 @@ bool g_forcedChange = false;
|
|||||||
|
|
||||||
void NextMapManager::OnSourceModAllInitialized_Post()
|
void NextMapManager::OnSourceModAllInitialized_Post()
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#else
|
|
||||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ConCommand *pCmd = FindCommand("changelevel");
|
ConCommand *pCmd = FindCommand("changelevel");
|
||||||
if (pCmd != NULL)
|
if (pCmd != NULL)
|
||||||
@ -79,11 +75,7 @@ void NextMapManager::OnSourceModAllInitialized_Post()
|
|||||||
|
|
||||||
void NextMapManager::OnSourceModShutdown()
|
void NextMapManager::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#else
|
|
||||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (changeLevelCmd != NULL)
|
if (changeLevelCmd != NULL)
|
||||||
{
|
{
|
||||||
|
@ -97,7 +97,7 @@ SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, cons
|
|||||||
|
|
||||||
static void PrintfBuffer_FrameAction(void *data)
|
static void PrintfBuffer_FrameAction(void *data)
|
||||||
{
|
{
|
||||||
g_Players.OnPrintfFrameAction(reinterpret_cast<unsigned int>(data));
|
g_Players.OnPrintfFrameAction(static_cast<unsigned int>(reinterpret_cast<uintptr_t>(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConCommand *maxplayersCmd = NULL;
|
ConCommand *maxplayersCmd = NULL;
|
||||||
@ -196,6 +196,7 @@ void PlayerManager::OnSourceModAllInitialized()
|
|||||||
m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
|
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_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
|
||||||
m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
|
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_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
|
||||||
m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL);
|
m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL);
|
||||||
|
|
||||||
@ -249,6 +250,7 @@ void PlayerManager::OnSourceModShutdown()
|
|||||||
forwardsys->ReleaseForward(m_clcommandkv_post);
|
forwardsys->ReleaseForward(m_clcommandkv_post);
|
||||||
forwardsys->ReleaseForward(m_clinfochanged);
|
forwardsys->ReleaseForward(m_clinfochanged);
|
||||||
forwardsys->ReleaseForward(m_clauth);
|
forwardsys->ReleaseForward(m_clauth);
|
||||||
|
forwardsys->ReleaseForward(m_cllang);
|
||||||
forwardsys->ReleaseForward(m_onActivate);
|
forwardsys->ReleaseForward(m_onActivate);
|
||||||
forwardsys->ReleaseForward(m_onActivate2);
|
forwardsys->ReleaseForward(m_onActivate2);
|
||||||
|
|
||||||
@ -410,7 +412,7 @@ void PlayerManager::RunAuthChecks()
|
|||||||
pPlayer = &m_Players[m_AuthQueue[i]];
|
pPlayer = &m_Players[m_AuthQueue[i]];
|
||||||
pPlayer->UpdateAuthIds();
|
pPlayer->UpdateAuthIds();
|
||||||
|
|
||||||
authstr = pPlayer->m_AuthID.chars();
|
authstr = pPlayer->m_AuthID.c_str();
|
||||||
|
|
||||||
if (!pPlayer->IsAuthStringValidated())
|
if (!pPlayer->IsAuthStringValidated())
|
||||||
{
|
{
|
||||||
@ -517,7 +519,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
|||||||
/* Get the client's language */
|
/* Get the client's language */
|
||||||
if (m_QueryLang)
|
if (m_QueryLang)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
pPlayer->m_LangId = translator->GetServerLanguage();
|
pPlayer->m_LangId = translator->GetServerLanguage();
|
||||||
#else
|
#else
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -525,6 +527,8 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
|||||||
{
|
{
|
||||||
unsigned int langid;
|
unsigned int langid;
|
||||||
pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage();
|
pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage();
|
||||||
|
|
||||||
|
OnClientLanguageChanged(client, pPlayer->m_LangId);
|
||||||
} else {
|
} else {
|
||||||
pPlayer->m_LangId = translator->GetServerLanguage();
|
pPlayer->m_LangId = translator->GetServerLanguage();
|
||||||
}
|
}
|
||||||
@ -671,6 +675,8 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
|||||||
&& (m_SourceTVUserId == userId
|
&& (m_SourceTVUserId == userId
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
|| strcmp(playername, "GOTV") == 0
|
|| 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 \
|
#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_LEFT4DEAD2)
|
||||||
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
|
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
|
||||||
@ -714,19 +720,19 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
|||||||
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
|
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
|
||||||
{
|
{
|
||||||
pListener = (*iter);
|
pListener = (*iter);
|
||||||
pListener->OnClientAuthorized(client, steamId ? steamId : pPlayer->m_AuthID.chars());
|
pListener->OnClientAuthorized(client, steamId ? steamId : pPlayer->m_AuthID.c_str());
|
||||||
}
|
}
|
||||||
/* Finally, tell plugins */
|
/* Finally, tell plugins */
|
||||||
if (m_clauth->GetFunctionCount())
|
if (m_clauth->GetFunctionCount())
|
||||||
{
|
{
|
||||||
m_clauth->PushCell(client);
|
m_clauth->PushCell(client);
|
||||||
/* For legacy reasons, people are expecting the Steam2 id here if using Steam auth */
|
/* For legacy reasons, people are expecting the Steam2 id here if using Steam auth */
|
||||||
m_clauth->PushString(steamId ? steamId : pPlayer->m_AuthID.chars());
|
m_clauth->PushString(steamId ? steamId : pPlayer->m_AuthID.c_str());
|
||||||
m_clauth->Execute(NULL);
|
m_clauth->Execute(NULL);
|
||||||
}
|
}
|
||||||
pPlayer->Authorize_Post();
|
pPlayer->Authorize_Post();
|
||||||
}
|
}
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
else if(m_QueryLang)
|
else if(m_QueryLang)
|
||||||
{
|
{
|
||||||
// Not a bot
|
// Not a bot
|
||||||
@ -786,7 +792,7 @@ void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
|
|||||||
CPlayer *pPlayer = &m_Players[i];
|
CPlayer *pPlayer = &m_Players[i];
|
||||||
if (pPlayer->IsConnected() && pPlayer->IsFakeClient())
|
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
|
||||||
// These games have the bug fixed where hltv/replay was getting kicked on hibernation
|
// These games have the bug fixed where hltv/replay was getting kicked on hibernation
|
||||||
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
|
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
|
||||||
continue;
|
continue;
|
||||||
@ -873,7 +879,7 @@ void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
|
|||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
|
|
||||||
size_t nMsgLen = strlen(szMsg);
|
size_t nMsgLen = strlen(szMsg);
|
||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE || SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
static const int nNumBitsWritten = 0;
|
static const int nNumBitsWritten = 0;
|
||||||
#else
|
#else
|
||||||
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
||||||
@ -891,7 +897,7 @@ void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
|
|||||||
if (player.m_PrintfBuffer.empty())
|
if (player.m_PrintfBuffer.empty())
|
||||||
g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
|
g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
|
||||||
|
|
||||||
player.m_PrintfBuffer.append(szMsg);
|
player.m_PrintfBuffer.push_back(szMsg);
|
||||||
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
@ -918,21 +924,21 @@ void PlayerManager::OnPrintfFrameAction(unsigned int serial)
|
|||||||
|
|
||||||
while (!player.m_PrintfBuffer.empty())
|
while (!player.m_PrintfBuffer.empty())
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE || SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
static const int nNumBitsWritten = 0;
|
static const int nNumBitsWritten = 0;
|
||||||
#else
|
#else
|
||||||
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ke::AString &string = player.m_PrintfBuffer.front();
|
std::string &string = player.m_PrintfBuffer.front();
|
||||||
|
|
||||||
// stop if we'd overflow the SVC_Print buffer (+7 as ceil)
|
// stop if we'd overflow the SVC_Print buffer (+7 as ceil)
|
||||||
if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize)
|
if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.chars());
|
SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.c_str());
|
||||||
|
|
||||||
player.m_PrintfBuffer.popFront();
|
player.m_PrintfBuffer.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.m_PrintfBuffer.empty())
|
if (!player.m_PrintfBuffer.empty())
|
||||||
@ -1161,14 +1167,18 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
|||||||
}
|
}
|
||||||
else if (args.ArgC() > 1 && strcmp(args.Arg(1), "credits") == 0)
|
else if (args.ArgC() > 1 && strcmp(args.Arg(1), "credits") == 0)
|
||||||
{
|
{
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
"SourceMod would not be possible without:");
|
"SourceMod would not be possible without:");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" David \"BAILOPAN\" Anderson, Matt \"pRED\" Woodrow");
|
" David \"BAILOPAN\" Anderson, Matt \"pRED\" Woodrow");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" Scott \"DS\" Ehlert, Fyren");
|
" Scott \"DS\" Ehlert, Fyren");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" Nicholas \"psychonic\" Hastings, Asher \"asherkin\" Baker");
|
" Nicholas \"psychonic\" Hastings, Asher \"asherkin\" Baker");
|
||||||
|
ClientConsolePrint(pEntity,
|
||||||
|
" Ruben \"Dr!fter\" Gonzalez, Josh \"KyleS\" Allard");
|
||||||
|
ClientConsolePrint(pEntity,
|
||||||
|
" Michael \"Headline\" Flaherty, Jannik \"Peace-Maker\" Hartung");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" Borja \"faluco\" Ferrer, Pavol \"PM OnoTo\" Marko");
|
" Borja \"faluco\" Ferrer, Pavol \"PM OnoTo\" Marko");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
@ -1183,7 +1193,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
|||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
"To see credits, type \"sm credits\"");
|
"To see credits, type \"sm credits\"");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
"Visit http://www.sourcemod.net/");
|
"Visit https://www.sourcemod.net/");
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1338,65 +1348,69 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
|||||||
m_clinfochanged->PushCell(client);
|
m_clinfochanged->PushCell(client);
|
||||||
m_clinfochanged->Execute(&res, NULL);
|
m_clinfochanged->Execute(&res, NULL);
|
||||||
|
|
||||||
if (pPlayer->IsFakeClient())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPlayerInfo *info = pPlayer->GetPlayerInfo();
|
IPlayerInfo *info = pPlayer->GetPlayerInfo();
|
||||||
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
|
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
|
||||||
const char *old_name = pPlayer->m_Name.c_str();
|
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)
|
if (strcmp(old_name, new_name) != 0)
|
||||||
{
|
{
|
||||||
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
|
if (!pPlayer->IsFakeClient())
|
||||||
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
|
||||||
{
|
{
|
||||||
if (!CheckSetAdminName(client, pPlayer, id))
|
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
|
||||||
|
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
||||||
{
|
{
|
||||||
char kickMsg[128];
|
if (!CheckSetAdminName(client, pPlayer, id))
|
||||||
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
|
{
|
||||||
pPlayer->Kick(kickMsg);
|
char kickMsg[128];
|
||||||
RETURN_META(MRES_IGNORED);
|
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) {
|
else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
|
||||||
if (id == pPlayer->GetAdminId())
|
if (id == pPlayer->GetAdminId())
|
||||||
{
|
{
|
||||||
/* This player is changing their name; force them to drop admin privileges! */
|
/* This player is changing their name; force them to drop admin privileges! */
|
||||||
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pPlayer->SetName(new_name);
|
pPlayer->SetName(new_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_PassInfoVar.size() > 0)
|
if (!pPlayer->IsFakeClient())
|
||||||
{
|
{
|
||||||
/* Try for a password change */
|
if (m_PassInfoVar.size() > 0)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
pPlayer->m_LastPassword.assign(new_pass);
|
/* Try for a password change */
|
||||||
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
|
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->m_LastPassword.assign(new_pass);
|
||||||
pPlayer->DoBasicAdminChecks();
|
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 */
|
/* Notify Extensions */
|
||||||
List<IClientListener *>::iterator iter;
|
List<IClientListener *>::iterator iter;
|
||||||
IClientListener *pListener = NULL;
|
IClientListener *pListener = NULL;
|
||||||
@ -1410,6 +1424,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()
|
int PlayerManager::GetMaxClients()
|
||||||
{
|
{
|
||||||
return m_maxClients;
|
return m_maxClients;
|
||||||
@ -1575,7 +1596,10 @@ void PlayerManager::InvalidatePlayer(CPlayer *pPlayer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_UserIdLookUp[engine->GetPlayerUserId(pPlayer->m_pEdict)] = 0;
|
auto userid = engine->GetPlayerUserId(pPlayer->m_pEdict);
|
||||||
|
if (userid != -1)
|
||||||
|
m_UserIdLookUp[userid] = 0;
|
||||||
|
|
||||||
pPlayer->Disconnect();
|
pPlayer->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2011,7 +2035,7 @@ void CmdMaxplayersCallback()
|
|||||||
g_Players.MaxPlayersChanged();
|
g_Players.MaxPlayersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= m_maxClients; i++)
|
for (int i = 1; i <= m_maxClients; i++)
|
||||||
@ -2019,7 +2043,9 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
|
|||||||
if (m_Players[i].m_LanguageCookie == cookie)
|
if (m_Players[i].m_LanguageCookie == cookie)
|
||||||
{
|
{
|
||||||
unsigned int langid;
|
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;
|
||||||
|
OnClientLanguageChanged(i, new_langid);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2088,7 +2114,8 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|
|||||||
|| SOURCE_ENGINE == SE_HL2DM \
|
|| SOURCE_ENGINE == SE_HL2DM \
|
||||||
|| SOURCE_ENGINE == SE_BMS \
|
|| SOURCE_ENGINE == SE_BMS \
|
||||||
|| SOURCE_ENGINE == SE_INSURGENCY \
|
|| SOURCE_ENGINE == SE_INSURGENCY \
|
||||||
|| SOURCE_ENGINE == SE_DOI
|
|| SOURCE_ENGINE == SE_DOI \
|
||||||
|
|| SOURCE_ENGINE == SE_BLADE
|
||||||
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
|
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
|
||||||
#else
|
#else
|
||||||
#if SOURCE_ENGINE == SE_SDK2013
|
#if SOURCE_ENGINE == SE_SDK2013
|
||||||
@ -2264,7 +2291,7 @@ void CPlayer::Disconnect()
|
|||||||
m_bIsSourceTV = false;
|
m_bIsSourceTV = false;
|
||||||
m_bIsReplay = false;
|
m_bIsReplay = false;
|
||||||
m_Serial.value = -1;
|
m_Serial.value = -1;
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
m_LanguageCookie = InvalidQueryCvarCookie;
|
m_LanguageCookie = InvalidQueryCvarCookie;
|
||||||
#endif
|
#endif
|
||||||
ClearNetchannelQueue();
|
ClearNetchannelQueue();
|
||||||
@ -2273,7 +2300,7 @@ void CPlayer::Disconnect()
|
|||||||
void CPlayer::ClearNetchannelQueue(void)
|
void CPlayer::ClearNetchannelQueue(void)
|
||||||
{
|
{
|
||||||
while (!m_PrintfBuffer.empty())
|
while (!m_PrintfBuffer.empty())
|
||||||
m_PrintfBuffer.popFront();
|
m_PrintfBuffer.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayer::SetName(const char *name)
|
void CPlayer::SetName(const char *name)
|
||||||
@ -2306,11 +2333,6 @@ void CPlayer::SetName(const char *name)
|
|||||||
|
|
||||||
const char *CPlayer::GetName()
|
const char *CPlayer::GetName()
|
||||||
{
|
{
|
||||||
if (m_Info && m_pEdict->GetUnknown())
|
|
||||||
{
|
|
||||||
return m_Info->GetName();
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Name.c_str();
|
return m_Name.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2326,7 +2348,7 @@ const char *CPlayer::GetAuthString(bool validated)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_AuthID.chars();
|
return m_AuthID.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSteamID &CPlayer::GetSteamId(bool validated)
|
const CSteamID &CPlayer::GetSteamId(bool validated)
|
||||||
@ -2347,7 +2369,7 @@ const char *CPlayer::GetSteam2Id(bool validated)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_Steam2Id.chars();
|
return m_Steam2Id.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CPlayer::GetSteam3Id(bool validated)
|
const char *CPlayer::GetSteam3Id(bool validated)
|
||||||
@ -2357,14 +2379,14 @@ const char *CPlayer::GetSteam3Id(bool validated)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_Steam3Id.chars();
|
return m_Steam3Id.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CPlayer::GetSteamAccountID(bool validated)
|
unsigned int CPlayer::GetSteamAccountID(bool validated)
|
||||||
{
|
{
|
||||||
if (!IsFakeClient() && (!validated || IsAuthStringValidated()))
|
if (!IsFakeClient() && (!validated || IsAuthStringValidated()))
|
||||||
{
|
{
|
||||||
const CSteamID &id = GetSteamId();
|
const CSteamID &id = GetSteamId(validated);
|
||||||
if (id.IsValid())
|
if (id.IsValid())
|
||||||
return id.GetAccountID();
|
return id.GetAccountID();
|
||||||
}
|
}
|
||||||
@ -2491,7 +2513,7 @@ void CPlayer::Kick(const char *str)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
pClient->Disconnect(str);
|
pClient->Disconnect(str);
|
||||||
#else
|
#else
|
||||||
pClient->Disconnect("%s", str);
|
pClient->Disconnect("%s", str);
|
||||||
@ -2624,7 +2646,7 @@ void CPlayer::DoBasicAdminChecks()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check steam id */
|
/* Check steam id */
|
||||||
if ((id = adminsys->FindAdminByIdentity("steam", m_AuthID.chars())) != INVALID_ADMIN_ID)
|
if ((id = adminsys->FindAdminByIdentity("steam", m_AuthID.c_str())) != INVALID_ADMIN_ID)
|
||||||
{
|
{
|
||||||
if (g_Players.CheckSetAdmin(client, this, id))
|
if (g_Players.CheckSetAdmin(client, this, id))
|
||||||
{
|
{
|
||||||
@ -2640,7 +2662,11 @@ unsigned int CPlayer::GetLanguageId()
|
|||||||
|
|
||||||
void CPlayer::SetLanguageId(unsigned int id)
|
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()
|
int CPlayer::GetUserId()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sts=8 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
|
||||||
@ -133,9 +133,9 @@ private:
|
|||||||
String m_Name;
|
String m_Name;
|
||||||
String m_Ip;
|
String m_Ip;
|
||||||
String m_IpNoPort;
|
String m_IpNoPort;
|
||||||
ke::AString m_AuthID;
|
std::string m_AuthID;
|
||||||
ke::AString m_Steam2Id;
|
std::string m_Steam2Id;
|
||||||
ke::AString m_Steam3Id;
|
std::string m_Steam3Id;
|
||||||
AdminId m_Admin = INVALID_ADMIN_ID;
|
AdminId m_Admin = INVALID_ADMIN_ID;
|
||||||
bool m_TempAdmin = false;
|
bool m_TempAdmin = false;
|
||||||
edict_t *m_pEdict = nullptr;
|
edict_t *m_pEdict = nullptr;
|
||||||
@ -151,10 +151,10 @@ private:
|
|||||||
bool m_bIsReplay = false;
|
bool m_bIsReplay = false;
|
||||||
serial_t m_Serial;
|
serial_t m_Serial;
|
||||||
CSteamID m_SteamId;
|
CSteamID m_SteamId;
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
||||||
#endif
|
#endif
|
||||||
ke::Deque<ke::AString> m_PrintfBuffer;
|
std::deque<std::string> m_PrintfBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerManager :
|
class PlayerManager :
|
||||||
@ -193,6 +193,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
void OnClientSettingsChanged(edict_t *pEntity);
|
void OnClientSettingsChanged(edict_t *pEntity);
|
||||||
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
||||||
|
void OnClientLanguageChanged(int client, unsigned int language);
|
||||||
void OnServerHibernationUpdate(bool bHibernating);
|
void OnServerHibernationUpdate(bool bHibernating);
|
||||||
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
||||||
void OnPrintfFrameAction(unsigned int serial);
|
void OnPrintfFrameAction(unsigned int serial);
|
||||||
@ -216,6 +217,9 @@ public: //IPlayerManager
|
|||||||
void RecheckAnyAdmins();
|
void RecheckAnyAdmins();
|
||||||
public: // IGameEventListener2
|
public: // IGameEventListener2
|
||||||
void FireGameEvent(IGameEvent *pEvent);
|
void FireGameEvent(IGameEvent *pEvent);
|
||||||
|
#if SOURCE_ENGINE >= SE_ALIENSWARM
|
||||||
|
virtual int GetEventDebugID( void ) { return 42; }
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
inline int MaxClients()
|
inline int MaxClients()
|
||||||
{
|
{
|
||||||
@ -239,7 +243,7 @@ public:
|
|||||||
{
|
{
|
||||||
return m_bInCCKVHook;
|
return m_bInCCKVHook;
|
||||||
}
|
}
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
||||||
#endif
|
#endif
|
||||||
private:
|
private:
|
||||||
@ -257,6 +261,7 @@ private:
|
|||||||
IForward *m_clcommandkv_post;
|
IForward *m_clcommandkv_post;
|
||||||
IForward *m_clinfochanged;
|
IForward *m_clinfochanged;
|
||||||
IForward *m_clauth;
|
IForward *m_clauth;
|
||||||
|
IForward *m_cllang;
|
||||||
IForward *m_onActivate;
|
IForward *m_onActivate;
|
||||||
IForward *m_onActivate2;
|
IForward *m_onActivate2;
|
||||||
CPlayer *m_Players;
|
CPlayer *m_Players;
|
||||||
|
@ -69,6 +69,13 @@ class DefaultMapTimer :
|
|||||||
public IConVarChangeListener
|
public IConVarChangeListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_BMS
|
||||||
|
static constexpr int kMapTimeScaleFactor = 60;
|
||||||
|
#else
|
||||||
|
static constexpr int kMapTimeScaleFactor = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
DefaultMapTimer()
|
DefaultMapTimer()
|
||||||
{
|
{
|
||||||
m_bInUse = false;
|
m_bInUse = false;
|
||||||
@ -81,7 +88,7 @@ public:
|
|||||||
|
|
||||||
int GetMapTimeLimit()
|
int GetMapTimeLimit()
|
||||||
{
|
{
|
||||||
return mp_timelimit->GetInt();
|
return (mp_timelimit->GetInt() / kMapTimeScaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMapTimerStatus(bool enabled)
|
void SetMapTimerStatus(bool enabled)
|
||||||
@ -105,7 +112,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extra_time /= 60;
|
extra_time /= (60 / kMapTimeScaleFactor);
|
||||||
|
|
||||||
mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
|
mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
|
||||||
}
|
}
|
||||||
@ -484,4 +491,3 @@ bool TimerSystem::GetMapTimeLeft(float *time_left)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,7 +816,7 @@ public:
|
|||||||
|
|
||||||
inline bool GetColor(const char *pszFieldName, Color *out)
|
inline bool GetColor(const char *pszFieldName, Color *out)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
@ -837,7 +837,7 @@ public:
|
|||||||
|
|
||||||
inline bool SetColor(const char *pszFieldName, const Color &value)
|
inline bool SetColor(const char *pszFieldName, const Color &value)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
@ -856,7 +856,7 @@ public:
|
|||||||
|
|
||||||
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
|
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
@ -878,7 +878,7 @@ public:
|
|||||||
|
|
||||||
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
|
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
@ -898,7 +898,7 @@ public:
|
|||||||
|
|
||||||
inline bool AddColor(const char *pszFieldName, const Color &value)
|
inline bool AddColor(const char *pszFieldName, const Color &value)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
|
@ -35,12 +35,14 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
#include <cstrike15_usermessage_helpers.h>
|
#include <cstrike15_usermessage_helpers.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
#include <berimbau_usermessage_helpers.h>
|
||||||
#endif
|
#endif
|
||||||
#include <amtl/am-string.h>
|
#include <amtl/am-string.h>
|
||||||
|
|
||||||
UserMessages g_UserMsgs;
|
UserMessages g_UserMsgs;
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||||
#else
|
#else
|
||||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
@ -49,7 +51,7 @@ SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRec
|
|||||||
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
||||||
#endif
|
#endif
|
||||||
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
||||||
#endif // ==SE_CSGO
|
#endif // ==SE_CSGO || ==SE_BLADE
|
||||||
|
|
||||||
UserMessages::UserMessages()
|
UserMessages::UserMessages()
|
||||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||||
@ -93,7 +95,7 @@ void UserMessages::OnSourceModAllShutdown()
|
|||||||
{
|
{
|
||||||
if (m_HookCount)
|
if (m_HookCount)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
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);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
#else
|
#else
|
||||||
@ -111,6 +113,8 @@ int UserMessages::GetMessageIndex(const char *msg)
|
|||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
// Can split this per engine and/or game later
|
// Can split this per engine and/or game later
|
||||||
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
return g_BerimbauUsermessageHelpers.GetIndex(msg);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int msgid;
|
int msgid;
|
||||||
@ -148,6 +152,8 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
|||||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msgid);
|
||||||
#endif
|
#endif
|
||||||
if (!pszName)
|
if (!pszName)
|
||||||
return false;
|
return false;
|
||||||
@ -297,7 +303,7 @@ bool UserMessages::EndMessage()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||||
{
|
{
|
||||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||||
@ -327,7 +333,7 @@ bool UserMessages::EndMessage()
|
|||||||
} else {
|
} else {
|
||||||
engine->MessageEnd();
|
engine->MessageEnd();
|
||||||
}
|
}
|
||||||
#endif // SE_CSGO
|
#endif // SE_CSGO || SE_BLADE
|
||||||
|
|
||||||
m_InExec = false;
|
m_InExec = false;
|
||||||
m_CurFlags = 0;
|
m_CurFlags = 0;
|
||||||
@ -412,7 +418,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
|||||||
|
|
||||||
if (!m_HookCount++)
|
if (!m_HookCount++)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
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);
|
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
#else
|
#else
|
||||||
@ -438,6 +444,8 @@ const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
|
|||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
return g_BerimbauUsermessageHelpers.GetPrototype(msg_type);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -487,7 +495,7 @@ void UserMessages::_DecRefCounter()
|
|||||||
{
|
{
|
||||||
if (--m_HookCount == 0)
|
if (--m_HookCount == 0)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
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);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
#else
|
#else
|
||||||
@ -499,12 +507,17 @@ void UserMessages::_DecRefCounter()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msg_type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
OnStartMessage_Pre(&filter, msg_type, pszName);
|
||||||
|
|
||||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||||
{
|
{
|
||||||
int size = msg.ByteSize();
|
int size = msg.ByteSize();
|
||||||
@ -517,9 +530,7 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
|
|||||||
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
OnStartMessage_Post(&filter, msg_type, pszName);
|
||||||
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OnMessageEnd_Pre();
|
OnMessageEnd_Pre();
|
||||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||||
@ -551,7 +562,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
|
|||||||
RETURN_META(res)
|
RETURN_META(res)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
@ -591,7 +602,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
|||||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
@ -756,7 +767,7 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
|
|
||||||
if (!handled && intercepted)
|
if (!handled && intercepted)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||||
#else
|
#else
|
||||||
bf_write *engine_bfw;
|
bf_write *engine_bfw;
|
||||||
@ -768,11 +779,11 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
||||||
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
||||||
ENGINE_CALL(MessageEnd)();
|
ENGINE_CALL(MessageEnd)();
|
||||||
#endif // SE_CSGO
|
#endif // SE_CSGO || SE_BLADE
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
int size = m_OrigBuffer->ByteSize();
|
int size = m_OrigBuffer->ByteSize();
|
||||||
uint8 *data = (uint8 *)stackalloc(size);
|
uint8 *data = (uint8 *)stackalloc(size);
|
||||||
m_OrigBuffer->SerializePartialToArray(data, size);
|
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||||
@ -802,7 +813,7 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
delete pTempMsg;
|
delete pTempMsg;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
#define USE_PROTOBUF_USERMESSAGES
|
#define USE_PROTOBUF_USERMESSAGES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -102,12 +102,12 @@ public: //IUserMessages
|
|||||||
bool intercept=false);
|
bool intercept=false);
|
||||||
UserMessageType GetUserMessageType() const;
|
UserMessageType GetUserMessageType() const;
|
||||||
public:
|
public:
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||||
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
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);
|
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
|
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
|
||||||
#else
|
#else
|
||||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
@ -82,7 +82,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||||
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
|
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
|
||||||
#else
|
#else
|
||||||
void LinkConCommandBase(ConCommandBase *pBase)
|
void LinkConCommandBase(ConCommandBase *pBase)
|
||||||
@ -108,20 +108,20 @@ public:
|
|||||||
listener = listener->next;
|
listener = listener->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (iter != tracked_bases.end())
|
while (iter != tracked_bases.end())
|
||||||
{
|
{
|
||||||
if ((*iter)->pBase == pBase)
|
if ((*iter)->pBase == pBase)
|
||||||
{
|
{
|
||||||
pInfo = (*iter);
|
pInfo = (*iter);
|
||||||
iter = tracked_bases.erase(iter);
|
iter = tracked_bases.erase(iter);
|
||||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
|
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
|
||||||
delete pInfo;
|
delete pInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
|
void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os
|
||||||
|
|
||||||
for arch in SM.archs:
|
for cxx in builder.targets:
|
||||||
binary = SM.Library(builder, 'sourcemod.logic', arch)
|
binary = SM.Library(builder, cxx, 'sourcemod.logic')
|
||||||
binary.compiler.cxxincludes += [
|
binary.compiler.cxxincludes += [
|
||||||
builder.sourcePath,
|
builder.sourcePath,
|
||||||
os.path.join(builder.sourcePath, 'core', 'logic'),
|
os.path.join(builder.sourcePath, 'core', 'logic'),
|
||||||
@ -17,9 +17,9 @@ for arch in SM.archs:
|
|||||||
'SM_LOGIC'
|
'SM_LOGIC'
|
||||||
]
|
]
|
||||||
|
|
||||||
if builder.target.platform == 'linux':
|
if binary.compiler.target.platform == 'linux':
|
||||||
binary.compiler.postlink += ['-lpthread', '-lrt']
|
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||||
elif builder.target.platform == 'mac':
|
elif binary.compiler.target.platform == 'mac':
|
||||||
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
||||||
binary.compiler.postlink += ['-framework', 'CoreServices']
|
binary.compiler.postlink += ['-framework', 'CoreServices']
|
||||||
|
|
||||||
@ -35,8 +35,7 @@ for arch in SM.archs:
|
|||||||
'smn_maplists.cpp',
|
'smn_maplists.cpp',
|
||||||
'ADTFactory.cpp',
|
'ADTFactory.cpp',
|
||||||
'smn_adt_stack.cpp',
|
'smn_adt_stack.cpp',
|
||||||
'thread/ThreadWorker.cpp',
|
'BaseWorker.cpp',
|
||||||
'thread/BaseWorker.cpp',
|
|
||||||
'ThreadSupport.cpp',
|
'ThreadSupport.cpp',
|
||||||
'smn_float.cpp',
|
'smn_float.cpp',
|
||||||
'TextParsers.cpp',
|
'TextParsers.cpp',
|
||||||
@ -85,15 +84,12 @@ for arch in SM.archs:
|
|||||||
'smn_halflife.cpp',
|
'smn_halflife.cpp',
|
||||||
'FrameIterator.cpp',
|
'FrameIterator.cpp',
|
||||||
'DatabaseConfBuilder.cpp',
|
'DatabaseConfBuilder.cpp',
|
||||||
|
'LumpManager.cpp',
|
||||||
|
'smn_entitylump.cpp',
|
||||||
'NativeInvoker.cpp',
|
'NativeInvoker.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if arch == 'x64':
|
if binary.compiler.target.arch == 'x86_64':
|
||||||
binary.sources += ['PseudoAddrManager.cpp']
|
binary.sources += ['PseudoAddrManager.cpp']
|
||||||
|
|
||||||
if builder.target.platform == 'windows':
|
|
||||||
binary.sources += ['thread/WinThreads.cpp']
|
|
||||||
else:
|
|
||||||
binary.sources += ['thread/PosixThreads.cpp']
|
|
||||||
|
|
||||||
SM.binaries += [builder.Add(binary)]
|
SM.binaries += [builder.Add(binary)]
|
||||||
|
@ -1581,7 +1581,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
|
|||||||
{
|
{
|
||||||
id = grp_table[i];
|
id = grp_table[i];
|
||||||
num = GetGroupImmunityCount(id);
|
num = GetGroupImmunityCount(id);
|
||||||
for (unsigned int j=0; j<num; i++)
|
for (unsigned int j=0; j<num; j++)
|
||||||
{
|
{
|
||||||
other = GetGroupImmunity(id, j);
|
other = GetGroupImmunity(id, j);
|
||||||
for (unsigned int k=0; k<pUser->grp_count; k++)
|
for (unsigned int k=0; k<pUser->grp_count; k++)
|
||||||
@ -1843,13 +1843,13 @@ bool AdminCache::DumpCache(const char *filename)
|
|||||||
fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
|
fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
|
||||||
if (pGroup->pCmdGrpTable != NULL)
|
if (pGroup->pCmdGrpTable != NULL)
|
||||||
{
|
{
|
||||||
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
for (OverrideMap::iterator iter = pGroup->pCmdGrpTable->iter(); !iter.empty(); iter.next())
|
||||||
iterator_group_grp_override(fp, iter->key.chars(), iter->value);
|
iterator_group_grp_override(fp, iter->key.c_str(), iter->value);
|
||||||
}
|
}
|
||||||
if (pGroup->pCmdTable != NULL)
|
if (pGroup->pCmdTable != NULL)
|
||||||
{
|
{
|
||||||
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
||||||
iterator_group_basic_override(fp, iter->key.chars(), iter->value);
|
iterator_group_basic_override(fp, iter->key.c_str(), iter->value);
|
||||||
}
|
}
|
||||||
fprintf(fp, "\t\t}\n");
|
fprintf(fp, "\t\t}\n");
|
||||||
|
|
||||||
@ -1924,9 +1924,9 @@ bool AdminCache::DumpCache(const char *filename)
|
|||||||
|
|
||||||
fprintf(fp, "\"Overrides\"\n{\n");
|
fprintf(fp, "\"Overrides\"\n{\n");
|
||||||
for (FlagMap::iterator iter = m_CmdGrpOverrides.iter(); !iter.empty(); iter.next())
|
for (FlagMap::iterator iter = m_CmdGrpOverrides.iter(); !iter.empty(); iter.next())
|
||||||
iterator_glob_grp_override(fp, iter->key.chars(), iter->value);
|
iterator_glob_grp_override(fp, iter->key.c_str(), iter->value);
|
||||||
for (FlagMap::iterator iter = m_CmdOverrides.iter(); !iter.empty(); iter.next())
|
for (FlagMap::iterator iter = m_CmdOverrides.iter(); !iter.empty(); iter.next())
|
||||||
iterator_glob_basic_override(fp, iter->key.chars(), iter->value);
|
iterator_glob_basic_override(fp, iter->key.c_str(), iter->value);
|
||||||
fprintf(fp, "}\n");
|
fprintf(fp, "}\n");
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
@ -40,7 +40,7 @@ BaseWorker::BaseWorker(IThreadWorkerCallbacks *hooks) :
|
|||||||
|
|
||||||
BaseWorker::~BaseWorker()
|
BaseWorker::~BaseWorker()
|
||||||
{
|
{
|
||||||
if (m_state != Worker_Stopped || m_state != Worker_Invalid)
|
if (m_state != Worker_Stopped && m_state != Worker_Invalid)
|
||||||
Stop(true);
|
Stop(true);
|
||||||
|
|
||||||
if (m_ThreadQueue.size())
|
if (m_ThreadQueue.size())
|
@ -43,6 +43,7 @@ class BaseWorker;
|
|||||||
class SWThreadHandle : public IThreadHandle
|
class SWThreadHandle : public IThreadHandle
|
||||||
{
|
{
|
||||||
friend class BaseWorker;
|
friend class BaseWorker;
|
||||||
|
friend class CompatWorker;
|
||||||
public:
|
public:
|
||||||
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
||||||
IThread *GetThread();
|
IThread *GetThread();
|
@ -31,8 +31,10 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "CDataPack.h"
|
#include "CDataPack.h"
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
|
|
||||||
CDataPack::CDataPack()
|
CDataPack::CDataPack()
|
||||||
{
|
{
|
||||||
@ -44,33 +46,15 @@ CDataPack::~CDataPack()
|
|||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ke::Vector<ke::AutoPtr<CDataPack>> sDataPackCache;
|
|
||||||
|
|
||||||
CDataPack *CDataPack::New()
|
|
||||||
{
|
|
||||||
if (sDataPackCache.empty())
|
|
||||||
return new CDataPack();
|
|
||||||
|
|
||||||
CDataPack *pack = sDataPackCache.back().take();
|
|
||||||
sDataPackCache.pop();
|
|
||||||
pack->Initialize();
|
|
||||||
return pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDataPack::Free(CDataPack *pack)
|
|
||||||
{
|
|
||||||
sDataPackCache.append(static_cast<CDataPack *>(pack));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::Initialize()
|
void CDataPack::Initialize()
|
||||||
{
|
{
|
||||||
|
position = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
} while (this->RemoveItem());
|
} while (this->RemoveItem());
|
||||||
|
|
||||||
elements.clear();
|
elements.clear();
|
||||||
position = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::ResetSize()
|
void CDataPack::ResetSize()
|
||||||
@ -84,7 +68,7 @@ size_t CDataPack::CreateMemory(size_t size, void **addr)
|
|||||||
val.type = CDataPackType::Raw;
|
val.type = CDataPackType::Raw;
|
||||||
val.pData.vval = new uint8_t[size + sizeof(size)];
|
val.pData.vval = new uint8_t[size + sizeof(size)];
|
||||||
reinterpret_cast<size_t *>(val.pData.vval)[0] = size;
|
reinterpret_cast<size_t *>(val.pData.vval)[0] = size;
|
||||||
elements.insert(position, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
|
||||||
return position++;
|
return position++;
|
||||||
}
|
}
|
||||||
@ -94,7 +78,8 @@ void CDataPack::PackCell(cell_t cell)
|
|||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::Cell;
|
val.type = CDataPackType::Cell;
|
||||||
val.pData.cval = cell;
|
val.pData.cval = cell;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::PackFunction(cell_t function)
|
void CDataPack::PackFunction(cell_t function)
|
||||||
@ -102,7 +87,8 @@ void CDataPack::PackFunction(cell_t function)
|
|||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::Function;
|
val.type = CDataPackType::Function;
|
||||||
val.pData.cval = function;
|
val.pData.cval = function;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::PackFloat(float floatval)
|
void CDataPack::PackFloat(float floatval)
|
||||||
@ -110,16 +96,42 @@ void CDataPack::PackFloat(float floatval)
|
|||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::Float;
|
val.type = CDataPackType::Float;
|
||||||
val.pData.fval = floatval;
|
val.pData.fval = floatval;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::PackString(const char *string)
|
void CDataPack::PackString(const char *string)
|
||||||
{
|
{
|
||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::String;
|
val.type = CDataPackType::String;
|
||||||
ke::AString *sval = new ke::AString(string);
|
std::string *sval = new std::string(string);
|
||||||
val.pData.sval = sval;
|
val.pData.sval = sval;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDataPack::PackCellArray(cell_t const *vals, cell_t count)
|
||||||
|
{
|
||||||
|
InternalPack val;
|
||||||
|
val.type = CDataPackType::CellArray;
|
||||||
|
|
||||||
|
val.pData.aval = new cell_t [count + 1];
|
||||||
|
memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count);
|
||||||
|
val.pData.aval[0] = count;
|
||||||
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDataPack::PackFloatArray(cell_t const *vals, cell_t count)
|
||||||
|
{
|
||||||
|
InternalPack val;
|
||||||
|
val.type = CDataPackType::FloatArray;
|
||||||
|
|
||||||
|
val.pData.aval = new cell_t [count + 1];
|
||||||
|
memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count);
|
||||||
|
val.pData.aval[0] = count;
|
||||||
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::Reset() const
|
void CDataPack::Reset() const
|
||||||
@ -134,7 +146,7 @@ size_t CDataPack::GetPosition() const
|
|||||||
|
|
||||||
bool CDataPack::SetPosition(size_t pos) const
|
bool CDataPack::SetPosition(size_t pos) const
|
||||||
{
|
{
|
||||||
if (pos > elements.length())
|
if (pos > elements.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
position = pos;
|
position = pos;
|
||||||
@ -167,7 +179,7 @@ float CDataPack::ReadFloat() const
|
|||||||
|
|
||||||
bool CDataPack::IsReadable(size_t bytes) const
|
bool CDataPack::IsReadable(size_t bytes) const
|
||||||
{
|
{
|
||||||
return (position < elements.length());
|
return (position < elements.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CDataPack::ReadString(size_t *len) const
|
const char *CDataPack::ReadString(size_t *len) const
|
||||||
@ -180,11 +192,51 @@ const char *CDataPack::ReadString(size_t *len) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ke::AString &val = *elements[position++].pData.sval;
|
const std::string &val = *elements[position++].pData.sval;
|
||||||
if (len)
|
if (len)
|
||||||
*len = val.length();
|
*len = val.size();
|
||||||
|
|
||||||
return val.chars();
|
return val.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *CDataPack::ReadCellArray(cell_t *size) const
|
||||||
|
{
|
||||||
|
if (!IsReadable() || elements[position].type != CDataPackType::CellArray)
|
||||||
|
{
|
||||||
|
if(size)
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *val = elements[position].pData.aval;
|
||||||
|
cell_t *ptr = &(val[1]);
|
||||||
|
++position;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = val[0];
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *CDataPack::ReadFloatArray(cell_t *size) const
|
||||||
|
{
|
||||||
|
if (!IsReadable() || elements[position].type != CDataPackType::FloatArray)
|
||||||
|
{
|
||||||
|
if(size)
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *val = elements[position].pData.aval;
|
||||||
|
cell_t *ptr = &(val[1]);
|
||||||
|
++position;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = val[0];
|
||||||
|
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *CDataPack::ReadMemory(size_t *size) const
|
void *CDataPack::ReadMemory(size_t *size) const
|
||||||
@ -205,7 +257,7 @@ void *CDataPack::ReadMemory(size_t *size) const
|
|||||||
|
|
||||||
bool CDataPack::RemoveItem(size_t pos)
|
bool CDataPack::RemoveItem(size_t pos)
|
||||||
{
|
{
|
||||||
if (!elements.length())
|
if (!elements.size())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -214,7 +266,8 @@ bool CDataPack::RemoveItem(size_t pos)
|
|||||||
{
|
{
|
||||||
pos = position;
|
pos = position;
|
||||||
}
|
}
|
||||||
if (pos >= elements.length())
|
|
||||||
|
if (pos >= elements.size())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -228,7 +281,7 @@ bool CDataPack::RemoveItem(size_t pos)
|
|||||||
{
|
{
|
||||||
case CDataPackType::Raw:
|
case CDataPackType::Raw:
|
||||||
{
|
{
|
||||||
delete elements[pos].pData.vval;
|
delete [] elements[pos].pData.vval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,8 +290,15 @@ bool CDataPack::RemoveItem(size_t pos)
|
|||||||
delete elements[pos].pData.sval;
|
delete elements[pos].pData.sval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CDataPackType::CellArray:
|
||||||
|
case CDataPackType::FloatArray:
|
||||||
|
{
|
||||||
|
delete [] elements[pos].pData.aval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.remove(pos);
|
elements.erase(elements.begin() + pos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,9 @@ enum CDataPackType {
|
|||||||
Cell,
|
Cell,
|
||||||
Float,
|
Float,
|
||||||
String,
|
String,
|
||||||
Function
|
Function,
|
||||||
|
CellArray,
|
||||||
|
FloatArray,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDataPack
|
class CDataPack
|
||||||
@ -52,9 +54,6 @@ public:
|
|||||||
CDataPack();
|
CDataPack();
|
||||||
~CDataPack();
|
~CDataPack();
|
||||||
|
|
||||||
static CDataPack *New();
|
|
||||||
static void Free(CDataPack *pack);
|
|
||||||
|
|
||||||
public: // Originally IDataReader
|
public: // Originally IDataReader
|
||||||
/**
|
/**
|
||||||
* @brief Resets the position in the data stream to the beginning.
|
* @brief Resets the position in the data stream to the beginning.
|
||||||
@ -90,6 +89,21 @@ public: // Originally IDataReader
|
|||||||
*/
|
*/
|
||||||
float ReadFloat() const;
|
float ReadFloat() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads an array of values from the data stream.
|
||||||
|
*
|
||||||
|
* @param len The size of the array stored at this position to return.
|
||||||
|
* @return A cell array read from the current position.
|
||||||
|
*/
|
||||||
|
cell_t *ReadCellArray(cell_t *len) const;
|
||||||
|
/**
|
||||||
|
* @brief Reads an array of values from the data stream.
|
||||||
|
*
|
||||||
|
* @param len The size of the array stored at this position to return.
|
||||||
|
* @return A cell array read from the current position.
|
||||||
|
*/
|
||||||
|
cell_t *ReadFloatArray(cell_t *len) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns whether or not a specified number of bytes from the current stream
|
* @brief Returns whether or not a specified number of bytes from the current stream
|
||||||
* position to the end can be read.
|
* position to the end can be read.
|
||||||
@ -150,6 +164,21 @@ public: // Originally IDataPack
|
|||||||
*/
|
*/
|
||||||
void PackString(const char *string);
|
void PackString(const char *string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Packs an array of cells into the data stream.
|
||||||
|
*
|
||||||
|
* @param vals Cells to write.
|
||||||
|
* @param count Number of cells.
|
||||||
|
*/
|
||||||
|
void PackCellArray(cell_t const *vals, cell_t count);
|
||||||
|
/**
|
||||||
|
* @brief Packs an array of cells into the data stream.
|
||||||
|
*
|
||||||
|
* @param vals Cells to write.
|
||||||
|
* @param count Number of cells.
|
||||||
|
*/
|
||||||
|
void PackFloatArray(cell_t const *vals, cell_t count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a generic block of memory in the stream.
|
* @brief Creates a generic block of memory in the stream.
|
||||||
*
|
*
|
||||||
@ -172,7 +201,7 @@ public: // Originally IDataPack
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
inline size_t GetCapacity() const { return this->elements.length(); };
|
inline size_t GetCapacity() const { return this->elements.size(); };
|
||||||
inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; };
|
inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; };
|
||||||
bool RemoveItem(size_t pos = -1);
|
bool RemoveItem(size_t pos = -1);
|
||||||
|
|
||||||
@ -181,7 +210,8 @@ private:
|
|||||||
cell_t cval;
|
cell_t cval;
|
||||||
float fval;
|
float fval;
|
||||||
uint8_t *vval;
|
uint8_t *vval;
|
||||||
ke::AString *sval;
|
std::string *sval;
|
||||||
|
cell_t *aval;
|
||||||
} InternalPackValue;
|
} InternalPackValue;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -189,7 +219,7 @@ private:
|
|||||||
CDataPackType type;
|
CDataPackType type;
|
||||||
} InternalPack;
|
} InternalPack;
|
||||||
|
|
||||||
ke::Vector<InternalPack> elements;
|
std::vector<InternalPack> elements;
|
||||||
mutable size_t position;
|
mutable size_t position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ICellArray.h>
|
#include <ICellArray.h>
|
||||||
|
#include <amtl/am-bits.h>
|
||||||
|
|
||||||
extern HandleType_t htCellArray;
|
extern HandleType_t htCellArray;
|
||||||
|
|
||||||
@ -214,30 +215,34 @@ private:
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
size_t newAllocSize = m_AllocSize;
|
||||||
/* Set a base allocation size of 8 items */
|
/* Set a base allocation size of 8 items */
|
||||||
if (!m_AllocSize)
|
if (!newAllocSize)
|
||||||
{
|
{
|
||||||
m_AllocSize = 8;
|
newAllocSize = 8;
|
||||||
|
}
|
||||||
|
if (!ke::IsUintPtrAddSafe(m_Size, count))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
/* If it's not enough, keep doubling */
|
/* If it's not enough, keep doubling */
|
||||||
while (m_Size + count > m_AllocSize)
|
while (m_Size + count > newAllocSize)
|
||||||
{
|
{
|
||||||
m_AllocSize *= 2;
|
if (!ke::IsUintPtrMultiplySafe(newAllocSize, 2))
|
||||||
}
|
|
||||||
/* finally, allocate the new block */
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize));
|
|
||||||
if (!data) // allocation failure
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
newAllocSize *= 2;
|
||||||
m_Data = data;
|
|
||||||
} else {
|
|
||||||
m_Data = static_cast<cell_t*>(malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize));
|
|
||||||
}
|
}
|
||||||
return (m_Data != nullptr);
|
/* finally, allocate the new block */
|
||||||
|
cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * newAllocSize));
|
||||||
|
/* Update state if allocation was successful */
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
m_AllocSize = newAllocSize;
|
||||||
|
m_Data = data;
|
||||||
|
}
|
||||||
|
return (data != nullptr);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
cell_t *m_Data;
|
cell_t *m_Data;
|
||||||
|
@ -34,17 +34,20 @@
|
|||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <amtl/am-thread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <bridge/include/ILogger.h>
|
#include <bridge/include/ILogger.h>
|
||||||
#include <bridge/include/CoreProvider.h>
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
#define DBPARSE_LEVEL_NONE 0
|
#define DBPARSE_LEVEL_NONE 0
|
||||||
#define DBPARSE_LEVEL_MAIN 1
|
#define DBPARSE_LEVEL_MAIN 1
|
||||||
#define DBPARSE_LEVEL_DATABASE 2
|
#define DBPARSE_LEVEL_DATABASE 2
|
||||||
|
|
||||||
DBManager g_DBMan;
|
DBManager g_DBMan;
|
||||||
static bool s_OneTimeThreaderErrorMsg = false;
|
|
||||||
|
|
||||||
DBManager::DBManager()
|
DBManager::DBManager()
|
||||||
: m_Terminate(false),
|
: m_Terminate(false),
|
||||||
@ -125,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)
|
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::RefPtr<ConfDbInfo> pInfo = list->GetDatabaseConf(name);
|
ke::RefPtr<ConfDbInfo> pInfo = list.GetDatabaseConf(name);
|
||||||
|
|
||||||
if (!pInfo)
|
if (!pInfo)
|
||||||
{
|
{
|
||||||
@ -145,12 +148,12 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
|||||||
/* Try to assign a real driver pointer */
|
/* Try to assign a real driver pointer */
|
||||||
if (pInfo->info.driver[0] == '\0')
|
if (pInfo->info.driver[0] == '\0')
|
||||||
{
|
{
|
||||||
ke::AString defaultDriver = list->GetDefaultDriver();
|
std::string defaultDriver = list.GetDefaultDriver();
|
||||||
if (!m_pDefault && defaultDriver.length() > 0)
|
if (!m_pDefault && defaultDriver.length() > 0)
|
||||||
{
|
{
|
||||||
m_pDefault = FindOrLoadDriver(defaultDriver.chars());
|
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||||
}
|
}
|
||||||
dname = defaultDriver.length() ? defaultDriver.chars() : "default";
|
dname = defaultDriver.length() ? defaultDriver.c_str() : "default";
|
||||||
pInfo->realDriver = m_pDefault;
|
pInfo->realDriver = m_pDefault;
|
||||||
} else {
|
} else {
|
||||||
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
|
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
|
||||||
@ -206,17 +209,14 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
for (size_t i = 0; i < list->length(); i++)
|
for (auto conf : list) {
|
||||||
{
|
if (conf->realDriver == pDriver)
|
||||||
ke::RefPtr<ConfDbInfo> current = list->at(i);
|
|
||||||
if (current->realDriver == pDriver)
|
|
||||||
{
|
{
|
||||||
current->realDriver = NULL;
|
conf->realDriver = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Someone unloaded the default driver? Silly.. */
|
/* Someone unloaded the default driver? Silly.. */
|
||||||
if (pDriver == m_pDefault)
|
if (pDriver == m_pDefault)
|
||||||
{
|
{
|
||||||
@ -252,11 +252,11 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
|||||||
|
|
||||||
IDBDriver *DBManager::GetDefaultDriver()
|
IDBDriver *DBManager::GetDefaultDriver()
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::AString defaultDriver = list->GetDefaultDriver();
|
std::string defaultDriver = list.GetDefaultDriver();
|
||||||
if (!m_pDefault && defaultDriver.length() > 0)
|
if (!m_pDefault && defaultDriver.length() > 0)
|
||||||
{
|
{
|
||||||
m_pDefault = FindOrLoadDriver(defaultDriver.chars());
|
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_pDefault;
|
return m_pDefault;
|
||||||
@ -319,12 +319,12 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
|
|||||||
|
|
||||||
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::RefPtr<ConfDbInfo> info = list->GetDatabaseConf(name);
|
ke::RefPtr<ConfDbInfo> info = list.GetDatabaseConf(name);
|
||||||
if (!info)
|
if (!info)
|
||||||
{
|
{
|
||||||
// couldn't find requested conf, return default if exists
|
// couldn't find requested conf, return default if exists
|
||||||
info = list->GetDefaultConfiguration();
|
info = list.GetDefaultConfiguration();
|
||||||
if (!info)
|
if (!info)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -334,11 +334,10 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
|||||||
return &info->info;
|
return &info->info;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
|
ke::RefPtr<ConfDbInfo> DBManager::GetDatabaseConf(const char *name)
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name));
|
return list.GetDatabaseConf(name);
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||||
@ -377,13 +376,12 @@ void DBManager::KillWorkerThread()
|
|||||||
if (m_Worker)
|
if (m_Worker)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_QueueEvent);
|
std::lock_guard<std::mutex> lock(m_Lock);
|
||||||
m_Terminate = true;
|
m_Terminate = true;
|
||||||
m_QueueEvent.Notify();
|
m_QueueEvent.notify_all();
|
||||||
}
|
}
|
||||||
m_Worker->Join();
|
m_Worker->join();
|
||||||
m_Worker = nullptr;
|
m_Worker = nullptr;
|
||||||
s_OneTimeThreaderErrorMsg = false;
|
|
||||||
m_Terminate = false;
|
m_Terminate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,27 +397,17 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
|
|||||||
|
|
||||||
if (!m_Worker)
|
if (!m_Worker)
|
||||||
{
|
{
|
||||||
m_Worker = new ke::Thread([this]() -> void {
|
m_Worker = ke::NewThread("SM Database Worker", [this]() -> void {
|
||||||
Run();
|
Run();
|
||||||
}, "SM SQL Worker");
|
});
|
||||||
if (!m_Worker->Succeeded())
|
|
||||||
{
|
|
||||||
if (!s_OneTimeThreaderErrorMsg)
|
|
||||||
{
|
|
||||||
logger->LogError("[SM] Unable to create db threader (error unknown)");
|
|
||||||
s_OneTimeThreaderErrorMsg = true;
|
|
||||||
}
|
|
||||||
m_Worker = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add to the queue */
|
/* Add to the queue */
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_QueueEvent);
|
std::lock_guard<std::mutex> lock(m_Lock);
|
||||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
||||||
queue.push(op);
|
queue.push(op);
|
||||||
m_QueueEvent.Notify();
|
m_QueueEvent.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -450,7 +438,7 @@ void DBManager::Run()
|
|||||||
|
|
||||||
void DBManager::ThreadMain()
|
void DBManager::ThreadMain()
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_QueueEvent);
|
std::unique_lock<std::mutex> lock(m_Lock);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// The lock has been acquired. Grab everything we can out of the
|
// The lock has been acquired. Grab everything we can out of the
|
||||||
@ -458,46 +446,43 @@ void DBManager::ThreadMain()
|
|||||||
// we process all operations we can before checking to terminate.
|
// we process all operations we can before checking to terminate.
|
||||||
// There's no risk of starvation since the main thread blocks on us
|
// There's no risk of starvation since the main thread blocks on us
|
||||||
// terminating.
|
// terminating.
|
||||||
while (true)
|
auto queue = &m_OpQueue.GetLikelyQueue();
|
||||||
{
|
if (queue->empty()) {
|
||||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
|
// If the queue is empty and we've been asked to stop, leave now.
|
||||||
if (queue.empty())
|
if (m_Terminate)
|
||||||
break;
|
return;
|
||||||
|
|
||||||
IDBThreadOperation *op = queue.first();
|
// Otherwise, wait for something to happen.
|
||||||
queue.pop();
|
m_QueueEvent.wait(lock);
|
||||||
|
continue;
|
||||||
// Unlock the queue when we run the query, so the main thread can
|
|
||||||
// keep pumping events. We re-acquire the lock to check for more
|
|
||||||
// items. It's okay if we terminate while unlocked; the main
|
|
||||||
// thread would be blocked and we'd need to flush the queue
|
|
||||||
// anyway, so after we've depleted the queue here, we'll just
|
|
||||||
// reach the terminate at the top of the loop.
|
|
||||||
{
|
|
||||||
ke::AutoUnlock unlock(&m_QueueEvent);
|
|
||||||
op->RunThreadPart();
|
|
||||||
|
|
||||||
ke::AutoLock lock(&m_ThinkLock);
|
|
||||||
m_ThinkQueue.push(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!m_Terminate)
|
|
||||||
{
|
|
||||||
ke::AutoUnlock unlock(&m_QueueEvent);
|
|
||||||
#ifdef _WIN32
|
|
||||||
Sleep(20);
|
|
||||||
#else
|
|
||||||
usleep(20000);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Terminate)
|
IDBThreadOperation *op = queue->first();
|
||||||
return;
|
queue->pop();
|
||||||
|
|
||||||
// Release the lock and wait for a signal.
|
// Unlock the queue when we run the query, so the main thread can
|
||||||
m_QueueEvent.Wait();
|
// keep pumping events. We re-acquire the lock to check for more
|
||||||
|
// items. It's okay if we terminate while unlocked; the main
|
||||||
|
// thread would be blocked and we'd need to flush the queue
|
||||||
|
// anyway, so after we've depleted the queue here, we'll just
|
||||||
|
// reach the terminate at the top of the loop.
|
||||||
|
lock.unlock();
|
||||||
|
op->RunThreadPart();
|
||||||
|
|
||||||
|
// Re-acquire the lock and give the data back to the main thread
|
||||||
|
// immediately. We use a separate lock to minimize game thread
|
||||||
|
// contention.
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> think_lock(m_ThinkLock);
|
||||||
|
m_ThinkQueue.push(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we add a 20ms delay after processing a query. This is
|
||||||
|
// questionable but the intent is to avoid starving the game thread.
|
||||||
|
if (!m_Terminate)
|
||||||
|
std::this_thread::sleep_for(20ms);
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,7 +497,7 @@ void DBManager::RunFrame()
|
|||||||
/* Dump one thing per-frame so the server stays sane. */
|
/* Dump one thing per-frame so the server stays sane. */
|
||||||
IDBThreadOperation *op;
|
IDBThreadOperation *op;
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_ThinkLock);
|
std::lock_guard<std::mutex> lock(m_ThinkLock);
|
||||||
op = m_ThinkQueue.first();
|
op = m_ThinkQueue.first();
|
||||||
m_ThinkQueue.pop();
|
m_ThinkQueue.pop();
|
||||||
}
|
}
|
||||||
@ -591,10 +576,10 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::AString DBManager::GetDefaultDriverName()
|
std::string DBManager::GetDefaultDriverName()
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
return list->GetDefaultDriver();
|
return list.GetDefaultDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||||
|
@ -38,7 +38,10 @@
|
|||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <am-thread-utils.h>
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include "sm_simple_prioqueue.h"
|
#include "sm_simple_prioqueue.h"
|
||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
#include "DatabaseConfBuilder.h"
|
#include "DatabaseConfBuilder.h"
|
||||||
@ -68,7 +71,7 @@ public: //IDBManager
|
|||||||
void AddDriver(IDBDriver *pDrivera);
|
void AddDriver(IDBDriver *pDrivera);
|
||||||
void RemoveDriver(IDBDriver *pDriver);
|
void RemoveDriver(IDBDriver *pDriver);
|
||||||
const DatabaseInfo *FindDatabaseConf(const char *name);
|
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);
|
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
|
||||||
unsigned int GetDriverCount();
|
unsigned int GetDriverCount();
|
||||||
IDBDriver *GetDriver(unsigned int index);
|
IDBDriver *GetDriver(unsigned int index);
|
||||||
@ -84,7 +87,7 @@ public: //IPluginsListener
|
|||||||
public:
|
public:
|
||||||
IDBDriver *FindOrLoadDriver(const char *name);
|
IDBDriver *FindOrLoadDriver(const char *name);
|
||||||
IDBDriver *GetDefaultDriver();
|
IDBDriver *GetDefaultDriver();
|
||||||
ke::AString GetDefaultDriverName();
|
std::string GetDefaultDriverName();
|
||||||
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
|
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
inline HandleType_t GetDatabaseType()
|
inline HandleType_t GetDatabaseType()
|
||||||
@ -101,9 +104,10 @@ private:
|
|||||||
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
||||||
Queue<IDBThreadOperation *> m_ThinkQueue;
|
Queue<IDBThreadOperation *> m_ThinkQueue;
|
||||||
CVector<bool> m_drSafety; /* which drivers are safe? */
|
CVector<bool> m_drSafety; /* which drivers are safe? */
|
||||||
ke::AutoPtr<ke::Thread> m_Worker;
|
std::unique_ptr<std::thread> m_Worker;
|
||||||
ke::ConditionVariable m_QueueEvent;
|
std::condition_variable m_QueueEvent;
|
||||||
ke::Mutex m_ThinkLock;
|
std::mutex m_ThinkLock;
|
||||||
|
std::mutex m_Lock;
|
||||||
bool m_Terminate;
|
bool m_Terminate;
|
||||||
|
|
||||||
DatabaseConfBuilder m_Builder;
|
DatabaseConfBuilder m_Builder;
|
||||||
|
@ -36,8 +36,8 @@
|
|||||||
#define DBPARSE_LEVEL_DATABASE 2
|
#define DBPARSE_LEVEL_DATABASE 2
|
||||||
|
|
||||||
DatabaseConfBuilder::DatabaseConfBuilder()
|
DatabaseConfBuilder::DatabaseConfBuilder()
|
||||||
: m_ParseList(nullptr),
|
: m_ParseList(),
|
||||||
m_InfoList(new ConfDbInfoList())
|
m_InfoList()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ DatabaseConfBuilder::~DatabaseConfBuilder()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfoList *DatabaseConfBuilder::GetConfigList()
|
ConfDbInfoList &DatabaseConfBuilder::GetConfigList()
|
||||||
{
|
{
|
||||||
return m_InfoList;
|
return m_InfoList;
|
||||||
}
|
}
|
||||||
@ -59,9 +59,9 @@ void DatabaseConfBuilder::StartParse()
|
|||||||
{
|
{
|
||||||
SMCError err;
|
SMCError err;
|
||||||
SMCStates states = {0, 0};
|
SMCStates states = {0, 0};
|
||||||
if ((err = textparsers->ParseFile_SMC(m_Filename.chars(), this, &states)) != SMCError_Okay)
|
if ((err = textparsers->ParseFile_SMC(m_Filename.c_str(), this, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.chars());
|
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.c_str());
|
||||||
if (err != SMCError_Custom)
|
if (err != SMCError_Custom)
|
||||||
{
|
{
|
||||||
const char *txt = textparsers->GetSMCErrorString(err);
|
const char *txt = textparsers->GetSMCErrorString(err);
|
||||||
@ -75,7 +75,7 @@ void DatabaseConfBuilder::ReadSMC_ParseStart()
|
|||||||
m_ParseLevel = 0;
|
m_ParseLevel = 0;
|
||||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||||
|
|
||||||
m_ParseList = new ConfDbInfoList();
|
m_ParseList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCResult DatabaseConfBuilder::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
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)
|
if (strcmp(key, "driver_default") == 0)
|
||||||
{
|
{
|
||||||
m_ParseList->SetDefaultDriver(value);
|
m_ParseList.SetDefaultDriver(value);
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||||
if (strcmp(key, "driver") == 0)
|
if (strcmp(key, "driver") == 0)
|
||||||
@ -153,15 +153,15 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
|
|
||||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||||
{
|
{
|
||||||
m_ParseCurrent->info.driver = m_ParseCurrent->driver.chars();
|
m_ParseCurrent->info.driver = m_ParseCurrent->driver.c_str();
|
||||||
m_ParseCurrent->info.database = m_ParseCurrent->database.chars();
|
m_ParseCurrent->info.database = m_ParseCurrent->database.c_str();
|
||||||
m_ParseCurrent->info.host = m_ParseCurrent->host.chars();
|
m_ParseCurrent->info.host = m_ParseCurrent->host.c_str();
|
||||||
m_ParseCurrent->info.user = m_ParseCurrent->user.chars();
|
m_ParseCurrent->info.user = m_ParseCurrent->user.c_str();
|
||||||
m_ParseCurrent->info.pass = m_ParseCurrent->pass.chars();
|
m_ParseCurrent->info.pass = m_ParseCurrent->pass.c_str();
|
||||||
|
|
||||||
/* Save it.. */
|
/* Save it.. */
|
||||||
m_ParseCurrent->AddRef();
|
m_ParseCurrent->AddRef();
|
||||||
m_ParseList->append(m_ParseCurrent);
|
m_ParseList.push_back(m_ParseCurrent);
|
||||||
m_ParseCurrent = nullptr;
|
m_ParseCurrent = nullptr;
|
||||||
|
|
||||||
/* Go up one level */
|
/* Go up one level */
|
||||||
@ -176,9 +176,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
|
|
||||||
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
|
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||||
{
|
{
|
||||||
m_InfoList->ReleaseMembers();
|
m_InfoList.clear();
|
||||||
delete m_InfoList;
|
|
||||||
m_InfoList = m_ParseList;
|
m_InfoList = m_ParseList;
|
||||||
|
m_ParseList.clear();
|
||||||
m_ParseList = nullptr;
|
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
|
#include <am-refcounting.h>
|
||||||
#include <am-refcounting-threadsafe.h>
|
#include <am-refcounting-threadsafe.h>
|
||||||
|
|
||||||
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
|
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
|
||||||
@ -46,58 +47,53 @@ public:
|
|||||||
ConfDbInfo() : realDriver(NULL)
|
ConfDbInfo() : realDriver(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ke::AString name;
|
std::string name;
|
||||||
ke::AString driver;
|
std::string driver;
|
||||||
ke::AString host;
|
std::string host;
|
||||||
ke::AString user;
|
std::string user;
|
||||||
ke::AString pass;
|
std::string pass;
|
||||||
ke::AString database;
|
std::string database;
|
||||||
IDBDriver *realDriver;
|
IDBDriver *realDriver;
|
||||||
DatabaseInfo info;
|
DatabaseInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfDbInfoList : public ke::Vector<ConfDbInfo *>
|
class ConfDbInfoList : public std::vector<ke::RefPtr<ConfDbInfo>>
|
||||||
{
|
{
|
||||||
/* Allow internal usage of ConfDbInfoList */
|
/* Allow internal usage of ConfDbInfoList */
|
||||||
friend class DBManager;
|
friend class DBManager;
|
||||||
friend class DatabaseConfBuilder;
|
friend class DatabaseConfBuilder;
|
||||||
private:
|
private:
|
||||||
ke::AString& GetDefaultDriver() {
|
std::string& GetDefaultDriver() {
|
||||||
return m_DefDriver;
|
return m_DefDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfo *GetDatabaseConf(const char *name) {
|
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name) {
|
||||||
for (size_t i = 0; i < this->length(); i++)
|
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
|
/* If we run into the default configuration, then we'll save it
|
||||||
* for the next call to GetDefaultConfiguration */
|
* for the next call to GetDefaultConfiguration */
|
||||||
if (strcmp(current->name.chars(), "default") == 0)
|
if (strcmp(current->name.c_str(), "default") == 0)
|
||||||
{
|
{
|
||||||
m_DefaultConfig = current;
|
m_DefaultConfig = current;
|
||||||
}
|
}
|
||||||
if (strcmp(current->name.chars(), name) == 0)
|
if (strcmp(current->name.c_str(), name) == 0)
|
||||||
{
|
{
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
ConfDbInfo *GetDefaultConfiguration() {
|
|
||||||
|
ke::RefPtr<ConfDbInfo> GetDefaultConfiguration() {
|
||||||
return m_DefaultConfig;
|
return m_DefaultConfig;
|
||||||
}
|
}
|
||||||
void SetDefaultDriver(const char *input) {
|
void SetDefaultDriver(const char *input) {
|
||||||
m_DefDriver = ke::AString(input);
|
m_DefDriver = std::string(input);
|
||||||
}
|
|
||||||
void ReleaseMembers() {
|
|
||||||
for (size_t i = 0; i < this->length(); i++) {
|
|
||||||
ConfDbInfo *current = this->at(i);
|
|
||||||
current->Release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
ConfDbInfo *m_DefaultConfig;
|
ke::RefPtr<ConfDbInfo> m_DefaultConfig;
|
||||||
ke::AString m_DefDriver;
|
std::string m_DefDriver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +104,7 @@ public:
|
|||||||
~DatabaseConfBuilder();
|
~DatabaseConfBuilder();
|
||||||
void StartParse();
|
void StartParse();
|
||||||
void SetPath(char* path);
|
void SetPath(char* path);
|
||||||
ConfDbInfoList *GetConfigList();
|
ConfDbInfoList &GetConfigList();
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
@ -120,10 +116,10 @@ private:
|
|||||||
unsigned int m_ParseLevel;
|
unsigned int m_ParseLevel;
|
||||||
unsigned int m_ParseState;
|
unsigned int m_ParseState;
|
||||||
ConfDbInfo *m_ParseCurrent;
|
ConfDbInfo *m_ParseCurrent;
|
||||||
ConfDbInfoList *m_ParseList;
|
ConfDbInfoList m_ParseList;
|
||||||
private:
|
private:
|
||||||
ke::AString m_Filename;
|
std::string m_Filename;
|
||||||
ConfDbInfoList *m_InfoList;
|
ConfDbInfoList m_InfoList;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
|
#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);
|
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
||||||
|
|
||||||
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
|
||||||
|
|
||||||
if (error)
|
if (err >= 0) {
|
||||||
{
|
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
if (error)
|
||||||
} else {
|
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
else
|
||||||
|
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] %s", buffer);
|
g_Logger.LogError("[SM] %s", buffer);
|
||||||
@ -194,22 +194,22 @@ void DebugReport::ReportError(const IErrorReport &report, IFrameIterator &iter)
|
|||||||
g_Logger.LogError("[SM] Blaming: %s", blame);
|
g_Logger.LogError("[SM] Blaming: %s", blame);
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::Vector<ke::AString> arr = GetStackTrace(&iter);
|
std::vector<std::string> arr = GetStackTrace(&iter);
|
||||||
for (size_t i = 0; i < arr.length(); i++)
|
for (size_t i = 0; i < arr.size(); i++)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("%s", arr[i].chars());
|
g_Logger.LogError("%s", arr[i].c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
|
std::vector<std::string> DebugReport::GetStackTrace(IFrameIterator *iter)
|
||||||
{
|
{
|
||||||
char temp[3072];
|
char temp[3072];
|
||||||
ke::Vector<ke::AString> trace;
|
std::vector<std::string> trace;
|
||||||
iter->Reset();
|
iter->Reset();
|
||||||
|
|
||||||
if (!iter->Done())
|
if (!iter->Done())
|
||||||
{
|
{
|
||||||
trace.append("[SM] Call stack trace:");
|
trace.push_back("[SM] Call stack trace:");
|
||||||
|
|
||||||
for (int index = 0; !iter->Done(); iter->Next(), index++)
|
for (int index = 0; !iter->Done(); iter->Next(), index++)
|
||||||
{
|
{
|
||||||
@ -221,7 +221,7 @@ ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
|
|||||||
if (iter->IsNativeFrame())
|
if (iter->IsNativeFrame())
|
||||||
{
|
{
|
||||||
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] %s", index, fn);
|
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] %s", index, fn);
|
||||||
trace.append(temp);
|
trace.push_back(temp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (iter->IsScriptedFrame())
|
if (iter->IsScriptedFrame())
|
||||||
@ -237,7 +237,7 @@ ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
|
|||||||
file,
|
file,
|
||||||
fn);
|
fn);
|
||||||
|
|
||||||
trace.append(temp);
|
trace.push_back(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,10 +47,12 @@ public: // IDebugListener
|
|||||||
void ReportError(const IErrorReport &report, IFrameIterator &iter);
|
void ReportError(const IErrorReport &report, IFrameIterator &iter);
|
||||||
void OnDebugSpew(const char *msg, ...);
|
void OnDebugSpew(const char *msg, ...);
|
||||||
public:
|
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 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 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, ...);
|
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
||||||
ke::Vector<ke::AString> GetStackTrace(IFrameIterator *iter);
|
std::vector<std::string> GetStackTrace(IFrameIterator *iter);
|
||||||
private:
|
private:
|
||||||
int _GetPluginIndex(IPluginContext *ctx);
|
int _GetPluginIndex(IPluginContext *ctx);
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include <ILibrarySys.h>
|
#include <ILibrarySys.h>
|
||||||
#include <ISourceMod.h>
|
#include <ISourceMod.h>
|
||||||
@ -76,7 +79,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -85,7 +88,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s.%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s.%s." PLATFORM_LIB_EXT,
|
||||||
filename,
|
filename,
|
||||||
bridge->gamesuffix);
|
bridge->gamesuffix);
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s.2.ep2v." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
|
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
|
||||||
@ -108,7 +111,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s.2.l4d2." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +122,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "auto.%s/%s." PLATFORM_LIB_EXT,
|
||||||
filename,
|
filename,
|
||||||
bridge->gamesuffix);
|
bridge->gamesuffix);
|
||||||
|
|
||||||
@ -129,7 +132,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,6 +240,8 @@ void CLocalExtension::Unload()
|
|||||||
m_pLib->CloseLibrary();
|
m_pLib->CloseLibrary();
|
||||||
m_pLib = NULL;
|
m_pLib = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bFullyLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
||||||
@ -301,7 +306,7 @@ bool CExtension::Load(char *error, size_t maxlength)
|
|||||||
/* Check if we're past load time */
|
/* Check if we're past load time */
|
||||||
if (!bridge->IsMapLoading())
|
if (!bridge->IsMapLoading())
|
||||||
{
|
{
|
||||||
m_pAPI->OnExtensionsAllLoaded();
|
MarkAllLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -496,7 +501,7 @@ void CExtensionManager::TryAutoload()
|
|||||||
|
|
||||||
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
|
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
|
||||||
|
|
||||||
ke::AutoPtr<IDirectory> pDir(libsys->OpenDirectory(path));
|
std::unique_ptr<IDirectory> pDir(libsys->OpenDirectory(path));
|
||||||
if (!pDir)
|
if (!pDir)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -628,9 +633,15 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
|||||||
|
|
||||||
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
|
if (strstr(file, "..") != NULL)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(error, maxlength, "Cannot load extensions outside the \"extensions\" folder.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove platform extension if it's there. Compat hack. */
|
/* Remove platform extension if it's there. Compat hack. */
|
||||||
const char *ext = libsys->GetFileExtension(file);
|
const char *ext = libsys->GetFileExtension(file);
|
||||||
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
if (ext && strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||||
{
|
{
|
||||||
char path2[PLATFORM_MAX_PATH];
|
char path2[PLATFORM_MAX_PATH];
|
||||||
ke::SafeStrcpy(path2, sizeof(path2), file);
|
ke::SafeStrcpy(path2, sizeof(path2), file);
|
||||||
@ -1171,7 +1182,6 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
|||||||
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
|
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srand(static_cast<int>(time(NULL)));
|
|
||||||
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
||||||
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
||||||
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
||||||
@ -1364,7 +1374,7 @@ bool CLocalExtension::IsSameFile(const char *file)
|
|||||||
|
|
||||||
bool CRemoteExtension::IsSameFile(const char *file)
|
bool CRemoteExtension::IsSameFile(const char *file)
|
||||||
{
|
{
|
||||||
/* :TODO: this could be better, but no one uses this API anyway. */
|
/* Check full path and name passed in from LoadExternal */
|
||||||
return strcmp(file, m_Path.c_str()) == 0;
|
return strcmp(file, m_Path.c_str()) == 0 || strcmp(file, m_File.c_str()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned
|
|||||||
{
|
{
|
||||||
scripts->AddFunctionsToForward(name, fwd);
|
scripts->AddFunctionsToForward(name, fwd);
|
||||||
|
|
||||||
m_managed.append(fwd);
|
m_managed.push_back(fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fwd;
|
return fwd;
|
||||||
@ -78,7 +78,7 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType
|
|||||||
|
|
||||||
if (fwd)
|
if (fwd)
|
||||||
{
|
{
|
||||||
m_unmanaged.append(fwd);
|
m_unmanaged.push_back(fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fwd;
|
return fwd;
|
||||||
@ -751,9 +751,9 @@ bool CForward::AddFunction(IPluginFunction *func)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (func->IsRunnable())
|
if (func->IsRunnable())
|
||||||
m_functions.append(func);
|
m_functions.push_back(func);
|
||||||
else
|
else
|
||||||
m_paused.append(func);
|
m_paused.push_back(func);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -780,7 +780,7 @@ const char *CForward::GetForwardName()
|
|||||||
|
|
||||||
unsigned int CForward::GetFunctionCount()
|
unsigned int CForward::GetFunctionCount()
|
||||||
{
|
{
|
||||||
return m_functions.length();
|
return m_functions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecType CForward::GetExecType()
|
ExecType CForward::GetExecType()
|
||||||
|
@ -36,7 +36,7 @@ SafeFrameIterator::SafeFrameIterator(IFrameIterator *it)
|
|||||||
while (!it->Done())
|
while (!it->Done())
|
||||||
{
|
{
|
||||||
FrameInfo info = FrameInfo(it);
|
FrameInfo info = FrameInfo(it);
|
||||||
frames.append(info);
|
frames.push_back(info);
|
||||||
it->Next();
|
it->Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ SafeFrameIterator::SafeFrameIterator(IFrameIterator *it)
|
|||||||
|
|
||||||
bool SafeFrameIterator::Done() const
|
bool SafeFrameIterator::Done() const
|
||||||
{
|
{
|
||||||
return current >= frames.length();
|
return current >= frames.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafeFrameIterator::Next()
|
bool SafeFrameIterator::Next()
|
||||||
@ -77,7 +77,7 @@ const char *SafeFrameIterator::FunctionName() const
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return frames[current].FunctionName.chars();
|
return frames[current].FunctionName.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *SafeFrameIterator::FilePath() const
|
const char *SafeFrameIterator::FilePath() const
|
||||||
@ -87,5 +87,5 @@ const char *SafeFrameIterator::FilePath() const
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return frames[current].FilePath.chars();
|
return frames[current].FilePath.c_str();
|
||||||
}
|
}
|
||||||
|
@ -48,16 +48,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
struct FrameInfo
|
struct FrameInfo
|
||||||
{
|
{
|
||||||
ke::AString FunctionName;
|
std::string FunctionName;
|
||||||
ke::AString FilePath;
|
std::string FilePath;
|
||||||
unsigned LineNumber;
|
unsigned LineNumber;
|
||||||
|
|
||||||
FrameInfo(IFrameIterator *it)
|
FrameInfo(IFrameIterator *it)
|
||||||
{
|
{
|
||||||
LineNumber = it->LineNumber();
|
LineNumber = it->LineNumber();
|
||||||
|
|
||||||
FunctionName = it->FunctionName();
|
if (it->FunctionName())
|
||||||
FilePath = it->FilePath();
|
FunctionName = it->FunctionName();
|
||||||
|
if (it->FilePath())
|
||||||
|
FilePath = it->FilePath();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,5 +75,5 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
size_t current;
|
size_t current;
|
||||||
ke::Vector<FrameInfo> frames;
|
std::vector<FrameInfo> frames;
|
||||||
};
|
};
|
||||||
|
@ -85,15 +85,12 @@ static const char *g_pParseEngine = NULL;
|
|||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
#if defined PLATFORM_WINDOWS
|
||||||
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_SERVER_BINARY "server.dll"
|
|
||||||
#elif defined PLATFORM_LINUX
|
#elif defined PLATFORM_LINUX
|
||||||
#define PLATFORM_NAME "linux" PLATFORM_ARCH_SUFFIX
|
#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_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
|
#elif defined PLATFORM_APPLE
|
||||||
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_SERVER_BINARY "server.dylib"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct TempSigInfo
|
struct TempSigInfo
|
||||||
@ -153,6 +150,23 @@ static inline bool IsPlatformCompatible(const char *platform, bool *hadPrimaryMa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline time_t GetFileModTime(const char *path)
|
||||||
|
{
|
||||||
|
char filepath[PLATFORM_MAX_PATH];
|
||||||
|
g_pSM->BuildPath(Path_SM, filepath, sizeof(filepath), "gamedata/%s.txt", path);
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
struct _stat64 s;
|
||||||
|
if (_stat64(filepath, &s) != 0)
|
||||||
|
#elif defined PLATFORM_POSIX
|
||||||
|
struct stat s;
|
||||||
|
if (stat(filepath, &s) != 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return s.st_mtime;
|
||||||
|
}
|
||||||
|
|
||||||
CGameConfig::CGameConfig(const char *file, const char *engine)
|
CGameConfig::CGameConfig(const char *file, const char *engine)
|
||||||
{
|
{
|
||||||
strncopy(m_File, file, sizeof(m_File));
|
strncopy(m_File, file, sizeof(m_File));
|
||||||
@ -160,6 +174,8 @@ CGameConfig::CGameConfig(const char *file, const char *engine)
|
|||||||
m_CustomLevel = 0;
|
m_CustomLevel = 0;
|
||||||
m_CustomHandler = NULL;
|
m_CustomHandler = NULL;
|
||||||
|
|
||||||
|
m_ModTime = GetFileModTime(file);
|
||||||
|
|
||||||
if (!engine)
|
if (!engine)
|
||||||
m_pEngine = bridge->GetSourceEngineName();
|
m_pEngine = bridge->GetSourceEngineName();
|
||||||
else
|
else
|
||||||
@ -206,7 +222,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
{
|
{
|
||||||
bShouldBeReadingDefault = true;
|
bShouldBeReadingDefault = true;
|
||||||
m_ParseState = PSTATE_GAMEDEFS;
|
m_ParseState = PSTATE_GAMEDEFS;
|
||||||
strncopy(m_Game, name, sizeof(m_Game));
|
m_Game = name;
|
||||||
} else {
|
} else {
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
}
|
}
|
||||||
@ -222,7 +238,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
{
|
{
|
||||||
m_ParseState = PSTATE_GAMEDEFS_KEYS;
|
m_ParseState = PSTATE_GAMEDEFS_KEYS;
|
||||||
}
|
}
|
||||||
else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
|
else if ((strcmp(name, "#supported") == 0) && (m_Game == "#default"))
|
||||||
{
|
{
|
||||||
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
|
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
|
||||||
/* Ignore this section unless we get a game. */
|
/* Ignore this section unless we get a game. */
|
||||||
@ -261,23 +277,23 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_KEYS:
|
case PSTATE_GAMEDEFS_KEYS:
|
||||||
{
|
{
|
||||||
strncopy(m_Key, name, sizeof(m_Key));
|
m_Key = name;
|
||||||
m_ParseState = PSTATE_GAMEDEFS_KEYS_PLATFORM;
|
m_ParseState = PSTATE_GAMEDEFS_KEYS_PLATFORM;
|
||||||
matched_platform = false;
|
matched_platform = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_OFFSETS:
|
case PSTATE_GAMEDEFS_OFFSETS:
|
||||||
{
|
{
|
||||||
m_Prop[0] = '\0';
|
m_Prop.clear();
|
||||||
m_Class[0] = '\0';
|
m_Class.clear();
|
||||||
strncopy(m_offset, name, sizeof(m_offset));
|
m_offset = name;
|
||||||
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
|
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
|
||||||
matched_platform = false;
|
matched_platform = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_SIGNATURES:
|
case PSTATE_GAMEDEFS_SIGNATURES:
|
||||||
{
|
{
|
||||||
strncopy(m_offset, name, sizeof(m_offset));
|
m_offset = name;
|
||||||
s_TempSig.Reset();
|
s_TempSig.Reset();
|
||||||
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
|
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
|
||||||
matched_platform = false;
|
matched_platform = false;
|
||||||
@ -296,7 +312,10 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
|
char binName[64];
|
||||||
|
bridge->FormatSourceBinaryName(name, binName, sizeof(binName));
|
||||||
|
|
||||||
|
g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/%s", binName);
|
||||||
if ((fp = fopen(path, "rb")) == NULL)
|
if ((fp = fopen(path, "rb")) == NULL)
|
||||||
{
|
{
|
||||||
ke::SafeSprintf(error, sizeof(error), "Could not open binary: %s", path);
|
ke::SafeSprintf(error, sizeof(error), "Could not open binary: %s", path);
|
||||||
@ -319,7 +338,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
if (error[0] != '\0')
|
if (error[0] != '\0')
|
||||||
{
|
{
|
||||||
m_IgnoreLevel = 1;
|
m_IgnoreLevel = 1;
|
||||||
logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile);
|
logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game.c_str(), m_CurFile);
|
||||||
logger->LogError("[SM] %s", error);
|
logger->LogError("[SM] %s", error);
|
||||||
} else {
|
} else {
|
||||||
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
|
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
|
||||||
@ -334,12 +353,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_ADDRESSES:
|
case PSTATE_GAMEDEFS_ADDRESSES:
|
||||||
{
|
{
|
||||||
m_Address[0] = '\0';
|
m_Address.clear();
|
||||||
m_AddressSignature[0] = '\0';
|
m_AddressSignature.clear();
|
||||||
m_AddressReadCount = 0;
|
m_AddressReadCount = 0;
|
||||||
m_AddressLastIsOffset = false;
|
m_AddressLastIsOffset = false;
|
||||||
|
|
||||||
strncopy(m_Address, name, sizeof(m_Address));
|
m_Address = name;
|
||||||
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS;
|
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -355,7 +374,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0 &&
|
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0 &&
|
||||||
strcmp(name, "linux64") != 0 && strcmp(name, "windows64") != 0 && strcmp(name, "mac64") != 0)
|
strcmp(name, "linux64") != 0 && strcmp(name, "windows64") != 0 && strcmp(name, "mac64") != 0)
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address, m_CurFile);
|
logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address.c_str(), m_CurFile);
|
||||||
logger->LogError("[SM] Unrecognized platform \"%s\"", name);
|
logger->LogError("[SM] Unrecognized platform \"%s\"", name);
|
||||||
}
|
}
|
||||||
m_IgnoreLevel = 1;
|
m_IgnoreLevel = 1;
|
||||||
@ -392,21 +411,21 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
{
|
{
|
||||||
if (strcmp(key, "class") == 0)
|
if (strcmp(key, "class") == 0)
|
||||||
{
|
{
|
||||||
strncopy(m_Class, value, sizeof(m_Class));
|
m_Class = value;
|
||||||
} else if (strcmp(key, "prop") == 0) {
|
} else if (strcmp(key, "prop") == 0) {
|
||||||
strncopy(m_Prop, value, sizeof(m_Prop));
|
m_Prop = value;
|
||||||
} else if (IsPlatformCompatible(key, &matched_platform)) {
|
} else if (IsPlatformCompatible(key, &matched_platform)) {
|
||||||
m_Offsets.replace(m_offset, atoi(value));
|
m_Offsets.replace(m_offset.c_str(), static_cast<int>(strtol(value, NULL, 0)));
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
|
||||||
ke::AString vstr(value);
|
std::string vstr(value);
|
||||||
m_Keys.replace(key, ke::Move(vstr));
|
m_Keys.replace(key, std::move(vstr));
|
||||||
}
|
}
|
||||||
else if (m_ParseState == PSTATE_GAMEDEFS_KEYS_PLATFORM) {
|
else if (m_ParseState == PSTATE_GAMEDEFS_KEYS_PLATFORM) {
|
||||||
if (IsPlatformCompatible(key, &matched_platform))
|
if (IsPlatformCompatible(key, &matched_platform))
|
||||||
{
|
{
|
||||||
ke::AString vstr(value);
|
std::string vstr(value);
|
||||||
m_Keys.replace(m_Key, ke::Move(vstr));
|
m_Keys.replace(m_Key.c_str(), std::move(vstr));
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
|
||||||
if (strcmp(key, "game") == 0)
|
if (strcmp(key, "game") == 0)
|
||||||
@ -457,7 +476,7 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
int limit = sizeof(m_AddressRead)/sizeof(m_AddressRead[0]);
|
int limit = sizeof(m_AddressRead)/sizeof(m_AddressRead[0]);
|
||||||
if (m_AddressLastIsOffset)
|
if (m_AddressLastIsOffset)
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address, m_CurFile);
|
logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address.c_str(), m_CurFile);
|
||||||
}
|
}
|
||||||
else if (m_AddressReadCount < limit)
|
else if (m_AddressReadCount < limit)
|
||||||
{
|
{
|
||||||
@ -465,15 +484,15 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
{
|
{
|
||||||
m_AddressLastIsOffset = true;
|
m_AddressLastIsOffset = true;
|
||||||
}
|
}
|
||||||
m_AddressRead[m_AddressReadCount] = atoi(value);
|
m_AddressRead[m_AddressReadCount] = static_cast<int>(strtol(value, NULL, 0));
|
||||||
m_AddressReadCount++;
|
m_AddressReadCount++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address, limit, m_CurFile);
|
logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address.c_str(), limit, m_CurFile);
|
||||||
}
|
}
|
||||||
} else if (strcmp(key, "signature") == 0) {
|
} else if (strcmp(key, "signature") == 0) {
|
||||||
strncopy(m_AddressSignature, value, sizeof(m_AddressSignature));
|
m_AddressSignature = value;
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
|
||||||
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
|
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
|
||||||
@ -529,25 +548,24 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
||||||
{
|
{
|
||||||
/* Parse the offset... */
|
/* Parse the offset... */
|
||||||
if (m_Class[0] != '\0'
|
if (!m_Class.empty() && !m_Prop.empty())
|
||||||
&& m_Prop[0] != '\0')
|
|
||||||
{
|
{
|
||||||
SendProp *pProp = gamehelpers->FindInSendTable(m_Class, m_Prop);
|
SendProp *pProp = gamehelpers->FindInSendTable(m_Class.c_str(), m_Prop.c_str());
|
||||||
if (pProp)
|
if (pProp)
|
||||||
{
|
{
|
||||||
int val = gamehelpers->GetSendPropOffset(pProp);
|
int val = gamehelpers->GetSendPropOffset(pProp);
|
||||||
m_Offsets.replace(m_offset, val);
|
m_Offsets.replace(m_offset.c_str(), val);
|
||||||
m_Props.replace(m_offset, pProp);
|
m_Props.replace(m_offset.c_str(), pProp);
|
||||||
} else {
|
} else {
|
||||||
/* Check if it's a non-default game and no offsets exist */
|
/* Check if it's a non-default game and no offsets exist */
|
||||||
if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
|
if ((m_Game != "*" && m_Game != "#default")
|
||||||
&& (!m_Offsets.retrieve(m_offset)))
|
&& (!m_Offsets.retrieve(m_offset.c_str())))
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
|
logger->LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
|
||||||
m_Class,
|
m_Class.c_str(),
|
||||||
m_Prop,
|
m_Prop.c_str(),
|
||||||
m_CurFile,
|
m_CurFile,
|
||||||
m_Game);
|
m_Game.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,7 +673,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Sigs.replace(m_offset, final_addr);
|
m_Sigs.replace(m_offset.c_str(), final_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
|
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
|
||||||
@ -671,10 +689,10 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
{
|
{
|
||||||
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES;
|
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES;
|
||||||
|
|
||||||
if (m_Address[0] != '\0' && m_AddressSignature[0] != '\0')
|
if (!m_Address.empty() && !m_AddressSignature.empty())
|
||||||
{
|
{
|
||||||
AddressConf addrConf(m_AddressSignature, sizeof(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset);
|
AddressConf addrConf(std::move(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset);
|
||||||
m_Addresses.replace(m_Address, addrConf);
|
m_Addresses.replace(m_Address.c_str(), addrConf);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -792,7 +810,10 @@ public:
|
|||||||
(!had_game && matched_engine) ||
|
(!had_game && matched_engine) ||
|
||||||
(matched_engine && matched_game))
|
(matched_engine && matched_game))
|
||||||
{
|
{
|
||||||
fileList->push_back(cur_file);
|
if (fileList->find(cur_file) == fileList->end())
|
||||||
|
{
|
||||||
|
fileList->push_back(cur_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state = MSTATE_MAIN;
|
state = MSTATE_MAIN;
|
||||||
}
|
}
|
||||||
@ -1001,10 +1022,10 @@ bool CGameConfig::GetOffset(const char *key, int *value)
|
|||||||
|
|
||||||
const char *CGameConfig::GetKeyValue(const char *key)
|
const char *CGameConfig::GetKeyValue(const char *key)
|
||||||
{
|
{
|
||||||
StringHashMap<ke::AString>::Result r = m_Keys.find(key);
|
StringHashMap<std::string>::Result r = m_Keys.find(key);
|
||||||
if (!r.found())
|
if (!r.found())
|
||||||
return NULL;
|
return NULL;
|
||||||
return r->value.chars();
|
return r->value.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
//memory addresses below 0x10000 are automatically considered invalid for dereferencing
|
//memory addresses below 0x10000 are automatically considered invalid for dereferencing
|
||||||
@ -1022,7 +1043,7 @@ bool CGameConfig::GetAddress(const char *key, void **retaddr)
|
|||||||
AddressConf &addrConf = r->value;
|
AddressConf &addrConf = r->value;
|
||||||
|
|
||||||
void *addr;
|
void *addr;
|
||||||
if (!GetMemSig(addrConf.signatureName, &addr))
|
if (!GetMemSig(addrConf.signatureName.c_str(), &addr))
|
||||||
{
|
{
|
||||||
*retaddr = NULL;
|
*retaddr = NULL;
|
||||||
return false;
|
return false;
|
||||||
@ -1055,11 +1076,11 @@ static inline unsigned minOf(unsigned a, unsigned b)
|
|||||||
return a <= b ? a : b;
|
return a <= b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGameConfig::AddressConf::AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset)
|
CGameConfig::AddressConf::AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset)
|
||||||
{
|
{
|
||||||
unsigned readLimit = minOf(readCount, sizeof(this->read) / sizeof(this->read[0]));
|
unsigned readLimit = minOf(readCount, sizeof(this->read) / sizeof(this->read[0]));
|
||||||
|
|
||||||
strncopy(signatureName, sigName, sizeof(signatureName) / sizeof(signatureName[0]));
|
this->signatureName = std::move(sigName);
|
||||||
this->readCount = readLimit;
|
this->readCount = readLimit;
|
||||||
memcpy(&this->read[0], read, sizeof(this->read[0])*readLimit);
|
memcpy(&this->read[0], read, sizeof(this->read[0])*readLimit);
|
||||||
|
|
||||||
@ -1132,9 +1153,17 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon
|
|||||||
|
|
||||||
if (m_Lookup.retrieve(file, &pConfig))
|
if (m_Lookup.retrieve(file, &pConfig))
|
||||||
{
|
{
|
||||||
|
bool ret = true;
|
||||||
|
time_t modtime = GetFileModTime(file);
|
||||||
|
if (pConfig->m_ModTime != modtime)
|
||||||
|
{
|
||||||
|
pConfig->m_ModTime = modtime;
|
||||||
|
ret = pConfig->Reparse(error, maxlength);
|
||||||
|
}
|
||||||
|
|
||||||
pConfig->AddRef();
|
pConfig->AddRef();
|
||||||
*_pConfig = pConfig;
|
*_pConfig = pConfig;
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pConfig = new CGameConfig(file);
|
pConfig = new CGameConfig(file);
|
||||||
|
@ -81,16 +81,16 @@ private:
|
|||||||
char m_CurFile[PLATFORM_MAX_PATH];
|
char m_CurFile[PLATFORM_MAX_PATH];
|
||||||
StringHashMap<int> m_Offsets;
|
StringHashMap<int> m_Offsets;
|
||||||
StringHashMap<SendProp *> m_Props;
|
StringHashMap<SendProp *> m_Props;
|
||||||
StringHashMap<ke::AString> m_Keys;
|
StringHashMap<std::string> m_Keys;
|
||||||
StringHashMap<void *> m_Sigs;
|
StringHashMap<void *> m_Sigs;
|
||||||
/* Parse states */
|
/* Parse states */
|
||||||
int m_ParseState;
|
int m_ParseState;
|
||||||
unsigned int m_IgnoreLevel;
|
unsigned int m_IgnoreLevel;
|
||||||
char m_Class[64];
|
std::string m_Class;
|
||||||
char m_Prop[64];
|
std::string m_Prop;
|
||||||
char m_offset[64];
|
std::string m_offset;
|
||||||
char m_Game[256];
|
std::string m_Game;
|
||||||
char m_Key[64];
|
std::string m_Key;
|
||||||
bool bShouldBeReadingDefault;
|
bool bShouldBeReadingDefault;
|
||||||
bool had_game;
|
bool had_game;
|
||||||
bool matched_game;
|
bool matched_game;
|
||||||
@ -105,24 +105,25 @@ private:
|
|||||||
/* Support for reading Addresses */
|
/* Support for reading Addresses */
|
||||||
struct AddressConf
|
struct AddressConf
|
||||||
{
|
{
|
||||||
char signatureName[64];
|
std::string signatureName;
|
||||||
int readCount;
|
int readCount;
|
||||||
int read[8];
|
int read[8];
|
||||||
bool lastIsOffset;
|
bool lastIsOffset;
|
||||||
|
|
||||||
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset);
|
AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset);
|
||||||
|
|
||||||
AddressConf() {}
|
AddressConf() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
char m_Address[64];
|
std::string m_Address;
|
||||||
char m_AddressSignature[64];
|
std::string m_AddressSignature;
|
||||||
int m_AddressReadCount;
|
int m_AddressReadCount;
|
||||||
int m_AddressRead[8];
|
int m_AddressRead[8];
|
||||||
bool m_AddressLastIsOffset;
|
bool m_AddressLastIsOffset;
|
||||||
StringHashMap<AddressConf> m_Addresses;
|
StringHashMap<AddressConf> m_Addresses;
|
||||||
const char *m_pEngine;
|
const char *m_pEngine;
|
||||||
const char *m_pBaseEngine;
|
const char *m_pBaseEngine;
|
||||||
|
time_t m_ModTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameConfigManager :
|
class GameConfigManager :
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
@ -38,10 +39,20 @@
|
|||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <bridge/include/ILogger.h>
|
#include <bridge/include/ILogger.h>
|
||||||
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
#include <ISourceMod.h>
|
||||||
|
|
||||||
|
#include "sm_platform.h"
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
#include "sm_invalidparamhandler.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
HandleSystem g_HandleSys;
|
HandleSystem g_HandleSys;
|
||||||
|
|
||||||
QHandle *ignore_handle;
|
QHandle *ignore_handle;
|
||||||
|
extern ConVar *g_datetime_format;
|
||||||
|
|
||||||
inline HandleType_t TypeParent(HandleType_t type)
|
inline HandleType_t TypeParent(HandleType_t type)
|
||||||
{
|
{
|
||||||
@ -206,7 +217,7 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
|||||||
pType->dispatch = dispatch;
|
pType->dispatch = dispatch;
|
||||||
if (name && name[0] != '\0')
|
if (name && name[0] != '\0')
|
||||||
{
|
{
|
||||||
pType->name = new ke::AString(name);
|
pType->name = std::make_unique<std::string>(name);
|
||||||
m_TypeLookup.insert(name, pType);
|
m_TypeLookup.insert(name, pType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,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];
|
QHandle *pHandle = &m_Handles[handle];
|
||||||
|
|
||||||
assert(pHandle->set == false);
|
assert(pHandle->set == false);
|
||||||
@ -311,7 +344,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
|||||||
|
|
||||||
/* Create the hash value */
|
/* Create the hash value */
|
||||||
Handle_t hash = pHandle->serial;
|
Handle_t hash = pHandle->serial;
|
||||||
hash <<= 16;
|
hash <<= HANDLESYS_HANDLE_BITS;
|
||||||
hash |= handle;
|
hash |= handle;
|
||||||
|
|
||||||
/* Add a reference count to the type */
|
/* Add a reference count to the type */
|
||||||
@ -430,7 +463,7 @@ Handle_t HandleSystem::CreateHandleInt(HandleType_t type,
|
|||||||
|
|
||||||
pHandle->object = object;
|
pHandle->object = object;
|
||||||
pHandle->clone = 0;
|
pHandle->clone = 0;
|
||||||
|
pHandle->timestamp = g_pSM->GetAdjustedTime();
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +508,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
|||||||
unsigned int *in_index,
|
unsigned int *in_index,
|
||||||
bool ignoreFree)
|
bool ignoreFree)
|
||||||
{
|
{
|
||||||
unsigned int serial = (handle >> 16);
|
unsigned int serial = (handle >> HANDLESYS_HANDLE_BITS);
|
||||||
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
||||||
|
|
||||||
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
||||||
@ -631,7 +664,7 @@ Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
|
|||||||
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
unsigned int serial = (hndl >> 16);
|
unsigned int serial = (hndl >> HANDLESYS_HANDLE_BITS);
|
||||||
#endif
|
#endif
|
||||||
index = (hndl & HANDLESYS_HANDLE_MASK);
|
index = (hndl & HANDLESYS_HANDLE_MASK);
|
||||||
|
|
||||||
@ -655,6 +688,9 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
|||||||
|
|
||||||
QHandleType *pType = &m_Types[pHandle->type];
|
QHandleType *pType = &m_Types[pHandle->type];
|
||||||
|
|
||||||
|
if (pHandle->owner && pHandle->owner->num_handles > 0)
|
||||||
|
pHandle->owner->num_handles--;
|
||||||
|
|
||||||
if (pHandle->clone)
|
if (pHandle->clone)
|
||||||
{
|
{
|
||||||
/* If we're a clone, decrease the parent reference count */
|
/* If we're a clone, decrease the parent reference count */
|
||||||
@ -925,7 +961,7 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
|||||||
|
|
||||||
/* Remove it from the type cache. */
|
/* Remove it from the type cache. */
|
||||||
if (pType->name)
|
if (pType->name)
|
||||||
m_TypeLookup.remove(pType->name->chars());
|
m_TypeLookup.remove(pType->name->c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1014,6 +1050,8 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
|
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
|
||||||
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
|
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
|
||||||
|
|
||||||
|
const QHandle *oldest = nullptr;
|
||||||
|
const QHandle *newest = nullptr;
|
||||||
for (unsigned int i = 1; i <= m_HandleTail; ++i)
|
for (unsigned int i = 1; i <= m_HandleTail; ++i)
|
||||||
{
|
{
|
||||||
const QHandle &Handle = m_Handles[i];
|
const QHandle &Handle = m_Handles[i];
|
||||||
@ -1030,6 +1068,15 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
highest_index = ((Handle.type) + 1);
|
highest_index = ((Handle.type) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!oldest || oldest->timestamp > Handle.timestamp)
|
||||||
|
{
|
||||||
|
oldest = &Handle;
|
||||||
|
}
|
||||||
|
if (!newest || newest->timestamp < Handle.timestamp)
|
||||||
|
{
|
||||||
|
newest = &Handle;
|
||||||
|
}
|
||||||
|
|
||||||
if (Handle.clone != 0)
|
if (Handle.clone != 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -1051,13 +1098,39 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_Types[i].name)
|
if (m_Types[i].name)
|
||||||
pTypeName = m_Types[i].name->chars();
|
pTypeName = m_Types[i].name->c_str();
|
||||||
else
|
else
|
||||||
pTypeName = "ANON";
|
pTypeName = "ANON";
|
||||||
|
|
||||||
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
|
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *fmt = bridge->GetCvarString(g_datetime_format);
|
||||||
|
|
||||||
|
char oldstamp[256], newstamp[256]; // 256 should be more than enough
|
||||||
|
|
||||||
|
// scope for InvalidParameterHandler
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
InvalidParameterHandler p;
|
||||||
|
#endif
|
||||||
|
size_t written = strftime(oldstamp, sizeof(oldstamp), fmt, localtime(&oldest->timestamp));
|
||||||
|
if (!written)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(oldstamp, sizeof(oldstamp), "INVALID");
|
||||||
|
}
|
||||||
|
|
||||||
|
written = strftime(newstamp, sizeof(newstamp), fmt, localtime(&newest->timestamp));
|
||||||
|
if (!written)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(newstamp, sizeof(newstamp), "INVALID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
|
||||||
|
HANDLE_LOG_VERY_BAD("Oldest Living Handle: %s created at %s", m_Types[oldest->type].name->c_str(), oldstamp);
|
||||||
|
HANDLE_LOG_VERY_BAD("Newest Living Handle: %s created at %s", m_Types[newest->type].name->c_str(), newstamp);
|
||||||
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
|
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
|
||||||
delete [] pCount;
|
delete [] pCount;
|
||||||
|
|
||||||
@ -1081,8 +1154,10 @@ static void rep(const HandleReporter &fn, const char *fmt, ...)
|
|||||||
void HandleSystem::Dump(const HandleReporter &fn)
|
void HandleSystem::Dump(const HandleReporter &fn)
|
||||||
{
|
{
|
||||||
unsigned int total_size = 0;
|
unsigned int total_size = 0;
|
||||||
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
|
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", "Handle", "Owner", "Type", "Memory", "Time Created");
|
||||||
rep(fn, "--------------------------------------------------------------------------");
|
rep(fn, "---------------------------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
const char *fmt = bridge->GetCvarString(g_datetime_format);
|
||||||
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
||||||
{
|
{
|
||||||
if (m_Handles[i].set != HandleSet_Used)
|
if (m_Handles[i].set != HandleSet_Used)
|
||||||
@ -1090,12 +1165,12 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Get the index */
|
/* 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 */
|
/* Determine the owner */
|
||||||
const char *owner = "UNKNOWN";
|
const char *owner = "UNKNOWN";
|
||||||
if (m_Handles[i].owner)
|
if (m_Handles[i].owner)
|
||||||
{
|
{
|
||||||
IdentityToken_t *pOwner = m_Handles[i].owner;
|
IdentityToken_t *pOwner = m_Handles[i].owner;
|
||||||
if (pOwner == g_pCoreIdent)
|
if (pOwner == g_pCoreIdent)
|
||||||
{
|
{
|
||||||
owner = "CORE";
|
owner = "CORE";
|
||||||
@ -1131,7 +1206,7 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
|||||||
unsigned int parentIdx;
|
unsigned int parentIdx;
|
||||||
bool bresult;
|
bool bresult;
|
||||||
if (pType->name)
|
if (pType->name)
|
||||||
type = pType->name->chars();
|
type = pType->name->c_str();
|
||||||
|
|
||||||
if ((parentIdx = m_Handles[i].clone) != 0)
|
if ((parentIdx = m_Handles[i].clone) != 0)
|
||||||
{
|
{
|
||||||
@ -1150,19 +1225,33 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
|||||||
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
|
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char date[256]; // 256 should be more than enough
|
||||||
|
size_t written = 0;
|
||||||
|
// scope for InvalidParameterHandler
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
InvalidParameterHandler p;
|
||||||
|
#endif
|
||||||
|
written = strftime(date, sizeof(date), fmt, localtime(&m_Handles[i].timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!written)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(date, sizeof(date), "INVALID");
|
||||||
|
}
|
||||||
|
|
||||||
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|
||||||
|| !bresult)
|
|| !bresult)
|
||||||
{
|
{
|
||||||
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
|
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, "-1", date);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "%d", size);
|
ke::SafeSprintf(buffer, sizeof(buffer), "%d", size);
|
||||||
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
|
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, buffer, date);
|
||||||
total_size += size;
|
total_size += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
|
rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,22 +32,27 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||||
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||||
|
|
||||||
#include <IHandleSys.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sm_namehashset.h>
|
|
||||||
#include <amtl/am-autoptr.h>
|
#include <memory>
|
||||||
|
|
||||||
#include <amtl/am-string.h>
|
#include <amtl/am-string.h>
|
||||||
#include <amtl/am-function.h>
|
#include <amtl/am-function.h>
|
||||||
|
#include <IHandleSys.h>
|
||||||
|
#include <sm_namehashset.h>
|
||||||
#include "common_logic.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_TYPES (1<<9)
|
||||||
#define HANDLESYS_MAX_SUBTYPES 0xF
|
#define HANDLESYS_MAX_SUBTYPES 0xF
|
||||||
#define HANDLESYS_SUBTYPE_MASK 0xF
|
#define HANDLESYS_SUBTYPE_MASK 0xF
|
||||||
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
||||||
#define HANDLESYS_MAX_SERIALS 0xFFFF
|
#define HANDLESYS_SERIAL_BITS (32 - HANDLESYS_HANDLE_BITS)
|
||||||
#define HANDLESYS_SERIAL_MASK 0xFFFF0000
|
#define HANDLESYS_MAX_SERIALS (1 << HANDLESYS_SERIAL_BITS)
|
||||||
#define HANDLESYS_HANDLE_MASK 0x0000FFFF
|
#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
|
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
|
||||||
|
|
||||||
@ -88,6 +93,7 @@ struct QHandle
|
|||||||
bool access_special; /* Whether or not access rules are special or type-derived */
|
bool access_special; /* Whether or not access rules are special or type-derived */
|
||||||
bool is_destroying; /* Whether or not the handle is being destroyed */
|
bool is_destroying; /* Whether or not the handle is being destroyed */
|
||||||
HandleAccess sec; /* Security rules */
|
HandleAccess sec; /* Security rules */
|
||||||
|
time_t timestamp; /* Creation timestamp */
|
||||||
/* The following variables are unrelated to the Handle array, and used
|
/* The following variables are unrelated to the Handle array, and used
|
||||||
* as an inlined chain of information */
|
* as an inlined chain of information */
|
||||||
unsigned int freeID; /* ID of a free handle in the free handle chain */
|
unsigned int freeID; /* ID of a free handle in the free handle chain */
|
||||||
@ -105,7 +111,7 @@ struct QHandleType
|
|||||||
TypeAccess typeSec;
|
TypeAccess typeSec;
|
||||||
HandleAccess hndlSec;
|
HandleAccess hndlSec;
|
||||||
unsigned int opened;
|
unsigned int opened;
|
||||||
ke::AutoPtr<ke::AString> name;
|
std::unique_ptr<std::string> name;
|
||||||
|
|
||||||
static inline bool matches(const char *key, const QHandleType *type)
|
static inline bool matches(const char *key, const QHandleType *type)
|
||||||
{
|
{
|
||||||
@ -117,7 +123,7 @@ struct QHandleType
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ke::Lambda<void(const char *)> HandleReporter;
|
typedef ke::Function<void(const char *)> HandleReporter;
|
||||||
|
|
||||||
class HandleSystem :
|
class HandleSystem :
|
||||||
public IHandleSys
|
public IHandleSys
|
||||||
|
@ -319,7 +319,7 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
char buff[PLATFORM_MAX_PATH];
|
char buff[PLATFORM_MAX_PATH];
|
||||||
ke::SafeSprintf(buff, sizeof(buff), "%04d%02d%02d", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
ke::SafeSprintf(buff, sizeof(buff), "%04d%02d%02d", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||||
|
|
||||||
ke::AString currentDate(buff);
|
std::string currentDate(buff);
|
||||||
|
|
||||||
if (m_Mode == LoggingMode_PerMap)
|
if (m_Mode == LoggingMode_PerMap)
|
||||||
{
|
{
|
||||||
@ -327,7 +327,7 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
{
|
{
|
||||||
for (size_t iter = 0; iter < static_cast<size_t>(-1); ++iter)
|
for (size_t iter = 0; iter < static_cast<size_t>(-1); ++iter)
|
||||||
{
|
{
|
||||||
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.chars(), iter);
|
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.c_str(), iter);
|
||||||
if (!libsys->IsPathFile(buff))
|
if (!libsys->IsPathFile(buff))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -336,12 +336,12 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.chars());
|
ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.chars());
|
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_NormalFileName.compare(buff))
|
if (m_NormalFileName.compare(buff))
|
||||||
@ -353,11 +353,11 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
{
|
{
|
||||||
if (bLevelChange)
|
if (bLevelChange)
|
||||||
{
|
{
|
||||||
LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.chars());
|
LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.chars());
|
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.c_str());
|
||||||
if (bLevelChange || m_ErrorFileName.compare(buff))
|
if (bLevelChange || m_ErrorFileName.compare(buff))
|
||||||
{
|
{
|
||||||
_CloseError();
|
_CloseError();
|
||||||
@ -369,7 +369,7 @@ FILE *Logger::_OpenNormal()
|
|||||||
{
|
{
|
||||||
_UpdateFiles();
|
_UpdateFiles();
|
||||||
|
|
||||||
FILE *pFile = fopen(m_NormalFileName.chars(), "a+");
|
FILE *pFile = fopen(m_NormalFileName.c_str(), "a+");
|
||||||
if (pFile == NULL)
|
if (pFile == NULL)
|
||||||
{
|
{
|
||||||
_LogFatalOpen(m_NormalFileName);
|
_LogFatalOpen(m_NormalFileName);
|
||||||
@ -383,7 +383,7 @@ FILE *Logger::_OpenNormal()
|
|||||||
char date[32];
|
char date[32];
|
||||||
|
|
||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||||
fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.chars(), SOURCEMOD_VERSION);
|
fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.c_str(), SOURCEMOD_VERSION);
|
||||||
m_DamagedNormalFile = true;
|
m_DamagedNormalFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ FILE *Logger::_OpenError()
|
|||||||
{
|
{
|
||||||
_UpdateFiles();
|
_UpdateFiles();
|
||||||
|
|
||||||
FILE *pFile = fopen(m_ErrorFileName.chars(), "a+");
|
FILE *pFile = fopen(m_ErrorFileName.c_str(), "a+");
|
||||||
if (pFile == NULL)
|
if (pFile == NULL)
|
||||||
{
|
{
|
||||||
_LogFatalOpen(m_ErrorFileName);
|
_LogFatalOpen(m_ErrorFileName);
|
||||||
@ -409,7 +409,7 @@ FILE *Logger::_OpenError()
|
|||||||
char date[32];
|
char date[32];
|
||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||||
fprintf(pFile, "L %s: SourceMod error session started\n", date);
|
fprintf(pFile, "L %s: SourceMod error session started\n", date);
|
||||||
fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.chars(), m_ErrorFileName.chars());
|
fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.c_str(), m_ErrorFileName.c_str());
|
||||||
m_DamagedErrorFile = true;
|
m_DamagedErrorFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,11 +423,11 @@ FILE *Logger::_OpenFatal()
|
|||||||
return fopen(path, "at");
|
return fopen(path, "at");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::_LogFatalOpen(ke::AString &str)
|
void Logger::_LogFatalOpen(std::string &str)
|
||||||
{
|
{
|
||||||
char error[255];
|
char error[255];
|
||||||
libsys->GetPlatformError(error, sizeof(error));
|
libsys->GetPlatformError(error, sizeof(error));
|
||||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.chars());
|
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.c_str());
|
||||||
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,13 +92,13 @@ private:
|
|||||||
FILE *_OpenError();
|
FILE *_OpenError();
|
||||||
FILE *_OpenFatal();
|
FILE *_OpenFatal();
|
||||||
|
|
||||||
void _LogFatalOpen(ke::AString &str);
|
void _LogFatalOpen(std::string &str);
|
||||||
void _PrintToGameLog(const char *fmt, va_list ap);
|
void _PrintToGameLog(const char *fmt, va_list ap);
|
||||||
void _UpdateFiles(bool bLevelChange = false);
|
void _UpdateFiles(bool bLevelChange = false);
|
||||||
private:
|
private:
|
||||||
ke::AString m_NormalFileName;
|
std::string m_NormalFileName;
|
||||||
ke::AString m_ErrorFileName;
|
std::string m_ErrorFileName;
|
||||||
ke::AString m_CurrentMapName;
|
std::string m_CurrentMapName;
|
||||||
|
|
||||||
int m_Day;
|
int m_Day;
|
||||||
|
|
||||||
|
131
core/logic/LumpManager.cpp
Normal file
131
core/logic/LumpManager.cpp
Normal file
@ -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();
|
||||||
|
}
|
116
core/logic/LumpManager.h
Normal file
116
core/logic/LumpManager.h
Normal file
@ -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_
|
@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;
|
|||||||
|
|
||||||
MemoryUtils::MemoryUtils()
|
MemoryUtils::MemoryUtils()
|
||||||
{
|
{
|
||||||
|
m_InfoMap.init();
|
||||||
#ifdef PLATFORM_APPLE
|
#ifdef PLATFORM_APPLE
|
||||||
|
|
||||||
task_dyld_info_data_t dyld_info;
|
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)
|
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||||
{
|
{
|
||||||
DynLibInfo lib;
|
const DynLibInfo* lib = nullptr;
|
||||||
bool found;
|
|
||||||
char *ptr, *end;
|
|
||||||
|
|
||||||
memset(&lib, 0, sizeof(DynLibInfo));
|
if ((lib = GetLibraryInfo(libPtr)) == nullptr)
|
||||||
|
|
||||||
if (!GetLibraryInfo(libPtr, lib))
|
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
// Search in the original unaltered state of the binary.
|
||||||
end = ptr + lib.memorySize - len;
|
char *start = lib->originalCopy.get();
|
||||||
|
char *ptr = start;
|
||||||
|
char *end = ptr + lib->memorySize - len;
|
||||||
|
|
||||||
|
bool found;
|
||||||
while (ptr < end)
|
while (ptr < end)
|
||||||
{
|
{
|
||||||
found = true;
|
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)
|
if (found)
|
||||||
return ptr;
|
return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start);
|
||||||
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -116,6 +117,8 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
{
|
{
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
/* Add this this library into the cache */
|
||||||
|
GetLibraryInfo(handle);
|
||||||
return GetProcAddress((HMODULE)handle, symbol);
|
return GetProcAddress((HMODULE)handle, symbol);
|
||||||
|
|
||||||
#elif defined PLATFORM_LINUX
|
#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 we don't have a symbol table for this library, then create one */
|
||||||
if (table == NULL)
|
if (table == NULL)
|
||||||
{
|
{
|
||||||
@ -325,6 +331,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
/* Uh oh, we couldn't find a matching handle */
|
/* Uh oh, we couldn't find a matching handle */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add this this library into the cache */
|
||||||
|
GetLibraryInfo((void *)dlbase);
|
||||||
|
|
||||||
/* See if we already have a symbol table for this library */
|
/* See if we already have a symbol table for this library */
|
||||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
@ -429,21 +438,25 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr)
|
||||||
{
|
{
|
||||||
uintptr_t baseAddr;
|
uintptr_t baseAddr;
|
||||||
|
|
||||||
if (libPtr == NULL)
|
if (libPtr == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynLibInfo lib;
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
|
||||||
#ifdef PLATFORM_X86
|
#ifdef PLATFORM_X86
|
||||||
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386;
|
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386;
|
||||||
|
const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
|
||||||
#else
|
#else
|
||||||
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64;
|
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64;
|
||||||
|
const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MEMORY_BASIC_INFORMATION info;
|
MEMORY_BASIC_INFORMATION info;
|
||||||
@ -454,7 +467,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
||||||
@ -466,21 +479,21 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
opt = &pe->OptionalHeader;
|
opt = &pe->OptionalHeader;
|
||||||
|
|
||||||
/* Check PE magic and signature */
|
/* Check PE magic and signature */
|
||||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
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 */
|
/* Check architecture */
|
||||||
if (file->Machine != PE_FILE_MACHINE)
|
if (file->Machine != PE_FILE_MACHINE)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For our purposes, this must be a dynamic library */
|
/* For our purposes, this must be a dynamic library */
|
||||||
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, we can do this */
|
/* Finally, we can do this */
|
||||||
@ -507,12 +520,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
if (!dladdr(libPtr, &info))
|
if (!dladdr(libPtr, &info))
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.dli_fbase || !info.dli_fname)
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is for our insane sanity checks :o */
|
/* This is for our insane sanity checks :o */
|
||||||
@ -522,31 +535,31 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
/* Check ELF magic */
|
/* Check ELF magic */
|
||||||
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check ELF version */
|
/* Check ELF version */
|
||||||
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check ELF endianness */
|
/* Check ELF endianness */
|
||||||
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
|
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check ELF architecture */
|
/* Check ELF architecture */
|
||||||
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
|
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 */
|
/* For our purposes, this must be a dynamic library/shared object */
|
||||||
if (file->e_type != ET_DYN)
|
if (file->e_type != ET_DYN)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
phdrCount = file->e_phnum;
|
phdrCount = file->e_phnum;
|
||||||
@ -596,12 +609,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
if (!dladdr(libPtr, &info))
|
if (!dladdr(libPtr, &info))
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.dli_fbase || !info.dli_fname)
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is for our insane sanity checks :o */
|
/* This is for our insane sanity checks :o */
|
||||||
@ -611,19 +624,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
/* Check Mach-O magic */
|
/* Check Mach-O magic */
|
||||||
if (file->magic != MACH_MAGIC)
|
if (file->magic != MACH_MAGIC)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check architecture */
|
/* Check architecture */
|
||||||
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
|
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For our purposes, this must be a dynamic library */
|
/* For our purposes, this must be a dynamic library */
|
||||||
if (file->filetype != MH_DYLIB)
|
if (file->filetype != MH_DYLIB)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_count = file->ncmds;
|
cmd_count = file->ncmds;
|
||||||
@ -644,5 +657,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
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 "common_logic.h"
|
||||||
#include <IMemoryUtils.h>
|
#include <IMemoryUtils.h>
|
||||||
|
#include <am-hashmap.h>
|
||||||
|
#include <memory>
|
||||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include "sm_symtable.h"
|
#include "sm_symtable.h"
|
||||||
@ -49,6 +51,7 @@ struct DynLibInfo
|
|||||||
{
|
{
|
||||||
void *baseAddress;
|
void *baseAddress;
|
||||||
size_t memorySize;
|
size_t memorySize;
|
||||||
|
std::unique_ptr<char[]> originalCopy;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
#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 *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||||
void *ResolveSymbol(void *handle, const char *symbol);
|
void *ResolveSymbol(void *handle, const char *symbol);
|
||||||
public:
|
public:
|
||||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
const DynLibInfo *GetLibraryInfo(const void *libPtr);
|
||||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
private:
|
private:
|
||||||
CVector<LibSymbolTable *> m_SymTables;
|
CVector<LibSymbolTable *> m_SymTables;
|
||||||
@ -83,6 +86,8 @@ private:
|
|||||||
SInt32 m_OSXMinor;
|
SInt32 m_OSXMinor;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
|
||||||
|
LibraryInfoMap m_InfoMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MemoryUtils g_MemUtils;
|
extern MemoryUtils g_MemUtils;
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <IShareSys.h>
|
#include <IShareSys.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <am-autoptr.h>
|
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <am-utility.h>
|
#include <am-utility.h>
|
||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
@ -47,16 +46,14 @@ struct FakeNative
|
|||||||
FakeNative(const char *name, IPluginFunction *fun)
|
FakeNative(const char *name, IPluginFunction *fun)
|
||||||
: name(name),
|
: name(name),
|
||||||
ctx(fun->GetParentContext()),
|
ctx(fun->GetParentContext()),
|
||||||
call(fun),
|
call(fun)
|
||||||
gate(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~FakeNative();
|
|
||||||
|
|
||||||
ke::AString name;
|
std::string name;
|
||||||
IPluginContext *ctx;
|
IPluginContext *ctx;
|
||||||
IPluginFunction *call;
|
IPluginFunction *call;
|
||||||
SPVM_NATIVE_FUNC gate;
|
ke::RefPtr<INativeCallback> wrapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native : public ke::Refcounted<Native>
|
struct Native : public ke::Refcounted<Native>
|
||||||
@ -64,31 +61,25 @@ struct Native : public ke::Refcounted<Native>
|
|||||||
Native(CNativeOwner *owner, const sp_nativeinfo_t *native)
|
Native(CNativeOwner *owner, const sp_nativeinfo_t *native)
|
||||||
: owner(owner),
|
: owner(owner),
|
||||||
native(native),
|
native(native),
|
||||||
fake(NULL)
|
fake(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Native(CNativeOwner *owner, FakeNative *fake)
|
Native(CNativeOwner *owner, std::unique_ptr<FakeNative>&& fake)
|
||||||
: owner(owner),
|
: owner(owner),
|
||||||
native(NULL),
|
native(nullptr),
|
||||||
fake(fake)
|
fake(std::move(fake))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CNativeOwner *owner;
|
CNativeOwner *owner;
|
||||||
const sp_nativeinfo_t *native;
|
const sp_nativeinfo_t *native;
|
||||||
ke::AutoPtr<FakeNative> fake;
|
std::unique_ptr<FakeNative> fake;
|
||||||
|
|
||||||
SPVM_NATIVE_FUNC func() const
|
|
||||||
{
|
|
||||||
if (native)
|
|
||||||
return native->func;
|
|
||||||
return fake->gate;
|
|
||||||
}
|
|
||||||
const char *name() const
|
const char *name() const
|
||||||
{
|
{
|
||||||
if (native)
|
if (native)
|
||||||
return native->name;
|
return native->name;
|
||||||
return fake->name.chars();
|
return fake->name.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool matches(const char *name, const ke::RefPtr<Native> &entry)
|
static inline bool matches(const char *name, const ke::RefPtr<Native> &entry)
|
||||||
|
@ -273,7 +273,10 @@ NativeInvoker::Invoke(cell_t *result)
|
|||||||
/* Make the call if we can */
|
/* Make the call if we can */
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
*result = native_->func()(context_, _temp_params);
|
if(native_->native)
|
||||||
|
*result = native_->native->func(context_, _temp_params);
|
||||||
|
else
|
||||||
|
*result = native_->fake->wrapper->Invoke(context_, _temp_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* i should be equal to the last valid parameter + 1 */
|
/* i should be equal to the last valid parameter + 1 */
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||||
|
|
||||||
#include <sp_vm_api.h>
|
#include <sp_vm_api.h>
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
#include <amtl/am-refcounting.h>
|
#include <amtl/am-refcounting.h>
|
||||||
#include "Native.h"
|
#include "Native.h"
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
|
|||||||
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
||||||
g_ShareSys.AddNativeToCache(this, native);
|
g_ShareSys.AddNativeToCache(this, native);
|
||||||
|
|
||||||
m_natives.append(natives);
|
m_natives.push_back(natives);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
|
void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
|
||||||
@ -90,14 +90,14 @@ void CNativeOwner::DropEverything()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Strip all of our natives from the cache */
|
/* Strip all of our natives from the cache */
|
||||||
for (size_t i = 0; i < m_natives.length(); i++) {
|
for (size_t i = 0; i < m_natives.size(); i++) {
|
||||||
const sp_nativeinfo_t *natives = m_natives[i];
|
const sp_nativeinfo_t *natives = m_natives[i];
|
||||||
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
||||||
g_ShareSys.ClearNativeFromCache(this, native->name);
|
g_ShareSys.ClearNativeFromCache(this, native->name);
|
||||||
}
|
}
|
||||||
m_natives.clear();
|
m_natives.clear();
|
||||||
|
|
||||||
for (size_t i = 0; i < m_fakes.length(); i++)
|
for (size_t i = 0; i < m_fakes.size(); i++)
|
||||||
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
|
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
|
||||||
m_fakes.clear();
|
m_fakes.clear();
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <sp_vm_types.h>
|
#include <sp_vm_types.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <am-linkedlist.h>
|
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include "Native.h"
|
#include "Native.h"
|
||||||
@ -80,8 +79,8 @@ protected:
|
|||||||
List<CPlugin *> m_Dependents;
|
List<CPlugin *> m_Dependents;
|
||||||
unsigned int m_nMarkSerial;
|
unsigned int m_nMarkSerial;
|
||||||
List<WeakNative> m_WeakRefs;
|
List<WeakNative> m_WeakRefs;
|
||||||
ke::Vector<const sp_nativeinfo_t *> m_natives;
|
std::vector<const sp_nativeinfo_t *> m_natives;
|
||||||
ke::Vector<ke::RefPtr<Native> > m_fakes;
|
std::vector<ke::RefPtr<Native> > m_fakes;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CNativeOwner g_CoreNatives;
|
extern CNativeOwner g_CoreNatives;
|
||||||
|
@ -45,7 +45,6 @@
|
|||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "frame_tasks.h"
|
#include "frame_tasks.h"
|
||||||
#include <amtl/am-string.h>
|
#include <amtl/am-string.h>
|
||||||
#include <amtl/am-linkedlist.h>
|
|
||||||
#include <bridge/include/IVEngineServerBridge.h>
|
#include <bridge/include/IVEngineServerBridge.h>
|
||||||
#include <bridge/include/CoreProvider.h>
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
|
||||||
@ -79,7 +78,7 @@ CPlugin::CPlugin(const char *file)
|
|||||||
|
|
||||||
memset(&m_info, 0, sizeof(m_info));
|
memset(&m_info, 0, sizeof(m_info));
|
||||||
|
|
||||||
m_pPhrases = g_Translator.CreatePhraseCollection();
|
m_pPhrases.reset(g_Translator.CreatePhraseCollection());
|
||||||
}
|
}
|
||||||
|
|
||||||
CPlugin::~CPlugin()
|
CPlugin::~CPlugin()
|
||||||
@ -227,7 +226,7 @@ bool CPlugin::SetProperty(const char *prop, void *ptr)
|
|||||||
|
|
||||||
IPluginRuntime *CPlugin::GetRuntime()
|
IPluginRuntime *CPlugin::GetRuntime()
|
||||||
{
|
{
|
||||||
return m_pRuntime;
|
return m_pRuntime.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::EvictWithError(PluginStatus status, const char *error_fmt, ...)
|
void CPlugin::EvictWithError(PluginStatus status, const char *error_fmt, ...)
|
||||||
@ -276,7 +275,7 @@ bool CPlugin::ReadInfo()
|
|||||||
sm_plugininfo_c_t *cinfo;
|
sm_plugininfo_c_t *cinfo;
|
||||||
cell_t local_addr;
|
cell_t local_addr;
|
||||||
|
|
||||||
auto update_field = [base](cell_t addr, ke::AString *dest) {
|
auto update_field = [base](cell_t addr, std::string *dest) {
|
||||||
const char* ptr;
|
const char* ptr;
|
||||||
if (base->LocalToString(addr, (char **)&ptr) == SP_ERROR_NONE)
|
if (base->LocalToString(addr, (char **)&ptr) == SP_ERROR_NONE)
|
||||||
*dest = ptr;
|
*dest = ptr;
|
||||||
@ -483,7 +482,7 @@ bool CPlugin::TryCompile()
|
|||||||
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", m_filename);
|
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", m_filename);
|
||||||
|
|
||||||
char loadmsg[255];
|
char loadmsg[255];
|
||||||
m_pRuntime = g_pSourcePawn2->LoadBinaryFromFile(fullpath, loadmsg, sizeof(loadmsg));
|
m_pRuntime.reset(g_pSourcePawn2->LoadBinaryFromFile(fullpath, loadmsg, sizeof(loadmsg)));
|
||||||
if (!m_pRuntime) {
|
if (!m_pRuntime) {
|
||||||
EvictWithError(Plugin_BadLoad, "Unable to load plugin (%s)", loadmsg);
|
EvictWithError(Plugin_BadLoad, "Unable to load plugin (%s)", loadmsg);
|
||||||
return false;
|
return false;
|
||||||
@ -524,11 +523,11 @@ PluginType CPlugin::GetType()
|
|||||||
|
|
||||||
const sm_plugininfo_t *CPlugin::GetPublicInfo()
|
const sm_plugininfo_t *CPlugin::GetPublicInfo()
|
||||||
{
|
{
|
||||||
m_info.author = info_author_.chars();
|
m_info.author = info_author_.c_str();
|
||||||
m_info.description = info_description_.chars();
|
m_info.description = info_description_.c_str();
|
||||||
m_info.name = info_name_.chars();
|
m_info.name = info_name_.c_str();
|
||||||
m_info.url = info_url_.chars();
|
m_info.url = info_url_.c_str();
|
||||||
m_info.version = info_version_.chars();
|
m_info.version = info_version_.c_str();
|
||||||
return &m_info;
|
return &m_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,7 +657,7 @@ time_t CPlugin::GetFileTimeStamp()
|
|||||||
|
|
||||||
IPhraseCollection *CPlugin::GetPhrases()
|
IPhraseCollection *CPlugin::GetPhrases()
|
||||||
{
|
{
|
||||||
return m_pPhrases;
|
return m_pPhrases.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::DependencyDropped(CPlugin *pOwner)
|
void CPlugin::DependencyDropped(CPlugin *pOwner)
|
||||||
@ -674,7 +673,7 @@ void CPlugin::DependencyDropped(CPlugin *pOwner)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int unbound = 0;
|
unsigned int unbound = 0;
|
||||||
for (size_t i = 0; i < pOwner->m_fakes.length(); i++)
|
for (size_t i = 0; i < pOwner->m_fakes.size(); i++)
|
||||||
{
|
{
|
||||||
ke::RefPtr<Native> entry(pOwner->m_fakes[i]);
|
ke::RefPtr<Native> entry(pOwner->m_fakes[i]);
|
||||||
|
|
||||||
@ -773,13 +772,13 @@ bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKEN
|
|||||||
if (!entry)
|
if (!entry)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_fakes.append(entry);
|
m_fakes.push_back(entry);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::BindFakeNativesTo(CPlugin *other)
|
void CPlugin::BindFakeNativesTo(CPlugin *other)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_fakes.length(); i++)
|
for (size_t i = 0; i < m_fakes.size(); i++)
|
||||||
g_ShareSys.BindNativeToPlugin(other, m_fakes[i]);
|
g_ShareSys.BindNativeToPlugin(other, m_fakes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,7 +789,7 @@ void CPlugin::BindFakeNativesTo(CPlugin *other)
|
|||||||
CPluginManager::CPluginIterator::CPluginIterator(ReentrantList<CPlugin *>& in)
|
CPluginManager::CPluginIterator::CPluginIterator(ReentrantList<CPlugin *>& in)
|
||||||
{
|
{
|
||||||
for (PluginIter iter(in); !iter.done(); iter.next())
|
for (PluginIter iter(in); !iter.done(); iter.next())
|
||||||
mylist.append(*iter);
|
mylist.push_back(*iter);
|
||||||
current = mylist.begin();
|
current = mylist.begin();
|
||||||
g_PluginSys.AddPluginsListener(this);
|
g_PluginSys.AddPluginsListener(this);
|
||||||
}
|
}
|
||||||
@ -847,11 +846,7 @@ CPluginManager::~CPluginManager()
|
|||||||
|
|
||||||
void CPluginManager::Shutdown()
|
void CPluginManager::Shutdown()
|
||||||
{
|
{
|
||||||
List<CPlugin *>::iterator iter;
|
UnloadAll();
|
||||||
|
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
|
|
||||||
UnloadPlugin(*iter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::LoadAll(const char *config_path, const char *plugins_path)
|
void CPluginManager::LoadAll(const char *config_path, const char *plugins_path)
|
||||||
@ -979,6 +974,20 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
|
|||||||
LoadRes res;
|
LoadRes res;
|
||||||
|
|
||||||
*wasloaded = false;
|
*wasloaded = false;
|
||||||
|
|
||||||
|
if (strstr(path, "..") != NULL)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(error, maxlength, "Cannot load plugins outside the \"plugins\" folder");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ext = libsys->GetFileExtension(path);
|
||||||
|
if (!ext || strcmp(ext, "smx") != 0)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(error, maxlength, "Plugin files must have the \".smx\" file extension");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((res=LoadPlugin(&pl, path, true, PluginType_MapUpdated)) == LoadRes_Failure)
|
if ((res=LoadPlugin(&pl, path, true, PluginType_MapUpdated)) == LoadRes_Failure)
|
||||||
{
|
{
|
||||||
ke::SafeStrcpy(error, maxlength, pl->GetErrorMsg());
|
ke::SafeStrcpy(error, maxlength, pl->GetErrorMsg());
|
||||||
@ -1033,7 +1042,7 @@ void CPluginManager::LoadAutoPlugin(const char *plugin)
|
|||||||
|
|
||||||
void CPluginManager::AddPlugin(CPlugin *pPlugin)
|
void CPluginManager::AddPlugin(CPlugin *pPlugin)
|
||||||
{
|
{
|
||||||
m_plugins.append(pPlugin);
|
m_plugins.push_back(pPlugin);
|
||||||
m_LoadLookup.insert(pPlugin->GetFilename(), pPlugin);
|
m_LoadLookup.insert(pPlugin->GetFilename(), pPlugin);
|
||||||
|
|
||||||
pPlugin->SetRegistered();
|
pPlugin->SetRegistered();
|
||||||
@ -1165,7 +1174,7 @@ bool CPlugin::ForEachExtVar(const ExtVarCallback& callback)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::ForEachLibrary(ke::Lambda<void(const char *)> callback)
|
void CPlugin::ForEachLibrary(ke::Function<void(const char *)> callback)
|
||||||
{
|
{
|
||||||
for (auto iter = m_Libraries.begin(); iter != m_Libraries.end(); iter++)
|
for (auto iter = m_Libraries.begin(); iter != m_Libraries.end(); iter++)
|
||||||
callback((*iter).c_str());
|
callback((*iter).c_str());
|
||||||
@ -1177,7 +1186,7 @@ void CPlugin::AddRequiredLib(const char *name)
|
|||||||
m_RequiredLibs.push_back(name);
|
m_RequiredLibs.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPlugin::ForEachRequiredLib(ke::Lambda<bool(const char *)> callback)
|
bool CPlugin::ForEachRequiredLib(ke::Function<bool(const char *)> callback)
|
||||||
{
|
{
|
||||||
for (auto iter = m_RequiredLibs.begin(); iter != m_RequiredLibs.end(); iter++) {
|
for (auto iter = m_RequiredLibs.begin(); iter != m_RequiredLibs.end(); iter++) {
|
||||||
if (!callback((*iter).c_str()))
|
if (!callback((*iter).c_str()))
|
||||||
@ -1211,7 +1220,7 @@ void CPluginManager::LoadExtensions(CPlugin *pPlugin)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
pPlugin->ForEachExtVar(ke::Move(callback));
|
pPlugin->ForEachExtVar(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPluginManager::RequireExtensions(CPlugin *pPlugin)
|
bool CPluginManager::RequireExtensions(CPlugin *pPlugin)
|
||||||
@ -1247,7 +1256,7 @@ bool CPluginManager::RequireExtensions(CPlugin *pPlugin)
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
return pPlugin->ForEachExtVar(ke::Move(callback));
|
return pPlugin->ForEachExtVar(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
CPlugin *CPluginManager::CompileAndPrep(const char *path)
|
CPlugin *CPluginManager::CompileAndPrep(const char *path)
|
||||||
@ -1490,6 +1499,9 @@ void CPluginManager::Purge(CPlugin *plugin)
|
|||||||
if (plugin->GetStatus() == Plugin_Running)
|
if (plugin->GetStatus() == Plugin_Running)
|
||||||
plugin->Call_OnPluginEnd();
|
plugin->Call_OnPluginEnd();
|
||||||
|
|
||||||
|
m_pOnNotifyPluginUnloaded->PushCell(plugin->GetMyHandle());
|
||||||
|
m_pOnNotifyPluginUnloaded->Execute(NULL);
|
||||||
|
|
||||||
// Notify listeners of unloading.
|
// Notify listeners of unloading.
|
||||||
if (plugin->EnteredSecondPass()) {
|
if (plugin->EnteredSecondPass()) {
|
||||||
for (ListenerIter iter(m_listeners); !iter.done(); iter.next())
|
for (ListenerIter iter(m_listeners); !iter.done(); iter.next())
|
||||||
@ -1536,12 +1548,12 @@ CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx)
|
|||||||
|
|
||||||
unsigned int CPluginManager::GetPluginCount()
|
unsigned int CPluginManager::GetPluginCount()
|
||||||
{
|
{
|
||||||
return m_plugins.length();
|
return m_plugins.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
|
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
|
||||||
{
|
{
|
||||||
m_listeners.append(listener);
|
m_listeners.push_back(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
|
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
|
||||||
@ -1578,6 +1590,7 @@ void CPluginManager::OnSourceModAllInitialized()
|
|||||||
|
|
||||||
m_pOnLibraryAdded = forwardsys->CreateForward("OnLibraryAdded", ET_Ignore, 1, NULL, Param_String);
|
m_pOnLibraryAdded = forwardsys->CreateForward("OnLibraryAdded", ET_Ignore, 1, NULL, Param_String);
|
||||||
m_pOnLibraryRemoved = forwardsys->CreateForward("OnLibraryRemoved", ET_Ignore, 1, NULL, Param_String);
|
m_pOnLibraryRemoved = forwardsys->CreateForward("OnLibraryRemoved", ET_Ignore, 1, NULL, Param_String);
|
||||||
|
m_pOnNotifyPluginUnloaded = forwardsys->CreateForward("OnNotifyPluginUnloaded", ET_Ignore, 1, NULL, Param_Cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::OnSourceModShutdown()
|
void CPluginManager::OnSourceModShutdown()
|
||||||
@ -1592,6 +1605,7 @@ void CPluginManager::OnSourceModShutdown()
|
|||||||
|
|
||||||
forwardsys->ReleaseForward(m_pOnLibraryAdded);
|
forwardsys->ReleaseForward(m_pOnLibraryAdded);
|
||||||
forwardsys->ReleaseForward(m_pOnLibraryRemoved);
|
forwardsys->ReleaseForward(m_pOnLibraryRemoved);
|
||||||
|
forwardsys->ReleaseForward(m_pOnNotifyPluginUnloaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
|
ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
|
||||||
@ -1715,7 +1729,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
|
|||||||
rootmenu->ConsolePrint("[SM] Listing %d plugin%s:", plnum, (plnum > 1) ? "s" : "");
|
rootmenu->ConsolePrint("[SM] Listing %d plugin%s:", plnum, (plnum > 1) ? "s" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::LinkedList<CPlugin *> fail_list;
|
std::list<CPlugin *> fail_list;
|
||||||
|
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) {
|
for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) {
|
||||||
CPlugin *pl = (*iter);
|
CPlugin *pl = (*iter);
|
||||||
@ -1727,7 +1741,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
|
|||||||
len += ke::SafeSprintf(buffer, sizeof(buffer), " %0*d <%s>", plpadding, id, GetStatusText(pl->GetDisplayStatus()));
|
len += ke::SafeSprintf(buffer, sizeof(buffer), " %0*d <%s>", plpadding, id, GetStatusText(pl->GetDisplayStatus()));
|
||||||
|
|
||||||
/* Plugin has failed to load. */
|
/* Plugin has failed to load. */
|
||||||
fail_list.append(pl);
|
fail_list.push_back(pl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2033,7 +2047,8 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
|
|||||||
//the unload/reload attempt next frame will print a message
|
//the unload/reload attempt next frame will print a message
|
||||||
case PluginState::WaitingToUnload:
|
case PluginState::WaitingToUnload:
|
||||||
case PluginState::WaitingToUnloadAndReload:
|
case PluginState::WaitingToUnloadAndReload:
|
||||||
return;
|
rootmenu->ConsolePrint("[SM] Plugin %s will be reloaded on the next frame.", name);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
|
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
|
||||||
@ -2063,7 +2078,7 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print)
|
|||||||
if (state == PluginState::WaitingToUnloadAndReload)
|
if (state == PluginState::WaitingToUnloadAndReload)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ke::AString filename(pl->GetFilename());
|
std::string filename(pl->GetFilename());
|
||||||
PluginType ptype = pl->GetType();
|
PluginType ptype = pl->GetType();
|
||||||
|
|
||||||
int id = 1;
|
int id = 1;
|
||||||
@ -2078,13 +2093,13 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print)
|
|||||||
{
|
{
|
||||||
pl->SetWaitingToUnload(true);
|
pl->SetWaitingToUnload(true);
|
||||||
ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void {
|
ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void {
|
||||||
ReloadPluginImpl(id, filename.chars(), ptype, print);
|
ReloadPluginImpl(id, filename.c_str(), ptype, print);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadPluginImpl(id, filename.chars(), ptype, false);
|
ReloadPluginImpl(id, filename.c_str(), ptype, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2208,7 +2223,6 @@ void CPluginManager::UnloadAll()
|
|||||||
int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
|
int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
|
||||||
{
|
{
|
||||||
int id = 1;
|
int id = 1;
|
||||||
List<CPlugin *>::iterator iter;
|
|
||||||
|
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
|
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
|
||||||
if ((*iter) == pl)
|
if ((*iter) == pl)
|
||||||
@ -2273,7 +2287,7 @@ void CPluginManager::FreePluginList(const CVector<SMPlugin *> *list)
|
|||||||
delete const_cast<CVector<SMPlugin *> *>(list);
|
delete const_cast<CVector<SMPlugin *> *>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::ForEachPlugin(ke::Lambda<void(CPlugin *)> callback)
|
void CPluginManager::ForEachPlugin(ke::Function<void(CPlugin *)> callback)
|
||||||
{
|
{
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next())
|
for (PluginIter iter(m_plugins); !iter.done(); iter.next())
|
||||||
callback(*iter);
|
callback(*iter);
|
||||||
@ -2351,7 +2365,7 @@ public:
|
|||||||
{
|
{
|
||||||
ke::RefPtr<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener);
|
ke::RefPtr<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener);
|
||||||
|
|
||||||
v1_wrappers_.append(wrapper);
|
v1_wrappers_.push_back(wrapper);
|
||||||
g_PluginSys.AddPluginsListener(wrapper);
|
g_PluginSys.AddPluginsListener(wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2394,4 +2408,4 @@ static OldPluginAPI sOldPluginAPI;
|
|||||||
IPluginManager *CPluginManager::GetOldAPI()
|
IPluginManager *CPluginManager::GetOldAPI()
|
||||||
{
|
{
|
||||||
return &sOldPluginAPI;
|
return &sOldPluginAPI;
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,12 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
@ -129,10 +132,10 @@ public:
|
|||||||
bool required;
|
bool required;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ke::Lambda<bool(const sp_pubvar_t *, const ExtVar& ext)> ExtVarCallback;
|
typedef ke::Function<bool(const sp_pubvar_t *, const ExtVar& ext)> ExtVarCallback;
|
||||||
bool ForEachExtVar(const ExtVarCallback& callback);
|
bool ForEachExtVar(const ExtVarCallback& callback);
|
||||||
|
|
||||||
void ForEachLibrary(ke::Lambda<void(const char *)> callback);
|
void ForEachLibrary(ke::Function<void(const char *)> callback);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a plugin object with default values.
|
* Creates a plugin object with default values.
|
||||||
@ -215,7 +218,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddRequiredLib(const char *name);
|
void AddRequiredLib(const char *name);
|
||||||
bool ForEachRequiredLib(ke::Lambda<bool(const char *)> callback);
|
bool ForEachRequiredLib(ke::Function<bool(const char *)> callback);
|
||||||
|
|
||||||
bool HasMissingFakeNatives() const {
|
bool HasMissingFakeNatives() const {
|
||||||
return m_FakeNativesMissing;
|
return m_FakeNativesMissing;
|
||||||
@ -224,7 +227,7 @@ public:
|
|||||||
return m_LibraryMissing;
|
return m_LibraryMissing;
|
||||||
}
|
}
|
||||||
bool HasFakeNatives() const {
|
bool HasFakeNatives() const {
|
||||||
return m_fakes.length() > 0;
|
return m_fakes.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// True if we got far enough into the second pass to call OnPluginLoaded
|
// True if we got far enough into the second pass to call OnPluginLoaded
|
||||||
@ -267,8 +270,8 @@ private:
|
|||||||
char m_errormsg[256];
|
char m_errormsg[256];
|
||||||
|
|
||||||
// Internal properties that must by reset if the runtime is evicted.
|
// Internal properties that must by reset if the runtime is evicted.
|
||||||
ke::AutoPtr<IPluginRuntime> m_pRuntime;
|
std::unique_ptr<IPluginRuntime> m_pRuntime;
|
||||||
ke::AutoPtr<CPhraseCollection> m_pPhrases;
|
std::unique_ptr<CPhraseCollection> m_pPhrases;
|
||||||
IPluginContext *m_pContext;
|
IPluginContext *m_pContext;
|
||||||
sp_pubvar_t *m_MaxClientsVar;
|
sp_pubvar_t *m_MaxClientsVar;
|
||||||
StringHashMap<void *> m_Props;
|
StringHashMap<void *> m_Props;
|
||||||
@ -286,11 +289,11 @@ private:
|
|||||||
|
|
||||||
// Cached.
|
// Cached.
|
||||||
sm_plugininfo_t m_info;
|
sm_plugininfo_t m_info;
|
||||||
ke::AString info_name_;
|
std::string info_name_;
|
||||||
ke::AString info_author_;
|
std::string info_author_;
|
||||||
ke::AString info_description_;
|
std::string info_description_;
|
||||||
ke::AString info_version_;
|
std::string info_version_;
|
||||||
ke::AString info_url_;
|
std::string info_url_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPluginManager :
|
class CPluginManager :
|
||||||
@ -317,8 +320,8 @@ public:
|
|||||||
void Release();
|
void Release();
|
||||||
void OnPluginDestroyed(IPlugin *plugin) override;
|
void OnPluginDestroyed(IPlugin *plugin) override;
|
||||||
private:
|
private:
|
||||||
ke::LinkedList<CPlugin *> mylist;
|
std::list<CPlugin *> mylist;
|
||||||
ke::LinkedList<CPlugin *>::iterator current;
|
std::list<CPlugin *>::iterator current;
|
||||||
};
|
};
|
||||||
friend class CPluginManager::CPluginIterator;
|
friend class CPluginManager::CPluginIterator;
|
||||||
public: //IScriptManager
|
public: //IScriptManager
|
||||||
@ -432,7 +435,7 @@ public:
|
|||||||
|
|
||||||
void _SetPauseState(CPlugin *pPlugin, bool pause);
|
void _SetPauseState(CPlugin *pPlugin, bool pause);
|
||||||
|
|
||||||
void ForEachPlugin(ke::Lambda<void(CPlugin *)> callback);
|
void ForEachPlugin(ke::Function<void(CPlugin *)> callback);
|
||||||
private:
|
private:
|
||||||
LoadRes LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type);
|
LoadRes LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type);
|
||||||
|
|
||||||
@ -473,7 +476,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
ReentrantList<IPluginsListener *> m_listeners;
|
ReentrantList<IPluginsListener *> m_listeners;
|
||||||
ReentrantList<CPlugin *> m_plugins;
|
ReentrantList<CPlugin *> m_plugins;
|
||||||
ke::LinkedList<CPluginIterator *> m_iterators;
|
std::list<CPluginIterator *> m_iterators;
|
||||||
|
|
||||||
typedef decltype(m_listeners)::iterator ListenerIter;
|
typedef decltype(m_listeners)::iterator ListenerIter;
|
||||||
typedef decltype(m_plugins)::iterator PluginIter;
|
typedef decltype(m_plugins)::iterator PluginIter;
|
||||||
@ -484,10 +487,8 @@ private:
|
|||||||
{
|
{
|
||||||
/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */
|
/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */
|
||||||
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
||||||
ke::AString original(key.chars());
|
std::string lower = ke::Lowercase(key.c_str());
|
||||||
ke::AString lower = original.lowercase();
|
return detail::CharsAndLength(lower.c_str()).hash();
|
||||||
|
|
||||||
return detail::CharsAndLength(lower.chars()).hash();
|
|
||||||
#else
|
#else
|
||||||
return key.hash();
|
return key.hash();
|
||||||
#endif
|
#endif
|
||||||
@ -497,8 +498,8 @@ private:
|
|||||||
{
|
{
|
||||||
const char *pluginFileChars = const_cast<CPlugin*>(plugin)->GetFilename();
|
const char *pluginFileChars = const_cast<CPlugin*>(plugin)->GetFilename();
|
||||||
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
||||||
ke::AString pluginFile = ke::AString(pluginFileChars).lowercase();
|
std::string pluginFile = ke::Lowercase(pluginFileChars);
|
||||||
ke::AString input = ke::AString(file).lowercase();
|
std::string input = ke::Lowercase(file);
|
||||||
|
|
||||||
return pluginFile == input;
|
return pluginFile == input;
|
||||||
#else
|
#else
|
||||||
@ -522,6 +523,7 @@ private:
|
|||||||
// Forwards
|
// Forwards
|
||||||
IForward *m_pOnLibraryAdded;
|
IForward *m_pOnLibraryAdded;
|
||||||
IForward *m_pOnLibraryRemoved;
|
IForward *m_pOnLibraryRemoved;
|
||||||
|
IForward *m_pOnNotifyPluginUnloaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPluginManager g_PluginSys;
|
extern CPluginManager g_PluginSys;
|
||||||
|
@ -52,7 +52,7 @@ ProfileToolManager::OnSourceModShutdown()
|
|||||||
IProfilingTool *
|
IProfilingTool *
|
||||||
ProfileToolManager::FindToolByName(const char *name)
|
ProfileToolManager::FindToolByName(const char *name)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < tools_.length(); i++) {
|
for (size_t i = 0; i < tools_.size(); i++) {
|
||||||
if (strcmp(tools_[i]->Name(), name) == 0)
|
if (strcmp(tools_[i]->Name(), name) == 0)
|
||||||
return tools_[i];
|
return tools_[i];
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ ProfileToolManager::StartFromConsole(IProfilingTool *tool)
|
|||||||
void
|
void
|
||||||
ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args)
|
ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args)
|
||||||
{
|
{
|
||||||
if (tools_.length() == 0) {
|
if (tools_.size() == 0) {
|
||||||
rootmenu->ConsolePrint("No profiling tools are enabled.");
|
rootmenu->ConsolePrint("No profiling tools are enabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
|||||||
|
|
||||||
if (strcmp(cmdname, "list") == 0) {
|
if (strcmp(cmdname, "list") == 0) {
|
||||||
rootmenu->ConsolePrint("Profiling tools:");
|
rootmenu->ConsolePrint("Profiling tools:");
|
||||||
for (size_t i = 0; i < tools_.length(); i++) {
|
for (size_t i = 0; i < tools_.size(); i++) {
|
||||||
rootmenu->DrawGenericOption(tools_[i]->Name(), tools_[i]->Description());
|
rootmenu->DrawGenericOption(tools_[i]->Name(), tools_[i]->Description());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -135,7 +135,7 @@ ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
|||||||
if (strcmp(cmdname, "start") == 0) {
|
if (strcmp(cmdname, "start") == 0) {
|
||||||
if (!default_) {
|
if (!default_) {
|
||||||
default_ = FindToolByName("vprof");
|
default_ = FindToolByName("vprof");
|
||||||
if (!default_ && tools_.length() > 0)
|
if (!default_ && tools_.size() > 0)
|
||||||
default_ = tools_[0];
|
default_ = tools_[0];
|
||||||
if (!default_) {
|
if (!default_) {
|
||||||
rootmenu->ConsolePrint("Could not find any profiler to use.");
|
rootmenu->ConsolePrint("Could not find any profiler to use.");
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args) override;
|
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args) override;
|
||||||
|
|
||||||
void RegisterTool(IProfilingTool *tool) {
|
void RegisterTool(IProfilingTool *tool) {
|
||||||
tools_.append(tool);
|
tools_.push_back(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsActive() const {
|
bool IsActive() const {
|
||||||
@ -76,7 +76,7 @@ private:
|
|||||||
void StartFromConsole(IProfilingTool *tool);
|
void StartFromConsole(IProfilingTool *tool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ke::Vector<IProfilingTool *> tools_;
|
std::vector<IProfilingTool *> tools_;
|
||||||
IProfilingTool *active_;
|
IProfilingTool *active_;
|
||||||
IProfilingTool *default_;
|
IProfilingTool *default_;
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
|
@ -221,11 +221,15 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const ICommandAr
|
|||||||
ConsolePrint(" Fyren");
|
ConsolePrint(" Fyren");
|
||||||
ConsolePrint(" Nicholas \"psychonic\" Hastings");
|
ConsolePrint(" Nicholas \"psychonic\" Hastings");
|
||||||
ConsolePrint(" Asher \"asherkin\" Baker");
|
ConsolePrint(" Asher \"asherkin\" Baker");
|
||||||
|
ConsolePrint(" Ruben \"Dr!fter\" Gonzalez");
|
||||||
|
ConsolePrint(" Josh \"KyleS\" Allard");
|
||||||
|
ConsolePrint(" Michael \"Headline\" Flaherty");
|
||||||
|
ConsolePrint(" Jannik \"Peace-Maker\" Hartung");
|
||||||
ConsolePrint(" Borja \"faluco\" Ferrer");
|
ConsolePrint(" Borja \"faluco\" Ferrer");
|
||||||
ConsolePrint(" Pavol \"PM OnoTo\" Marko");
|
ConsolePrint(" Pavol \"PM OnoTo\" Marko");
|
||||||
ConsolePrint(" Special thanks to Liam, ferret, and Mani");
|
ConsolePrint(" Special thanks to Liam, ferret, and Mani");
|
||||||
ConsolePrint(" Special thanks to Viper and SteamFriends");
|
ConsolePrint(" Special thanks to Viper and SteamFriends");
|
||||||
ConsolePrint(" http://www.sourcemod.net/");
|
ConsolePrint(" https://www.sourcemod.net/");
|
||||||
}
|
}
|
||||||
else if (strcmp(cmdname, "version") == 0)
|
else if (strcmp(cmdname, "version") == 0)
|
||||||
{
|
{
|
||||||
|
@ -29,13 +29,16 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include <ILibrarySys.h>
|
#include <ILibrarySys.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
using namespace ke;
|
using namespace ke;
|
||||||
|
|
||||||
@ -361,11 +364,11 @@ void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *native
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pPlugin->GetRuntime()->UpdateNativeBinding(
|
auto rt = pPlugin->GetRuntime();
|
||||||
index,
|
if (pEntry->fake)
|
||||||
pEntry->func(),
|
rt->UpdateNativeBindingObject(index, pEntry->fake->wrapper, flags, nullptr);
|
||||||
flags,
|
else
|
||||||
nullptr);
|
rt->UpdateNativeBinding(index, pEntry->native->func, flags, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
|
AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
|
||||||
@ -379,11 +382,6 @@ AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const s
|
|||||||
return entry.forget();
|
return entry.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeNative::~FakeNative()
|
|
||||||
{
|
|
||||||
g_pSourcePawn2->DestroyFakeNative(gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
||||||
{
|
{
|
||||||
NativeCache::Result r = m_NtvCache.find(name);
|
NativeCache::Result r = m_NtvCache.find(name);
|
||||||
@ -400,21 +398,44 @@ void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
|||||||
m_NtvCache.remove(r);
|
m_NtvCache.remove(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DynamicNative final : public INativeCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DynamicNative(SPVM_FAKENATIVE_FUNC callback, void* data)
|
||||||
|
: callback_(callback),
|
||||||
|
data_(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void AddRef() override {
|
||||||
|
refcount_++;
|
||||||
|
}
|
||||||
|
void Release() override {
|
||||||
|
assert(refcount_ > 0);
|
||||||
|
if (--refcount_ == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
int Invoke(IPluginContext* ctx, const cell_t* params) override {
|
||||||
|
return callback_(ctx, params, data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t refcount_ = 0;
|
||||||
|
SPVM_FAKENATIVE_FUNC callback_;
|
||||||
|
void* data_;
|
||||||
|
};
|
||||||
|
|
||||||
AlreadyRefed<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
|
AlreadyRefed<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
|
||||||
{
|
{
|
||||||
RefPtr<Native> entry(FindNative(name));
|
RefPtr<Native> entry(FindNative(name));
|
||||||
if (entry)
|
if (entry)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
AutoPtr<FakeNative> fake(new FakeNative(name, pFunc));
|
std::unique_ptr<FakeNative> fake(new FakeNative(name, pFunc));
|
||||||
|
fake->wrapper = new DynamicNative(func, fake.get());
|
||||||
fake->gate = g_pSourcePawn2->CreateFakeNative(func, fake);
|
|
||||||
if (!fake->gate)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
|
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
|
||||||
|
|
||||||
entry = new Native(owner, fake.take());
|
entry = new Native(owner, std::move(fake));
|
||||||
m_NtvCache.insert(name, entry);
|
m_NtvCache.insert(name, entry);
|
||||||
|
|
||||||
return entry.forget();
|
return entry.forget();
|
||||||
|
@ -49,9 +49,11 @@ namespace SourceMod
|
|||||||
{
|
{
|
||||||
struct IdentityToken_t
|
struct IdentityToken_t
|
||||||
{
|
{
|
||||||
Handle_t ident;
|
Handle_t ident = 0;
|
||||||
void *ptr;
|
void *ptr = nullptr;
|
||||||
IdentityType_t type;
|
IdentityType_t type = 0;
|
||||||
|
size_t num_handles = 0;
|
||||||
|
bool warned_handle_usage = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 sw=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
@ -29,17 +29,518 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
#include <sm_platform.h>
|
#include <sm_platform.h>
|
||||||
|
#include <amtl/am-deque.h>
|
||||||
|
#include <amtl/am-maybe.h>
|
||||||
|
#include <amtl/am-thread.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include "BaseWorker.h"
|
||||||
#include "ThreadSupport.h"
|
#include "ThreadSupport.h"
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
|
|
||||||
#if defined PLATFORM_POSIX
|
static constexpr unsigned int DEFAULT_THINK_TIME_MS = 20;
|
||||||
#include "thread/PosixThreads.h"
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
#include "thread/WinThreads.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MainThreader g_MainThreader;
|
class CompatWorker final : public IThreadWorker
|
||||||
IThreader *g_pThreader = &g_MainThreader;
|
{
|
||||||
|
public:
|
||||||
|
explicit CompatWorker(IThreadWorkerCallbacks* callbacks);
|
||||||
|
~CompatWorker();
|
||||||
|
|
||||||
|
void MakeThread(IThread *pThread) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override;
|
||||||
|
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override;
|
||||||
|
unsigned int RunFrame() override;
|
||||||
|
bool Pause() override;
|
||||||
|
bool Unpause() override;
|
||||||
|
bool Start() override;
|
||||||
|
bool Stop(bool flush) override;
|
||||||
|
WorkerState GetStatus(unsigned int *numThreads) override;
|
||||||
|
void SetMaxThreadsPerFrame(unsigned int threads) override;
|
||||||
|
void SetThinkTimePerFrame(unsigned int thinktime) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Flush();
|
||||||
|
void Worker();
|
||||||
|
void RunWork(SWThreadHandle* handle);
|
||||||
|
void RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IThreadWorkerCallbacks* callbacks_;
|
||||||
|
WorkerState state_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable work_cv_;
|
||||||
|
std::deque<SWThreadHandle*> work_;
|
||||||
|
std::unique_ptr<std::thread> thread_;
|
||||||
|
std::atomic<unsigned int> jobs_per_wakeup_;
|
||||||
|
std::atomic<unsigned int> wait_between_jobs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompatWorker::CompatWorker(IThreadWorkerCallbacks* callbacks)
|
||||||
|
: callbacks_(callbacks),
|
||||||
|
state_(Worker_Stopped),
|
||||||
|
jobs_per_wakeup_(SM_DEFAULT_THREADS_PER_FRAME),
|
||||||
|
wait_between_jobs_(DEFAULT_THINK_TIME_MS)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CompatWorker::~CompatWorker()
|
||||||
|
{
|
||||||
|
Stop(false /* ignored */);
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Start()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (state_ != Worker_Stopped)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
thread_ = ke::NewThread("SM CompatWorker Thread", [this]() -> void {
|
||||||
|
Worker();
|
||||||
|
});
|
||||||
|
|
||||||
|
state_ = Worker_Running;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Stop(bool)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
if (state_ <= Worker_Stopped)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state_ = Worker_Stopped;
|
||||||
|
work_cv_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_->join();
|
||||||
|
thread_ = nullptr;
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Pause()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (state_ != Worker_Running)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state_ = Worker_Paused;
|
||||||
|
work_cv_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Unpause()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (state_ != Worker_Paused)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state_ = Worker_Running;
|
||||||
|
work_cv_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::Flush()
|
||||||
|
{
|
||||||
|
while (!work_.empty()) {
|
||||||
|
auto handle = ke::PopFront(&work_);
|
||||||
|
handle->GetThread()->OnTerminate(handle, true);
|
||||||
|
if (handle->m_params.flags & Thread_AutoRelease)
|
||||||
|
delete handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::Worker()
|
||||||
|
{
|
||||||
|
// Note: this must be first to ensure an ordering between Worker() and
|
||||||
|
// Start(). It must also be outside of the loop to ensure the lock is
|
||||||
|
// held across wakeup and retesting the predicates.
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
if (callbacks_) {
|
||||||
|
lock.unlock();
|
||||||
|
callbacks_->OnWorkerStart(this);
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::chrono::system_clock Clock;
|
||||||
|
typedef std::chrono::time_point<Clock> TimePoint;
|
||||||
|
|
||||||
|
auto can_work = [this]() -> bool {
|
||||||
|
return state_ == Worker_Running && !work_.empty();
|
||||||
|
};
|
||||||
|
|
||||||
|
ke::Maybe<TimePoint> wait;
|
||||||
|
unsigned int work_in_frame = 0;
|
||||||
|
for (;;) {
|
||||||
|
if (state_ == Worker_Stopped)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!can_work()) {
|
||||||
|
// Wait for work or a Stop.
|
||||||
|
work_cv_.wait(lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait.isValid()) {
|
||||||
|
// Wait until the specified time has passed. If we wake up with a
|
||||||
|
// timeout, then the wait has elapsed, so reset the holder.
|
||||||
|
if (work_cv_.wait_until(lock, wait.get()) == std::cv_status::timeout)
|
||||||
|
wait = ke::Nothing();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(state_ == Worker_Running);
|
||||||
|
assert(!work_.empty());
|
||||||
|
|
||||||
|
SWThreadHandle* handle = ke::PopFront(&work_);
|
||||||
|
RunWorkLocked(&lock, handle);
|
||||||
|
work_in_frame++;
|
||||||
|
|
||||||
|
// If we've reached our max jobs per "frame", signal that the next
|
||||||
|
// immediate job must be delayed. We retain the old ThreadWorker
|
||||||
|
// behavior by checking if the queue has more work. Thus, a delay
|
||||||
|
// only occurs if two jobs would be processed in the same wakeup.
|
||||||
|
if (work_in_frame >= jobs_per_wakeup_ && wait_between_jobs_ && can_work())
|
||||||
|
wait = ke::Some(Clock::now() + std::chrono::milliseconds(wait_between_jobs_));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(lock.owns_lock());
|
||||||
|
|
||||||
|
while (!work_.empty()) {
|
||||||
|
SWThreadHandle* handle = ke::PopFront(&work_);
|
||||||
|
RunWorkLocked(&lock, handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CompatWorker::RunFrame()
|
||||||
|
{
|
||||||
|
unsigned int nprocessed = 0;
|
||||||
|
for (unsigned int i = 1; i <= jobs_per_wakeup_; i++) {
|
||||||
|
SWThreadHandle* handle;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (work_.empty())
|
||||||
|
break;
|
||||||
|
handle = ke::PopFront(&work_);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunWork(handle);
|
||||||
|
nprocessed++;
|
||||||
|
}
|
||||||
|
return nprocessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle)
|
||||||
|
{
|
||||||
|
lock->unlock();
|
||||||
|
RunWork(handle);
|
||||||
|
lock->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::RunWork(SWThreadHandle* handle)
|
||||||
|
{
|
||||||
|
bool autorelease = !!(handle->m_params.flags & Thread_AutoRelease);
|
||||||
|
handle->m_state = Thread_Running;
|
||||||
|
handle->GetThread()->RunThread(handle);
|
||||||
|
handle->m_state = Thread_Done;
|
||||||
|
handle->GetThread()->OnTerminate(handle, false);
|
||||||
|
if (autorelease)
|
||||||
|
delete handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::MakeThread(IThread *pThread)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = Thread_AutoRelease;
|
||||||
|
MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatWorker::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = flags;
|
||||||
|
return MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatWorker::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
ThreadParams def_params;
|
||||||
|
if (!params)
|
||||||
|
params = &def_params;
|
||||||
|
|
||||||
|
if (state_ <= Worker_Stopped)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
SWThreadHandle* handle = new SWThreadHandle(this, params, pThread);
|
||||||
|
work_.push_back(handle);
|
||||||
|
work_cv_.notify_one();
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||||
|
{
|
||||||
|
min = ThreadPrio_Normal;
|
||||||
|
max = ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::SetMaxThreadsPerFrame(unsigned int threads)
|
||||||
|
{
|
||||||
|
jobs_per_wakeup_ = threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::SetThinkTimePerFrame(unsigned int thinktime)
|
||||||
|
{
|
||||||
|
wait_between_jobs_ = thinktime;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerState CompatWorker::GetStatus(unsigned int *numThreads)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
// This number is meaningless and the status is racy.
|
||||||
|
if (numThreads)
|
||||||
|
*numThreads = jobs_per_wakeup_;
|
||||||
|
return state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompatThread final : public IThreadHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CompatThread(IThread* callbacks, const ThreadParams* params);
|
||||||
|
|
||||||
|
bool WaitForThread() override;
|
||||||
|
void DestroyThis() override;
|
||||||
|
IThreadCreator *Parent() override;
|
||||||
|
void GetParams(ThreadParams *ptparams) override;
|
||||||
|
ThreadPriority GetPriority() override;
|
||||||
|
bool SetPriority(ThreadPriority prio) override;
|
||||||
|
ThreadState GetState() override;
|
||||||
|
bool Unpause() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
IThread* callbacks_;
|
||||||
|
ThreadParams params_;
|
||||||
|
std::unique_ptr<std::thread> thread_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable check_cv_;
|
||||||
|
std::atomic<bool> finished_;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompatThread::CompatThread(IThread* callbacks, const ThreadParams* params)
|
||||||
|
: callbacks_(callbacks),
|
||||||
|
params_(*params)
|
||||||
|
{
|
||||||
|
if (!(params_.flags & Thread_CreateSuspended))
|
||||||
|
Unpause();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatThread::Unpause()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
if (thread_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
thread_ = ke::NewThread("SM CompatThread", [this]() -> void {
|
||||||
|
Run();
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThread::Run()
|
||||||
|
{
|
||||||
|
// Create an ordering between when the thread runs and when thread_ is assigned.
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
callbacks_->RunThread(this);
|
||||||
|
finished_ = true;
|
||||||
|
callbacks_->OnTerminate(this, false);
|
||||||
|
|
||||||
|
if (params_.flags & Thread_AutoRelease) {
|
||||||
|
// There should be no handles outstanding, so it's safe to self-destruct.
|
||||||
|
thread_->detach();
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
|
callbacks_ = nullptr;
|
||||||
|
check_cv_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatThread::WaitForThread()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
for (;;) {
|
||||||
|
// When done, callbacks are unset. If paused, this will deadlock.
|
||||||
|
if (!callbacks_)
|
||||||
|
break;
|
||||||
|
check_cv_.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_->join();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadState CompatThread::GetState()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
if (!thread_)
|
||||||
|
return Thread_Paused;
|
||||||
|
return finished_ ? Thread_Done : Thread_Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThread::DestroyThis()
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPriority CompatThread::GetPriority()
|
||||||
|
{
|
||||||
|
return ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatThread::SetPriority(ThreadPriority prio)
|
||||||
|
{
|
||||||
|
return prio == ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadCreator *CompatThread::Parent()
|
||||||
|
{
|
||||||
|
return g_pThreader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThread::GetParams(ThreadParams *ptparams)
|
||||||
|
{
|
||||||
|
*ptparams = params_;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompatMutex : public IMutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool TryLock() {
|
||||||
|
return mutex_.try_lock();
|
||||||
|
}
|
||||||
|
void Lock() {
|
||||||
|
mutex_.lock();
|
||||||
|
}
|
||||||
|
void Unlock() {
|
||||||
|
mutex_.unlock();
|
||||||
|
}
|
||||||
|
void DestroyThis() {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::mutex mutex_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompatThreader final : public IThreader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void MakeThread(IThread *pThread) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override;
|
||||||
|
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override;
|
||||||
|
IMutex *MakeMutex() override;
|
||||||
|
void ThreadSleep(unsigned int ms) override;
|
||||||
|
IEventSignal *MakeEventSignal() override;
|
||||||
|
IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) override;
|
||||||
|
void DestroyWorker(IThreadWorker *pWorker) override;
|
||||||
|
} sCompatThreader;
|
||||||
|
|
||||||
|
void CompatThreader::MakeThread(IThread *pThread)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = Thread_AutoRelease;
|
||||||
|
MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = flags;
|
||||||
|
return MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||||
|
{
|
||||||
|
ThreadParams def_params;
|
||||||
|
if (!params)
|
||||||
|
params = &def_params;
|
||||||
|
|
||||||
|
return new CompatThread(pThread, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||||
|
{
|
||||||
|
min = ThreadPrio_Normal;
|
||||||
|
max = ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMutex *CompatThreader::MakeMutex()
|
||||||
|
{
|
||||||
|
return new CompatMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThreader::ThreadSleep(unsigned int ms)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompatEventSignal final : public IEventSignal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Wait() override {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
cv_.wait(lock);
|
||||||
|
}
|
||||||
|
void Signal() override {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
cv_.notify_all();
|
||||||
|
}
|
||||||
|
void DestroyThis() override {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable cv_;
|
||||||
|
};
|
||||||
|
|
||||||
|
IEventSignal *CompatThreader::MakeEventSignal()
|
||||||
|
{
|
||||||
|
return new CompatEventSignal();
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadWorker *CompatThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
|
||||||
|
{
|
||||||
|
if (!threaded)
|
||||||
|
return new BaseWorker(hooks);
|
||||||
|
return new CompatWorker(hooks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||||
|
{
|
||||||
|
delete pWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreader *g_pThreader = &sCompatThreader;
|
||||||
|
|
||||||
class RegThreadStuff : public SMGlobalClass
|
class RegThreadStuff : public SMGlobalClass
|
||||||
{
|
{
|
||||||
|
@ -32,49 +32,13 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <am-thread-utils.h>
|
|
||||||
#include <am-utility.h>
|
#include <am-utility.h>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
class CompatMutex : public IMutex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool TryLock() {
|
|
||||||
return mutex_.TryLock();
|
|
||||||
}
|
|
||||||
void Lock() {
|
|
||||||
mutex_.Lock();
|
|
||||||
}
|
|
||||||
void Unlock() {
|
|
||||||
mutex_.Unlock();
|
|
||||||
}
|
|
||||||
void DestroyThis() {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
ke::Mutex mutex_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CompatCondVar : public IEventSignal
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Wait() {
|
|
||||||
ke::AutoLock lock(&cv_);
|
|
||||||
cv_.Wait();
|
|
||||||
}
|
|
||||||
void Signal() {
|
|
||||||
ke::AutoLock lock(&cv_);
|
|
||||||
cv_.Notify();
|
|
||||||
}
|
|
||||||
void DestroyThis() {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
ke::ConditionVariable cv_;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern IThreader *g_pThreader;
|
extern IThreader *g_pThreader;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#include "LibrarySys.h"
|
#include "LibrarySys.h"
|
||||||
#include "RootConsoleMenu.h"
|
#include "RootConsoleMenu.h"
|
||||||
#include "CellArray.h"
|
#include "CellArray.h"
|
||||||
|
#include "smn_entitylump.h"
|
||||||
#include <bridge/include/BridgeAPI.h>
|
#include <bridge/include/BridgeAPI.h>
|
||||||
#include <bridge/include/IProviderCallbacks.h>
|
#include <bridge/include/IProviderCallbacks.h>
|
||||||
|
|
||||||
@ -89,6 +90,8 @@ CNativeOwner g_CoreNatives;
|
|||||||
PseudoAddressManager pseudoAddr;
|
PseudoAddressManager pseudoAddr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
EntityLumpParseResult lastParseResult;
|
||||||
|
|
||||||
static void AddCorePhraseFile(const char *filename)
|
static void AddCorePhraseFile(const char *filename)
|
||||||
{
|
{
|
||||||
g_pCorePhrases->AddPhraseFile(filename);
|
g_pCorePhrases->AddPhraseFile(filename);
|
||||||
@ -135,6 +138,35 @@ static uint32_t ToPseudoAddress(void *addr)
|
|||||||
#endif
|
#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.
|
// Defined in smn_filesystem.cpp.
|
||||||
extern bool OnLogPrint(const char *msg);
|
extern bool OnLogPrint(const char *msg);
|
||||||
|
|
||||||
@ -170,6 +202,9 @@ static sm_logic_t logic =
|
|||||||
CellArray::Free,
|
CellArray::Free,
|
||||||
FromPseudoAddress,
|
FromPseudoAddress,
|
||||||
ToPseudoAddress,
|
ToPseudoAddress,
|
||||||
|
SetEntityLumpWritable,
|
||||||
|
ParseEntityLumpString,
|
||||||
|
GetEntityLumpString,
|
||||||
&g_PluginSys,
|
&g_PluginSys,
|
||||||
&g_ShareSys,
|
&g_ShareSys,
|
||||||
&g_Extensions,
|
&g_Extensions,
|
||||||
|
@ -26,16 +26,17 @@
|
|||||||
// or <http://www.sourcemod.net/license.php>.
|
// or <http://www.sourcemod.net/license.php>.
|
||||||
#include "frame_tasks.h"
|
#include "frame_tasks.h"
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
ke::Vector<ke::Lambda<void()>> sNextTasks;
|
std::vector<ke::Function<void()>> sNextTasks;
|
||||||
ke::Vector<ke::Lambda<void()>> sWorkTasks;
|
std::vector<ke::Function<void()>> sWorkTasks;
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceMod::ScheduleTaskForNextFrame(ke::Lambda<void()>&& task)
|
SourceMod::ScheduleTaskForNextFrame(ke::Function<void()>&& task)
|
||||||
{
|
{
|
||||||
sNextTasks.append(ke::Forward<decltype(task)>(task));
|
sNextTasks.push_back(std::forward<decltype(task)>(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -45,11 +46,11 @@ SourceMod::RunScheduledFrameTasks(bool simulating)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Swap.
|
// Swap.
|
||||||
ke::Vector<ke::Lambda<void()>> temp(ke::Move(sNextTasks));
|
std::vector<ke::Function<void()>> temp(std::move(sNextTasks));
|
||||||
sNextTasks = ke::Move(sWorkTasks);
|
sNextTasks = std::move(sWorkTasks);
|
||||||
sWorkTasks = ke::Move(temp);
|
sWorkTasks = std::move(temp);
|
||||||
|
|
||||||
for (size_t i = 0; i < sWorkTasks.length(); i++)
|
for (size_t i = 0; i < sWorkTasks.size(); i++)
|
||||||
sWorkTasks[i]();
|
sWorkTasks[i]();
|
||||||
sWorkTasks.clear();
|
sWorkTasks.clear();
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,10 @@
|
|||||||
|
|
||||||
namespace SourceMod {
|
namespace SourceMod {
|
||||||
|
|
||||||
void ScheduleTaskForNextFrame(ke::Lambda<void()>&& task);
|
void ScheduleTaskForNextFrame(ke::Function<void()>&& task);
|
||||||
|
|
||||||
void RunScheduledFrameTasks(bool simulating);
|
void RunScheduledFrameTasks(bool simulating);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _include_sourcemod_logic_frame_tasks_h_
|
#endif // _include_sourcemod_logic_frame_tasks_h_
|
||||||
|
@ -89,6 +89,6 @@ unsigned int UTIL_CRC32(const void *pdata, size_t data_length)
|
|||||||
crc = CRCTable[c] ^ (crc >> 8);
|
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])
|
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);
|
Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
@ -83,6 +83,48 @@ static cell_t CreateStack(IPluginContext *pContext, const cell_t *params)
|
|||||||
return hndl;
|
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;
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&oldArray)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ICellArray *array = oldArray->clone();
|
||||||
|
if (!array)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Failed to clone stack. Out of memory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle_t hndl = handlesys->CreateHandle(htCellStack, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
if (!hndl)
|
||||||
|
{
|
||||||
|
delete array;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t PushStackCell(IPluginContext *pContext, const cell_t *params)
|
static cell_t PushStackCell(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
CellArray *array;
|
CellArray *array;
|
||||||
@ -387,6 +429,7 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
|
|||||||
REGISTER_NATIVES(cellStackNatives)
|
REGISTER_NATIVES(cellStackNatives)
|
||||||
{
|
{
|
||||||
{"CreateStack", CreateStack},
|
{"CreateStack", CreateStack},
|
||||||
|
{"CloneStack", CloneStack},
|
||||||
{"IsStackEmpty", IsStackEmpty},
|
{"IsStackEmpty", IsStackEmpty},
|
||||||
{"PopStackArray", PopStackArray},
|
{"PopStackArray", PopStackArray},
|
||||||
{"PopStackCell", PopStackCell},
|
{"PopStackCell", PopStackCell},
|
||||||
@ -398,6 +441,8 @@ REGISTER_NATIVES(cellStackNatives)
|
|||||||
|
|
||||||
// Transitional syntax support.
|
// Transitional syntax support.
|
||||||
{"ArrayStack.ArrayStack", CreateStack},
|
{"ArrayStack.ArrayStack", CreateStack},
|
||||||
|
{"ArrayStack.Clear", ClearStack},
|
||||||
|
{"ArrayStack.Clone", CloneStack},
|
||||||
{"ArrayStack.Pop", ArrayStack_Pop},
|
{"ArrayStack.Pop", ArrayStack_Pop},
|
||||||
{"ArrayStack.PopString", ArrayStack_PopString},
|
{"ArrayStack.PopString", ArrayStack_PopString},
|
||||||
{"ArrayStack.PopArray", ArrayStack_PopArray},
|
{"ArrayStack.PopArray", ArrayStack_PopArray},
|
||||||
|
@ -30,9 +30,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include <am-autoptr.h>
|
|
||||||
#include <am-moveable.h>
|
|
||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
#include <sm_stringhashmap.h>
|
#include <sm_stringhashmap.h>
|
||||||
#include "sm_memtable.h"
|
#include "sm_memtable.h"
|
||||||
@ -103,7 +104,7 @@ public:
|
|||||||
assert(isArray());
|
assert(isArray());
|
||||||
return reinterpret_cast<cell_t *>(raw()->base());
|
return reinterpret_cast<cell_t *>(raw()->base());
|
||||||
}
|
}
|
||||||
char *chars() const {
|
char *c_str() const {
|
||||||
assert(isString());
|
assert(isString());
|
||||||
return reinterpret_cast<char *>(raw()->base());
|
return reinterpret_cast<char *>(raw()->base());
|
||||||
}
|
}
|
||||||
@ -182,7 +183,7 @@ struct TrieSnapshot
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t length;
|
size_t length;
|
||||||
ke::AutoPtr<int[]> keys;
|
std::unique_ptr<int[]> keys;
|
||||||
BaseStringTable strings;
|
BaseStringTable strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -349,6 +350,27 @@ static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
CellTrie *pTrie;
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
Handle_t hndl = params[1];
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key;
|
||||||
|
pContext->LocalToString(params[2], &key);
|
||||||
|
|
||||||
|
StringHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||||
|
|
||||||
|
return r.found() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
CellTrie *pTrie;
|
CellTrie *pTrie;
|
||||||
@ -517,7 +539,7 @@ static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
size_t written;
|
size_t written;
|
||||||
pContext->StringToLocalUTF8(params[3], params[4], r->value.chars(), &written);
|
pContext->StringToLocalUTF8(params[3], params[4], r->value.c_str(), &written);
|
||||||
|
|
||||||
*pSize = (cell_t)written;
|
*pSize = (cell_t)written;
|
||||||
return 1;
|
return 1;
|
||||||
@ -557,10 +579,10 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
TrieSnapshot *snapshot = new TrieSnapshot;
|
TrieSnapshot *snapshot = new TrieSnapshot;
|
||||||
snapshot->length = pTrie->map.elements();
|
snapshot->length = pTrie->map.elements();
|
||||||
snapshot->keys = ke::MakeUnique<int[]>(snapshot->length);
|
snapshot->keys = std::make_unique<int[]>(snapshot->length);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
|
for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
|
||||||
snapshot->keys[i] = snapshot->strings.AddString(iter->key.chars(), iter->key.length());
|
snapshot->keys[i] = snapshot->strings.AddString(iter->key.c_str(), iter->key.length());
|
||||||
assert(i == snapshot->length);
|
assert(i == snapshot->length);
|
||||||
|
|
||||||
if ((hndl = handlesys->CreateHandle(htSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
|
if ((hndl = handlesys->CreateHandle(htSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
|
||||||
@ -635,6 +657,56 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
|
|||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
CellTrie *pOldTrie;
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], htCellTrie, &sec, (void **)&pOldTrie))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
CellTrie *pNewTrie = new CellTrie;
|
||||||
|
Handle_t hndl = handlesys->CreateHandle(htCellTrie, pNewTrie, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
if (!hndl)
|
||||||
|
{
|
||||||
|
delete pNewTrie;
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (StringHashMap<Entry>::iterator it = pOldTrie->map.iter(); !it.empty(); it.next())
|
||||||
|
{
|
||||||
|
const char *key = it->key.c_str();
|
||||||
|
StringHashMap<Entry>::Insert insert = pNewTrie->map.findForAdd(key);
|
||||||
|
if (pNewTrie->map.add(insert, key))
|
||||||
|
{
|
||||||
|
StringHashMap<Entry>::Result result = pOldTrie->map.find(key);
|
||||||
|
if (result->value.isCell())
|
||||||
|
{
|
||||||
|
insert->value.setCell(result->value.cell());
|
||||||
|
}
|
||||||
|
else if (result->value.isString())
|
||||||
|
{
|
||||||
|
insert->value.setString(result->value.c_str());
|
||||||
|
}
|
||||||
|
else if (result->value.isArray())
|
||||||
|
{
|
||||||
|
insert->value.setArray(result->value.array(), result->value.arrayLength());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlesys->FreeHandle(hndl, NULL);
|
||||||
|
return pContext->ThrowNativeError("Unhandled data type encountered, file a bug and reference pr #852");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(trieNatives)
|
REGISTER_NATIVES(trieNatives)
|
||||||
{
|
{
|
||||||
{"ClearTrie", ClearTrie},
|
{"ClearTrie", ClearTrie},
|
||||||
@ -659,12 +731,14 @@ REGISTER_NATIVES(trieNatives)
|
|||||||
{"StringMap.GetArray", GetTrieArray},
|
{"StringMap.GetArray", GetTrieArray},
|
||||||
{"StringMap.GetString", GetTrieString},
|
{"StringMap.GetString", GetTrieString},
|
||||||
{"StringMap.GetValue", GetTrieValue},
|
{"StringMap.GetValue", GetTrieValue},
|
||||||
|
{"StringMap.ContainsKey", ContainsKeyInTrie},
|
||||||
{"StringMap.Remove", RemoveFromTrie},
|
{"StringMap.Remove", RemoveFromTrie},
|
||||||
{"StringMap.SetArray", SetTrieArray},
|
{"StringMap.SetArray", SetTrieArray},
|
||||||
{"StringMap.SetString", SetTrieString},
|
{"StringMap.SetString", SetTrieString},
|
||||||
{"StringMap.SetValue", SetTrieValue},
|
{"StringMap.SetValue", SetTrieValue},
|
||||||
{"StringMap.Size.get", GetTrieSize},
|
{"StringMap.Size.get", GetTrieSize},
|
||||||
{"StringMap.Snapshot", CreateTrieSnapshot},
|
{"StringMap.Snapshot", CreateTrieSnapshot},
|
||||||
|
{"StringMap.Clone", CloneTrie},
|
||||||
|
|
||||||
{"StringMapSnapshot.Length.get", TrieSnapshotLength},
|
{"StringMapSnapshot.Length.get", TrieSnapshotLength},
|
||||||
{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize},
|
{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize},
|
||||||
|
@ -127,6 +127,8 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_pSM->SetGlobalTarget(index);
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
char *fmt;
|
char *fmt;
|
||||||
int arg = 3;
|
int arg = 3;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,8 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
@ -62,11 +64,11 @@ struct Transaction
|
|||||||
{
|
{
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
ke::AString query;
|
std::string query;
|
||||||
cell_t data;
|
cell_t data;
|
||||||
};
|
};
|
||||||
|
|
||||||
ke::Vector<Entry> entries;
|
std::vector<Entry> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseHelpers :
|
class DatabaseHelpers :
|
||||||
@ -455,7 +457,7 @@ static cell_t ConnectToDbAsync(IPluginContext *pContext, const cell_t *params, A
|
|||||||
g_pSM->Format(error,
|
g_pSM->Format(error,
|
||||||
sizeof(error),
|
sizeof(error),
|
||||||
"Could not find driver \"%s\"",
|
"Could not find driver \"%s\"",
|
||||||
pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName().chars() : pInfo->driver);
|
pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName().c_str() : pInfo->driver);
|
||||||
} else if (!driver->IsThreadSafe()) {
|
} else if (!driver->IsThreadSafe()) {
|
||||||
g_pSM->Format(error,
|
g_pSM->Format(error,
|
||||||
sizeof(error),
|
sizeof(error),
|
||||||
@ -1538,9 +1540,9 @@ static cell_t SQL_AddQuery(IPluginContext *pContext, const cell_t *params)
|
|||||||
Transaction::Entry entry;
|
Transaction::Entry entry;
|
||||||
entry.query = query;
|
entry.query = query;
|
||||||
entry.data = params[3];
|
entry.data = params[3];
|
||||||
txn->entries.append(ke::Move(entry));
|
txn->entries.push_back(std::move(entry));
|
||||||
|
|
||||||
return cell_t(txn->entries.length() - 1);
|
return cell_t(txn->entries.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
class TTransactOp : public IDBThreadOperation
|
class TTransactOp : public IDBThreadOperation
|
||||||
@ -1562,7 +1564,7 @@ public:
|
|||||||
|
|
||||||
~TTransactOp()
|
~TTransactOp()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < results_.length(); i++)
|
for (size_t i = 0; i < results_.size(); i++)
|
||||||
results_[i]->Destroy();
|
results_[i]->Destroy();
|
||||||
results_.clear();
|
results_.clear();
|
||||||
}
|
}
|
||||||
@ -1583,7 +1585,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool Succeeded() const
|
bool Succeeded() const
|
||||||
{
|
{
|
||||||
return error_.length() == 0;
|
return error_.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDbError()
|
void SetDbError()
|
||||||
@ -1615,16 +1617,16 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < txn_->entries.length(); i++)
|
for (size_t i = 0; i < txn_->entries.size(); i++)
|
||||||
{
|
{
|
||||||
Transaction::Entry &entry = txn_->entries[i];
|
Transaction::Entry &entry = txn_->entries[i];
|
||||||
IQuery *result = Exec(entry.query.chars());
|
IQuery *result = Exec(entry.query.c_str());
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
failIndex_ = (cell_t)i;
|
failIndex_ = (cell_t)i;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results_.append(result);
|
results_.push_back(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!db_->DoSimpleQuery("COMMIT"))
|
if (!db_->DoSimpleQuery("COMMIT"))
|
||||||
@ -1665,11 +1667,11 @@ private:
|
|||||||
// Add an extra refcount for the handle.
|
// Add an extra refcount for the handle.
|
||||||
db_->AddRef();
|
db_->AddRef();
|
||||||
|
|
||||||
assert(results_.length() == txn_->entries.length());
|
assert(results_.size() == txn_->entries.size());
|
||||||
|
|
||||||
ke::AutoPtr<cell_t[]> data = ke::MakeUnique<cell_t[]>(results_.length());
|
std::unique_ptr<cell_t[]> data = std::make_unique<cell_t[]>(results_.size());
|
||||||
ke::AutoPtr<cell_t[]> handles = ke::MakeUnique<cell_t[]>(results_.length());
|
std::unique_ptr<cell_t[]> handles = std::make_unique<cell_t[]>(results_.size());
|
||||||
for (size_t i = 0; i < results_.length(); i++)
|
for (size_t i = 0; i < results_.size(); i++)
|
||||||
{
|
{
|
||||||
CombinedQuery *obj = new CombinedQuery(results_[i], db_);
|
CombinedQuery *obj = new CombinedQuery(results_[i], db_);
|
||||||
Handle_t rh = CreateLocalHandle(hCombinedQueryType, obj, &sec);
|
Handle_t rh = CreateLocalHandle(hCombinedQueryType, obj, &sec);
|
||||||
@ -1680,7 +1682,7 @@ private:
|
|||||||
delete obj;
|
delete obj;
|
||||||
for (size_t iter = 0; iter < i; iter++)
|
for (size_t iter = 0; iter < i; iter++)
|
||||||
handlesys->FreeHandle(handles[iter], &sec);
|
handlesys->FreeHandle(handles[iter], &sec);
|
||||||
for (size_t iter = i; iter < results_.length(); iter++)
|
for (size_t iter = i; iter < results_.size(); iter++)
|
||||||
results_[iter]->Destroy();
|
results_[iter]->Destroy();
|
||||||
handlesys->FreeHandle(dbh, &sec);
|
handlesys->FreeHandle(dbh, &sec);
|
||||||
results_.clear();
|
results_.clear();
|
||||||
@ -1696,15 +1698,15 @@ private:
|
|||||||
{
|
{
|
||||||
success_->PushCell(dbh);
|
success_->PushCell(dbh);
|
||||||
success_->PushCell(data_);
|
success_->PushCell(data_);
|
||||||
success_->PushCell(txn_->entries.length());
|
success_->PushCell(txn_->entries.size());
|
||||||
success_->PushArray(handles.get(), results_.length());
|
success_->PushArray(handles.get(), results_.size());
|
||||||
success_->PushArray(data.get(), results_.length());
|
success_->PushArray(data.get(), results_.size());
|
||||||
success_->Execute(NULL);
|
success_->Execute(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup. Note we clear results_, since freeing their handles will
|
// Cleanup. Note we clear results_, since freeing their handles will
|
||||||
// call Destroy(), and we don't want to double-free in ~TTransactOp.
|
// call Destroy(), and we don't want to double-free in ~TTransactOp.
|
||||||
for (size_t i = 0; i < results_.length(); i++)
|
for (size_t i = 0; i < results_.size(); i++)
|
||||||
handlesys->FreeHandle(handles[i], &sec);
|
handlesys->FreeHandle(handles[i], &sec);
|
||||||
handlesys->FreeHandle(dbh, &sec);
|
handlesys->FreeHandle(dbh, &sec);
|
||||||
results_.clear();
|
results_.clear();
|
||||||
@ -1728,8 +1730,8 @@ public:
|
|||||||
{
|
{
|
||||||
HandleSecurity sec(ident_, g_pCoreIdent);
|
HandleSecurity sec(ident_, g_pCoreIdent);
|
||||||
|
|
||||||
ke::AutoPtr<cell_t[]> data = ke::MakeUnique<cell_t[]>(txn_->entries.length());
|
std::unique_ptr<cell_t[]> data = std::make_unique<cell_t[]>(txn_->entries.size());
|
||||||
for (size_t i = 0; i < txn_->entries.length(); i++)
|
for (size_t i = 0; i < txn_->entries.size(); i++)
|
||||||
data[i] = txn_->entries[i].data;
|
data[i] = txn_->entries[i].data;
|
||||||
|
|
||||||
Handle_t dbh = CreateLocalHandle(g_DBMan.GetDatabaseType(), db_, &sec);
|
Handle_t dbh = CreateLocalHandle(g_DBMan.GetDatabaseType(), db_, &sec);
|
||||||
@ -1743,10 +1745,10 @@ public:
|
|||||||
{
|
{
|
||||||
failure_->PushCell(dbh);
|
failure_->PushCell(dbh);
|
||||||
failure_->PushCell(data_);
|
failure_->PushCell(data_);
|
||||||
failure_->PushCell(txn_->entries.length());
|
failure_->PushCell(txn_->entries.size());
|
||||||
failure_->PushString(error_.chars());
|
failure_->PushString(error_.c_str());
|
||||||
failure_->PushCell(failIndex_);
|
failure_->PushCell(failIndex_);
|
||||||
failure_->PushArray(data.get(), txn_->entries.length());
|
failure_->PushArray(data.get(), txn_->entries.size());
|
||||||
failure_->Execute(NULL);
|
failure_->Execute(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1762,8 +1764,8 @@ private:
|
|||||||
IPluginFunction *failure_;
|
IPluginFunction *failure_;
|
||||||
cell_t data_;
|
cell_t data_;
|
||||||
AutoHandleRooter autoHandle_;
|
AutoHandleRooter autoHandle_;
|
||||||
ke::AString error_;
|
std::string error_;
|
||||||
ke::Vector<IQuery *> results_;
|
std::vector<IQuery *> results_;
|
||||||
cell_t failIndex_;
|
cell_t failIndex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public:
|
|||||||
}
|
}
|
||||||
void OnHandleDestroy(HandleType_t type, void *object)
|
void OnHandleDestroy(HandleType_t type, void *object)
|
||||||
{
|
{
|
||||||
CDataPack::Free(reinterpret_cast<CDataPack *>(object));
|
delete reinterpret_cast<CDataPack *>(object);
|
||||||
}
|
}
|
||||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
|
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
|
||||||
{
|
{
|
||||||
@ -73,7 +73,7 @@ public:
|
|||||||
|
|
||||||
static cell_t smn_CreateDataPack(IPluginContext *pContext, const cell_t *params)
|
static cell_t smn_CreateDataPack(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
CDataPack *pDataPack = CDataPack::New();
|
CDataPack *pDataPack = new CDataPack();
|
||||||
|
|
||||||
if (!pDataPack)
|
if (!pDataPack)
|
||||||
{
|
{
|
||||||
@ -166,6 +166,62 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t smn_WritePackCellArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError herr;
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
|
||||||
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
|
CDataPack *pDataPack = nullptr;
|
||||||
|
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params[4])
|
||||||
|
{
|
||||||
|
pDataPack->RemoveItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *pArray;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &pArray);
|
||||||
|
pDataPack->PackCellArray(pArray, params[3]);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t smn_WritePackFloatArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError herr;
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
|
||||||
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
|
CDataPack *pDataPack = nullptr;
|
||||||
|
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params[4])
|
||||||
|
{
|
||||||
|
pDataPack->RemoveItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *pArray;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &pArray);
|
||||||
|
pDataPack->PackFloatArray(pArray, params[3]);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params)
|
static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
@ -312,6 +368,108 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param
|
|||||||
return pDataPack->ReadFunction();
|
return pDataPack->ReadFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t smn_ReadPackCellArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError herr;
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
|
||||||
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
|
CDataPack *pDataPack = nullptr;
|
||||||
|
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pDataPack->IsReadable())
|
||||||
|
{
|
||||||
|
pContext->ReportError("Data pack operation is out of bounds.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDataPack->GetCurrentType() != CDataPackType::CellArray)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::CellArray);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t packCount = 0;
|
||||||
|
cell_t *pData = pDataPack->ReadCellArray(&packCount);
|
||||||
|
if(pData == nullptr || packCount == 0)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack operation: current position isn't an array!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t count = params[3];
|
||||||
|
if(packCount > count)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Input buffer too small (needed %d, got %d).", packCount, count);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *pArray;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &pArray);
|
||||||
|
|
||||||
|
memcpy(pArray, pData, sizeof(cell_t) * count);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t smn_ReadPackFloatArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError herr;
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
|
||||||
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
|
CDataPack *pDataPack = nullptr;
|
||||||
|
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pDataPack->IsReadable())
|
||||||
|
{
|
||||||
|
pContext->ReportError("Data pack operation is out of bounds.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDataPack->GetCurrentType() != CDataPackType::FloatArray)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::FloatArray);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t packCount = 0;
|
||||||
|
cell_t *pData = pDataPack->ReadFloatArray(&packCount);
|
||||||
|
if(pData == nullptr || packCount == 0)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Invalid data pack operation: current position isn't an array!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t count = params[3];
|
||||||
|
if(packCount > count)
|
||||||
|
{
|
||||||
|
pContext->ReportError("Input buffer too small (needed %d, got %d).", packCount, count);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *pArray;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &pArray);
|
||||||
|
|
||||||
|
memcpy(pArray, pData, sizeof(cell_t) * count);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
|
static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
@ -426,10 +584,14 @@ REGISTER_NATIVES(datapacknatives)
|
|||||||
{"DataPack.WriteFloat", smn_WritePackFloat},
|
{"DataPack.WriteFloat", smn_WritePackFloat},
|
||||||
{"DataPack.WriteString", smn_WritePackString},
|
{"DataPack.WriteString", smn_WritePackString},
|
||||||
{"DataPack.WriteFunction", smn_WritePackFunction},
|
{"DataPack.WriteFunction", smn_WritePackFunction},
|
||||||
|
{"DataPack.WriteCellArray", smn_WritePackCellArray},
|
||||||
|
{"DataPack.WriteFloatArray", smn_WritePackFloatArray},
|
||||||
{"DataPack.ReadCell", smn_ReadPackCell},
|
{"DataPack.ReadCell", smn_ReadPackCell},
|
||||||
{"DataPack.ReadFloat", smn_ReadPackFloat},
|
{"DataPack.ReadFloat", smn_ReadPackFloat},
|
||||||
{"DataPack.ReadString", smn_ReadPackString},
|
{"DataPack.ReadString", smn_ReadPackString},
|
||||||
{"DataPack.ReadFunction", smn_ReadPackFunction},
|
{"DataPack.ReadFunction", smn_ReadPackFunction},
|
||||||
|
{"DataPack.ReadCellArray", smn_ReadPackCellArray},
|
||||||
|
{"DataPack.ReadFloatArray", smn_ReadPackFloatArray},
|
||||||
{"DataPack.Reset", smn_ResetPack},
|
{"DataPack.Reset", smn_ResetPack},
|
||||||
{"DataPack.Position.get", smn_GetPackPosition},
|
{"DataPack.Position.get", smn_GetPackPosition},
|
||||||
{"DataPack.Position.set", smn_SetPackPosition},
|
{"DataPack.Position.set", smn_SetPackPosition},
|
||||||
|
367
core/logic/smn_entitylump.cpp
Normal file
367
core/logic/smn_entitylump.cpp
Normal file
@ -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}
|
||||||
|
};
|
44
core/logic/smn_entitylump.h
Normal file
44
core/logic/smn_entitylump.h
Normal file
@ -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_
|
@ -414,7 +414,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
|
|||||||
DetectExceptions eh(pContext);
|
DetectExceptions eh(pContext);
|
||||||
written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
|
written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
|
||||||
if (eh.HasException())
|
if (eh.HasException())
|
||||||
return 0;
|
return pContext->GetLastNativeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *addr;
|
cell_t *addr;
|
||||||
|
@ -29,12 +29,13 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
#include <ISourceMod.h>
|
#include <ISourceMod.h>
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
#include "NativeInvoker.h"
|
#include "NativeInvoker.h"
|
||||||
|
|
||||||
@ -746,7 +747,7 @@ struct SMFrameActionData
|
|||||||
|
|
||||||
static void PawnFrameAction(void *pData)
|
static void PawnFrameAction(void *pData)
|
||||||
{
|
{
|
||||||
ke::AutoPtr<SMFrameActionData> frame(reinterpret_cast<SMFrameActionData *>(pData));
|
std::unique_ptr<SMFrameActionData> frame(reinterpret_cast<SMFrameActionData *>(pData));
|
||||||
IPlugin *pPlugin = pluginsys->PluginFromHandle(frame->ownerhandle, NULL);
|
IPlugin *pPlugin = pluginsys->PluginFromHandle(frame->ownerhandle, NULL);
|
||||||
if (!pPlugin)
|
if (!pPlugin)
|
||||||
{
|
{
|
||||||
|
@ -162,6 +162,38 @@ static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||||
|
HandleError herr;
|
||||||
|
HandleSecurity sec;
|
||||||
|
IGameConfig *gc;
|
||||||
|
|
||||||
|
sec.pOwner = NULL;
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
|
||||||
|
if ((herr=handlesys->ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key;
|
||||||
|
void *val;
|
||||||
|
pCtx->LocalToString(params[2], &key);
|
||||||
|
|
||||||
|
if (!gc->GetMemSig(key, &val))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_X86
|
||||||
|
return (cell_t)val;
|
||||||
|
#else
|
||||||
|
return pseudoAddr.ToPseudoAddress(val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static GameConfigsNatives s_GameConfigsNatives;
|
static GameConfigsNatives s_GameConfigsNatives;
|
||||||
|
|
||||||
REGISTER_NATIVES(gameconfignatives)
|
REGISTER_NATIVES(gameconfignatives)
|
||||||
@ -176,5 +208,6 @@ REGISTER_NATIVES(gameconfignatives)
|
|||||||
{"GameData.GetOffset", smn_GameConfGetOffset},
|
{"GameData.GetOffset", smn_GameConfGetOffset},
|
||||||
{"GameData.GetKeyValue", smn_GameConfGetKeyValue},
|
{"GameData.GetKeyValue", smn_GameConfGetKeyValue},
|
||||||
{"GameData.GetAddress", smn_GameConfGetAddress},
|
{"GameData.GetAddress", smn_GameConfGetAddress},
|
||||||
|
{"GameData.GetMemSig", smn_GameConfGetMemSig},
|
||||||
{NULL, NULL}
|
{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)
|
|| last_time > pMapList->last_modified_time)
|
||||||
{
|
{
|
||||||
/* Reparse */
|
/* Reparse */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* 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);
|
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);
|
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||||
bool OnSetHandlerOption(const char *option, const void *data);
|
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:
|
private:
|
||||||
cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0);
|
cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0);
|
||||||
private:
|
private:
|
||||||
@ -485,7 +481,6 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *
|
|||||||
if (num_items > 1)
|
if (num_items > 1)
|
||||||
{
|
{
|
||||||
/* Yes, we do. */
|
/* Yes, we do. */
|
||||||
srand(time(NULL));
|
|
||||||
winning_item = rand() % num_items;
|
winning_item = rand() % num_items;
|
||||||
winning_item = results->item_list[winning_item].item;
|
winning_item = results->item_list[winning_item].item;
|
||||||
} else {
|
} else {
|
||||||
@ -497,99 +492,51 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *
|
|||||||
unsigned int winning_votes = results->item_list[0].count;
|
unsigned int winning_votes = results->item_list[0].count;
|
||||||
|
|
||||||
DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
|
DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
|
||||||
} else {
|
return;
|
||||||
IPluginContext *pContext = m_pVoteResults->GetParentContext();
|
}
|
||||||
bool no_call = false;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* First array */
|
IPluginContext *pContext = m_pVoteResults->GetParentContext();
|
||||||
cell_t client_array_address = -1;
|
AutoEnterHeapScope heap_scope(pContext);
|
||||||
cell_t *client_array_base = NULL;
|
|
||||||
cell_t client_array_size = results->num_clients + (results->num_clients * 2);
|
/* First array */
|
||||||
if (client_array_size)
|
cell_t client_array_address = -1;
|
||||||
{
|
if (cell_t client_array_size = results->num_clients * 2) {
|
||||||
if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
|
auto init = std::make_unique<cell_t[]>(client_array_size);
|
||||||
!= SP_ERROR_NONE)
|
for (unsigned int i = 0; i < results->num_clients; i++) {
|
||||||
{
|
init[i * 2] = results->client_list[i].client;
|
||||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
|
init[i * 2 + 1] = results->client_list[i].item;
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second array */
|
if (!pContext->HeapAlloc2dArray(results->num_clients, 2, &client_array_address, init.get())) {
|
||||||
cell_t item_array_address = -1;
|
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1,
|
||||||
cell_t *item_array_base = NULL;
|
"Menu callback could not allocate cells for client list.");
|
||||||
cell_t item_array_size = results->num_items + (results->num_items * 2);
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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)
|
bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data)
|
||||||
@ -1015,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 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)
|
static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user