Compare commits
514
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f250ba42d | ||
|
|
1b8bb4e049 | ||
|
|
34b8d00548 | ||
|
|
0a6cbadcd8 | ||
|
|
701fef1ba4 | ||
|
|
ba04132142 | ||
|
|
ea84302e28 | ||
|
|
08e2fc8deb | ||
|
|
ebed45a0f6 | ||
|
|
d3c279fd05 | ||
|
|
e69ed4b0da | ||
|
|
4daca3c5ba | ||
|
|
cb41fa6de4 | ||
|
|
dc758ead10 | ||
|
|
1fe38c7473 | ||
|
|
58ec9a4f38 | ||
|
|
b7477fc321 | ||
|
|
2bb3e5fd6b | ||
|
|
eedfd2d70d | ||
|
|
4bbd74b702 | ||
|
|
1d07d24054 | ||
|
|
7d3e32b65f | ||
|
|
04354a809c | ||
|
|
3cf30f5e62 | ||
|
|
7ff0129f36 | ||
|
|
b684d3aad7 | ||
|
|
f164419baa | ||
|
|
dcccfbd26a | ||
|
|
2fc0520895 | ||
|
|
7b1adfe00b | ||
|
|
28e1568eb7 | ||
|
|
0a6eac7c27 | ||
|
|
ecaced40f2 | ||
|
|
321443450a | ||
|
|
25a0a192a2 | ||
|
|
4563c00deb | ||
|
|
e26ce2b457 | ||
|
|
d1405f2ab3 | ||
|
|
2ff9b0aada | ||
|
|
acea705df8 | ||
|
|
30174c07de | ||
|
|
8e5c7713fc | ||
|
|
7b45342955 | ||
|
|
2f0965c14b | ||
|
|
c1c5d2656c | ||
|
|
af2af91300 | ||
|
|
c880919466 | ||
|
|
b1646accb9 | ||
|
|
00bb796db2 | ||
|
|
6c1259f6e6 | ||
|
|
a04521b55a | ||
|
|
c8b3c82a12 | ||
|
|
c1c8a4c988 | ||
|
|
335febca34 | ||
|
|
e191d446a7 | ||
|
|
412ad74aad | ||
|
|
e70fc299ac | ||
|
|
b3b972caf7 | ||
|
|
c25017e1a4 | ||
|
|
be1d12f94f | ||
|
|
3c18289465 | ||
|
|
ed29c837fa | ||
|
|
8d78c74554 | ||
|
|
e48bba5b4d | ||
|
|
547f7aecc1 | ||
|
|
67ba04bcee | ||
|
|
a1d84347ed | ||
|
|
253109d1c9 | ||
|
|
c0c9fc3267 | ||
|
|
918bec36d9 | ||
|
|
7b8cd751e1 | ||
|
|
849c4a70ae | ||
|
|
c231375e19 | ||
|
|
d8babe2a71 | ||
|
|
4e88a5a431 | ||
|
|
a6579c7bcb | ||
|
|
5a2f8afd33 | ||
|
|
3c12db8637 | ||
|
|
07cbe39552 | ||
|
|
974f31c149 | ||
|
|
4a1c565b62 | ||
|
|
32f9c46424 | ||
|
|
34d2d7760b | ||
|
|
2f36e3b231 | ||
|
|
b0d6e39035 | ||
|
|
b7a2f221f2 | ||
|
|
6d2bb90f51 | ||
|
|
fa1336623f | ||
|
|
2b65e2496d | ||
|
|
4953b1d889 | ||
|
|
ed75da0f85 | ||
|
|
ff7cb43f6a | ||
|
|
dc3b4a57cc | ||
|
|
7009e755fe | ||
|
|
bba2cfc6f7 | ||
|
|
759c76e188 | ||
|
|
db5a0be4ca | ||
|
|
29e57e77f7 | ||
|
|
f50c7469ca | ||
|
|
d9af295a29 | ||
|
|
4147bf7444 | ||
|
|
99e304d6b5 | ||
|
|
4e7000368f | ||
|
|
04b7b7b9ff | ||
|
|
2534fd1ce2 | ||
|
|
e10dd226ff | ||
|
|
b016623fb5 | ||
|
|
49d14111e2 | ||
|
|
f0a11d3cb7 | ||
|
|
168f42323b | ||
|
|
64e7d0b737 | ||
|
|
2e8c0c8f7d | ||
|
|
8f555543cc | ||
|
|
88a71ddad4 | ||
|
|
02e31bb576 | ||
|
|
32f7bec6c8 | ||
|
|
a935e6f90d | ||
|
|
f4dba84ae5 | ||
|
|
5cb4acf590 | ||
|
|
e83526aa63 | ||
|
|
04021ed8b1 | ||
|
|
31a4f40c9a | ||
|
|
4001b0f804 | ||
|
|
a838276ec2 | ||
|
|
6192efc078 | ||
|
|
4517031861 | ||
|
|
187ff255bd | ||
|
|
dec172f0e1 | ||
|
|
a0107299f3 | ||
|
|
bbbc2ce22c | ||
|
|
def0a8a0d6 | ||
|
|
46095d797c | ||
|
|
5687a7ba90 | ||
|
|
556c03babf | ||
|
|
09ea2e13aa | ||
|
|
ef62e3d665 | ||
|
|
fb2f0795c5 | ||
|
|
fb44b51d26 | ||
|
|
8680d07e0a | ||
|
|
9d8445b693 | ||
|
|
5de80c03db | ||
|
|
c5df0bf58f | ||
|
|
8c1502278b | ||
|
|
08e3e3b53d | ||
|
|
86591356b0 | ||
|
|
f62cf04f91 | ||
|
|
cf621eaf10 | ||
|
|
b8214a80c2 | ||
|
|
f79c9eec82 | ||
|
|
8fcecf3dec | ||
|
|
326e8ee205 | ||
|
|
bda56bf33f | ||
|
|
7439f15d7e | ||
|
|
7a4967abc9 | ||
|
|
6749545991 | ||
|
|
124c3f4575 | ||
|
|
56b77a536f | ||
|
|
e175cce776 | ||
|
|
097f42a01c | ||
|
|
bcf1b092ae | ||
|
|
d707ea0de5 | ||
|
|
2c107e3601 | ||
|
|
29d1246b8d | ||
|
|
514fc7dfe8 | ||
|
|
0691bca512 | ||
|
|
e1f8a0fd68 | ||
|
|
e141cf74d5 | ||
|
|
9ca1ca62ea | ||
|
|
99d27b979d | ||
|
|
681747d02c | ||
|
|
1ec936daf6 | ||
|
|
8eb6d9ccf5 | ||
|
|
d3394453ff | ||
|
|
5caeebf807 | ||
|
|
d6a9cb427f | ||
|
|
cb4b1dce71 | ||
|
|
e6c5adfa24 | ||
|
|
444896104f | ||
|
|
e2791a3702 | ||
|
|
16ed584e39 | ||
|
|
d6a0cb8992 | ||
|
|
f99b82b53a | ||
|
|
32b7e2df98 | ||
|
|
0137219fb8 | ||
|
|
51f914fb30 | ||
|
|
f85eeb2adb | ||
|
|
6b213a9caf | ||
|
|
35f31b0f1a | ||
|
|
56a68f4dfd | ||
|
|
6e930f6048 | ||
|
|
4fc7fce4fd | ||
|
|
f27202202b | ||
|
|
deb7a123a6 | ||
|
|
9ef7dca666 | ||
|
|
fe4e39a2dd | ||
|
|
4951dccded | ||
|
|
58870a30fb | ||
|
|
05e18833ac | ||
|
|
08c2a087d8 | ||
|
|
05c8681336 | ||
|
|
bf5ee181fa | ||
|
|
094acb1039 | ||
|
|
93944e7f4b | ||
|
|
1251093ec1 | ||
|
|
c951a6ca7c | ||
|
|
70a594f354 | ||
|
|
9b03490b1a | ||
|
|
edb7b49c25 | ||
|
|
0c1c984eaf | ||
|
|
b595047fdf | ||
|
|
2c25c09420 | ||
|
|
f6b088c2e6 | ||
|
|
1cf87d4ad9 | ||
|
|
0aad4353cf | ||
|
|
7875fe1acd | ||
|
|
95aca7b61b | ||
|
|
e52e3c4639 | ||
|
|
eee77228e6 | ||
|
|
2b0cc7b4ea | ||
|
|
eaccf6f90b | ||
|
|
a01848c774 | ||
|
|
ea748cfdbd | ||
|
|
401c6b445d | ||
|
|
3c0b289694 | ||
|
|
8182bdb476 | ||
|
|
ae7e5a6a4b | ||
|
|
50eb77926e | ||
|
|
bd24893837 | ||
|
|
dad66c9204 | ||
|
|
9292e0f816 | ||
|
|
4d48fc7ae5 | ||
|
|
463cfb0015 | ||
|
|
3ed5d1e8d7 | ||
|
|
e64e2534eb | ||
|
|
67e28d7475 | ||
|
|
64b8049d70 | ||
|
|
dd75e88cbb | ||
|
|
c75d607a00 | ||
|
|
8126aa6bb8 | ||
|
|
846caf1298 | ||
|
|
c2917a8dd4 | ||
|
|
9e443cfdd3 | ||
|
|
b743af8a72 | ||
|
|
8a4c96b252 | ||
|
|
0392e55ef7 | ||
|
|
fa5ee3287f | ||
|
|
e1882f97a1 | ||
|
|
1a156deca5 | ||
|
|
5668f23b50 | ||
|
|
232f344c41 | ||
|
|
79cf4e07eb | ||
|
|
f9b294d89e | ||
|
|
a88d7c1cdc | ||
|
|
85760603b7 | ||
|
|
ea1f5e86c0 | ||
|
|
b1072d3b09 | ||
|
|
81632dda97 | ||
|
|
80fdbcf8c7 | ||
|
|
bd2361c8ae | ||
|
|
c9a81c0651 | ||
|
|
aa096f2385 | ||
|
|
53acb70260 | ||
|
|
6ef4c4b3ad | ||
|
|
4ac38946f2 | ||
|
|
af54ae6af7 | ||
|
|
2c23544b29 | ||
|
|
5351bbec71 | ||
|
|
492c913aa9 | ||
|
|
31dd23fbd9 | ||
|
|
3f38171d8c | ||
|
|
307adb34ab | ||
|
|
8a4af4d22f | ||
|
|
2e7b6b5ba5 | ||
|
|
9a02cb9dc8 | ||
|
|
43c085eea3 | ||
|
|
6a834ffef7 | ||
|
|
86c8ec847a | ||
|
|
2df2b791d8 | ||
|
|
0e1ae4d85b | ||
|
|
3d96f8f127 | ||
|
|
2cc809be0c | ||
|
|
d2d2578314 | ||
|
|
76b51aed07 | ||
|
|
d0cbd943f1 | ||
|
|
c67a3cd749 | ||
|
|
bf0354dbb9 | ||
|
|
bc4f24e94d | ||
|
|
73203fb7b3 | ||
|
|
89c49c3976 | ||
|
|
89a56ac3e1 | ||
|
|
3cc5bebfa9 | ||
|
|
f9cfe7e9da | ||
|
|
5c58f8c97b | ||
|
|
bb9f31e555 | ||
|
|
ce57617744 | ||
|
|
77a7bf385b | ||
|
|
52d2a1797d | ||
|
|
111a3a7169 | ||
|
|
a513a2a6f8 | ||
|
|
f3f46fc126 | ||
|
|
3cff457c6d | ||
|
|
853b080aa4 | ||
|
|
261023800e | ||
|
|
7314d81947 | ||
|
|
d530d0c726 | ||
|
|
b01dd0798c | ||
|
|
968045ae62 | ||
|
|
4106620928 | ||
|
|
ac9b9f8c2a | ||
|
|
cdf54a3db1 | ||
|
|
8a5d833c89 | ||
|
|
57bba6d83f | ||
|
|
2c08bb3a96 | ||
|
|
6d4938f6b5 | ||
|
|
7104e187cc | ||
|
|
2fc7a017e1 | ||
|
|
e0a69507a0 | ||
|
|
29de57d415 | ||
|
|
42359a243a | ||
|
|
81e40c32c8 | ||
|
|
350044c9a8 | ||
|
|
bc1bb2cba2 | ||
|
|
6079c927ad | ||
|
|
42f61acc45 | ||
|
|
bc8c9ba691 | ||
|
|
6e59d8ae5c | ||
|
|
749177d0b3 | ||
|
|
4a32aff158 | ||
|
|
ac68a441ee | ||
|
|
119592eefe | ||
|
|
72a1fb06d0 | ||
|
|
8a7ced18de | ||
|
|
06c8f3a093 | ||
|
|
22aa6561b5 | ||
|
|
9ac54e5fb2 | ||
|
|
2c94b1268a | ||
|
|
46ce91c4f7 | ||
|
|
953da3f6e0 | ||
|
|
076b5191c9 | ||
|
|
20d12fad9f | ||
|
|
b18bd78c51 | ||
|
|
c3492f0192 | ||
|
|
d595e020cd | ||
|
|
5b4f98b354 | ||
|
|
6e2ac7376e | ||
|
|
1a86604d99 | ||
|
|
049f63e6fd | ||
|
|
3aea76cfb3 | ||
|
|
3b4c800baa | ||
|
|
ca9b2784bd | ||
|
|
df83dbc04e | ||
|
|
81af704f58 | ||
|
|
627e4fd115 | ||
|
|
044ee841f2 | ||
|
|
c93d05f622 | ||
|
|
c824afc61e | ||
|
|
3d015908d9 | ||
|
|
bff2b0a95d | ||
|
|
c9b320d645 | ||
|
|
29ee014a94 | ||
|
|
aa73e41f29 | ||
|
|
0a829027eb | ||
|
|
9c7249a1e9 | ||
|
|
d9357d5224 | ||
|
|
73a20de2ff | ||
|
|
8cd8228251 | ||
|
|
02faa8fbd6 | ||
|
|
79485eef38 | ||
|
|
b2d25f2a77 | ||
|
|
e794883b1f | ||
|
|
2a11739e86 | ||
|
|
dea6b06e2c | ||
|
|
13cf254f08 | ||
|
|
531c359fb9 | ||
|
|
9550e55160 | ||
|
|
40e0857a29 | ||
|
|
47fa9d9464 | ||
|
|
d827c0fd2d | ||
|
|
c16afc9cd3 | ||
|
|
a18b1e0790 | ||
|
|
80b2ea646a | ||
|
|
f7613f80f1 | ||
|
|
b90386276f | ||
|
|
8ad5d61878 | ||
|
|
b2fbd9691d | ||
|
|
0fac3fd74e | ||
|
|
3342a84cf4 | ||
|
|
21359ea17e | ||
|
|
a7cc2609e1 | ||
|
|
9023afff0d | ||
|
|
f388b0612b | ||
|
|
c7dbacc134 | ||
|
|
d88ba02fde | ||
|
|
6e91780e73 | ||
|
|
77ff2c40bd | ||
|
|
aee95b6c74 | ||
|
|
f1ef53cdff | ||
|
|
9a7c884c21 | ||
|
|
c7418e70ba | ||
|
|
1e70b04f48 | ||
|
|
1adb549a8d | ||
|
|
35eb2f2ce5 | ||
|
|
2030ef9114 | ||
|
|
c5330c73b7 | ||
|
|
7a968cb33c | ||
|
|
a2aa6b0daf | ||
|
|
8df36003a8 | ||
|
|
f226e6d70b | ||
|
|
394424c52f | ||
|
|
5c6a2868d9 | ||
|
|
62047b6d0d | ||
|
|
5e721623a0 | ||
|
|
90b739ae48 | ||
|
|
7262dd5e79 | ||
|
|
f41aefc525 | ||
|
|
0c22ab3972 | ||
|
|
221e7d48a7 | ||
|
|
21c0466b3d | ||
|
|
47f8d0eef5 | ||
|
|
d0286c1391 | ||
|
|
eac0e274a6 | ||
|
|
af05dbbcdf | ||
|
|
ac256a6c24 | ||
|
|
0771411eac | ||
|
|
e6de7c0c2d | ||
|
|
8d021c6caf | ||
|
|
9487f9d631 | ||
|
|
678cb82ec0 | ||
|
|
c4c8948d95 | ||
|
|
1e1f0de4ec | ||
|
|
84bde330cd | ||
|
|
e63a5cd3dc | ||
|
|
6c38c9264e | ||
|
|
946834b868 | ||
|
|
726aa68be9 | ||
|
|
16bdac4635 | ||
|
|
d014010a99 | ||
|
|
07915461e9 | ||
|
|
e24f15e7df | ||
|
|
90d4fed4a9 | ||
|
|
101d2359de | ||
|
|
046ce18e8b | ||
|
|
883e77bc60 | ||
|
|
6d2a3a7964 | ||
|
|
2fbd32cd1a | ||
|
|
800838d76a | ||
|
|
93b2edde8c | ||
|
|
a483ec5dc5 | ||
|
|
c42a26bb66 | ||
|
|
75a77c1925 | ||
|
|
c473d75d3d | ||
|
|
0c5e4b5a2f | ||
|
|
dcb9efa131 | ||
|
|
70301419b1 | ||
|
|
ad37496d34 | ||
|
|
472e9969d9 | ||
|
|
e1aba62c15 | ||
|
|
3a061aa38d | ||
|
|
d5f5239eeb | ||
|
|
8ba1d5e333 | ||
|
|
e618900688 | ||
|
|
ec69b34cbb | ||
|
|
430a860927 | ||
|
|
f08ce7f62f | ||
|
|
13e8cf9ed8 | ||
|
|
53d11eae63 | ||
|
|
72b6510e61 | ||
|
|
ea189849de | ||
|
|
8a2c175420 | ||
|
|
544ed79284 | ||
|
|
222b543adb | ||
|
|
2bec3aaa49 | ||
|
|
50c50a8f6c | ||
|
|
f0f44687b6 | ||
|
|
f295c6f4fd | ||
|
|
b455ac4f4e | ||
|
|
3d349378ad | ||
|
|
b865f96886 | ||
|
|
10bd6c298e | ||
|
|
4d3d51b5dd | ||
|
|
51d5f79f1e | ||
|
|
9b4bdd05b5 | ||
|
|
a0b05dc624 | ||
|
|
79fb305722 | ||
|
|
fbe46934a4 | ||
|
|
b9bd1b1037 | ||
|
|
b9aac380d4 | ||
|
|
127c89de4e | ||
|
|
251cced1f8 | ||
|
|
02931c94cf | ||
|
|
3a14544385 | ||
|
|
33b2847ec3 | ||
|
|
a3d5a0151d | ||
|
|
97c26eee3c | ||
|
|
cc3c16c079 | ||
|
|
c5af41d983 | ||
|
|
3bcd296d99 | ||
|
|
83a1ebcf0f | ||
|
|
8ba6d5cbba | ||
|
|
bb85c5eda2 | ||
|
|
a64894bbe4 | ||
|
|
50760d853f | ||
|
|
62b08e923c | ||
|
|
2f41af814e | ||
|
|
d28eca4bb3 | ||
|
|
306be48027 | ||
|
|
4ad308897f | ||
|
|
f6b6dff4c0 | ||
|
|
3ba7c63862 | ||
|
|
20112fe6cc | ||
|
|
3f49d29274 | ||
|
|
0601988e80 | ||
|
|
9eb41bc475 | ||
|
|
7cd5c96087 |
@@ -0,0 +1,15 @@
|
||||
# Binaries
|
||||
\.dll$
|
||||
\.exe$
|
||||
\.so$
|
||||
|
||||
# Files generated by Visual Studio
|
||||
\.aps$
|
||||
\.ncb$
|
||||
\.suo$
|
||||
\.user$
|
||||
|
||||
# Build directories
|
||||
/CrazyDebug.*
|
||||
/Debug.*
|
||||
/Release.*
|
||||
+3
-18
@@ -1,21 +1,6 @@
|
||||
We now use svn:keywords "Id" on all .c/.cpp/.h/.sp/.inc files. Please make sure your client is configured properly.
|
||||
|
||||
WINDOWS:
|
||||
Open your Application Data folder.
|
||||
Windows XP/2000: C:\Documents and Settings\<user>\Application Data
|
||||
Windows Vista: C:\Users\<user>\AppData\Roaming
|
||||
CONFIGURE YOUR IDENTITY FOR MERCURIAL!
|
||||
IF YOU ARE A DEVELOPER WITH PUSH ACCESS, DO IT NOW KPLZTHX.
|
||||
|
||||
Now go to Subversion. Open the "config" file with a text editor.
|
||||
http://wiki.alliedmods.net/Mercurial_Tutorial#Identity
|
||||
|
||||
LINUX:
|
||||
Open ~/.subversion/config with your favorite text editor.
|
||||
|
||||
Under [miscellany], uncomment this line:
|
||||
# enable-auto-props = yes
|
||||
|
||||
Under [auto-props], add these lines:
|
||||
*.c = svn:keywords=Id
|
||||
*.cpp = svn:keywords=Id
|
||||
*.h = svn:keywords=Id
|
||||
*.sp = svn:keywords=Id
|
||||
*.inc = svn:keywords=Id
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
SourceMod Changelog
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.1.0 [2008-12-28]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.1.0_Release_Notes
|
||||
|
||||
Major features:
|
||||
* New map management plugins.
|
||||
* New reserved slot type.
|
||||
* GameData updates are retrieved remotely
|
||||
* Client Preferences extension for per-client "cookies"
|
||||
* New incremental and independent JIT
|
||||
|
||||
Changes:
|
||||
|
||||
- Added new client preferences extension (API in clientprefs.inc, bug 1925).
|
||||
- Added new gamedata auto-update functionality (bug 2602).
|
||||
- Revamped and greatly expanded map management plugins and their functionality (bug 2201).
|
||||
- Debug mode is now always on; as there is no longer a performance loss, there is no non-debug mode.
|
||||
- The timeleft trigger can now handle mp_winlimit, mp_fraglimit, and mp_maxrounds (bug 2344).
|
||||
- Translations can now be in separate files and placed in language-unique folders.
|
||||
- The leading "STEAM_0:" or "STEAM_1:" in SteamIDs can now be omitted from admin files.
|
||||
- Added sm_revote command so clients can participate in a vote that fell off their screen (bug 2156).
|
||||
- Added Core API for creating stack structures (adt_stack.inc, bug 2441).
|
||||
- Added API for extending mapchooser (mapchooser.inc, bug 2201).
|
||||
- Added Core API for map transition control and history (nextmap.inc).
|
||||
- Added TF2 forward for overriding how critical hits are calculated.
|
||||
- Added SetClientInfo() native for modifying how a server sees a client's setinfo properties.
|
||||
- Added CreateDirectory() native (bug 3253).
|
||||
- Added "magic" MaxClients variable to replace slower GetMaxClients() call.
|
||||
- Added support for three-letter language codes (bug 3526).
|
||||
- Functions to control client versus client mic listening now work as described (bug 2498).
|
||||
- Fixed SDKTools not being reloadable, and fixed a related bug in Handle type removal (bug 2753).
|
||||
- Rewrote internal translation handling. Extensions now have access to an ITranslator API (bug 2535).
|
||||
- Rewrote internal handling of dependencies (especially relating to native providers) (bug 2466).
|
||||
- Added user config hooks to IGameConfigManager, for parsing user-defined sections.
|
||||
- Revamped SourcePawn API. Removed and deprecated many structures and functions accidentally exposed publicly.
|
||||
- Revamped SourcePawn structure, it is now separable from SourceMod for other projects.
|
||||
- Renamed basefuncommands.phrases.txt to funcommands.phrases.txt (bug 2485).
|
||||
- Renamed basefunvotes.phrases.txt to funvotes.phrases.txt (bug 2485).
|
||||
- Added IDBDriver API call for extensions to handle IDBDriver dependencies properly.
|
||||
- Usermessage natives now validate clients to prevent crashing.
|
||||
- Fixed OnConfigsExecuted not working on listen servers.
|
||||
- Fixed out-of-handle conditions in CreateTimer() causing crashes (bug 3381).
|
||||
- Fixed accessing invalid Handles causing crashes (bug 3359).
|
||||
- Fixed memory corruption with MySQL + FetchString (bug 3352).
|
||||
- Fixed ReadFileString ignoring its fourth parameter (bug 3459).
|
||||
- Fixed sm_sql_addadmin reading the immunity field as a password (bug 3395).
|
||||
- Fixed ReadFile sign-extending instead of zero-extending (bug 3449).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.0.4 [2008-09-14]
|
||||
|
||||
Changes:
|
||||
|
||||
- Fixed amb1986: Format() with very long strings could crash if the input and output buffers overlapped.
|
||||
- Fixed amb1938: The compiler ate too many characters in preprocessor macros.
|
||||
- Fixed amb1935: Topmenu child names were not uncached when a category was deleted.
|
||||
- Fixed amb1929: Banning via the console threw a runtime error.
|
||||
- Fixed amb1918: Ban menu should compare userids, not client indexes
|
||||
- Fixed amb1916: Threaded query delay is now 50ms instead of 500ms.
|
||||
- Fixed amb1899: Duplicate maps in auto generated maplists.
|
||||
- Fixed amb1891: Basechat didn't check for blank message in private says.
|
||||
- Fixed amb1853: Ternary operators with string assignments could chop strings off.
|
||||
- Fixed amb1815: Custom admin menu wasn't escaping input.
|
||||
- Fixed amb1808: KickClient() is now delayed to prevent crashes, use KickClientEx for old functionality.
|
||||
- Fixed amb1802: Possible crash when a client disconnected.
|
||||
- Fixed amb1801: Improved bot detection, and fixed bots crashing if inside an OrangeBox server.cfg.
|
||||
- Fixed amb1780: admin-sql-threaded had a debug spew turned on.
|
||||
- Fixed amb1779: Crash in GetTeamName() on mods that don't support it.
|
||||
- Fixed amb1763: Function call status is now cleared on a new function call.
|
||||
- Fixed amb1749: Updated and improved DoD:S SDKTools coverage.
|
||||
- Fixed team native crashes in SDKTools for mods like Insurgency.
|
||||
- Fixed various file handle leaks.
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.0.3 [2008-06-21]
|
||||
|
||||
Changes:
|
||||
|
||||
- Fixed SDKTools compatibility for latest TF2 update.
|
||||
- Fixed amb1750: OnAutoConfigsBuffered() inserted before "exec server.cfg".
|
||||
- Fixed a logic bug where OnConfigsExecuted() could be executed before "exec server.cfg" finished.
|
||||
- Fixed a rare crash in the event manager that manifested on Zombie Panic! Source.
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.0.2 [2008-05-31]
|
||||
|
||||
Changes:
|
||||
|
||||
- The admin menu is now user-modifiable (the "Dynamic Admin Menu").
|
||||
- Added a TF2 extension with Team Fortress functions.
|
||||
- Added a RegEx extension with regular expression functions.
|
||||
- Added functions to SDKTools for hooking entity outputs.
|
||||
- Added preliminary support for the DoD:S Orange Box beta.
|
||||
- Added a forward for map config plugins for preventing race conditions.
|
||||
- Added a %b format specifier for binary printing.
|
||||
- Added sm_dump_datamaps command (SDKTools) for enumerating datamap properties.
|
||||
- Added sm_dump_admcache command for debugging the admin cache.
|
||||
- Added amb1715 - TraceHull functions to SDKTools (complementing TraceRay).
|
||||
- Added amb1694 - FindCharInString() function.
|
||||
- Added amb1685 - GetTickInterval() function.
|
||||
- Added amb1620 - ActivateEntity() function to SDKTools (for Orange Box particle system).
|
||||
- Added amb1610 - StripQuotes() function.
|
||||
- Added amb1558 - Compiler now has __BINARY_PATH__ and __BINARY_FILE__ macros.
|
||||
- Fixed amb1686 - ReplaceString* with an empty search string crashed; it now throws an error.
|
||||
- Fixed amb1684 - Blank passwords required an empty but set password.
|
||||
- Fixed amb1595 - Extension load failures did not show a platform error message.
|
||||
- Fixed amb1583 - MySQL string fetch from prepared queries returned corrupted data.
|
||||
- Fixed amb1358 - Timeleft did not reset on TF2 restarts.
|
||||
- Fixed cases where the JIT was too cautious in space optimizations.
|
||||
- Fixed TF2/Cstrike extensions being loadable on incompatible games.
|
||||
- Fixed various documentation inconsistencies and typos.
|
||||
- Fixed internal bugs with file extension handling.
|
||||
|
||||
Notes:
|
||||
|
||||
There is a possible compatibility regression from amb1684. SetAdminPassword()
|
||||
has been modified to remove any set password when given an empty string. Previously,
|
||||
a blank password ("") would force an admin to use "setinfo" to set an empty password,
|
||||
but this functionality was deemed unuseful and unintended. Blank passwords now
|
||||
remove any set password.
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.0.1 [2008-05-20]
|
||||
|
||||
Changes:
|
||||
|
||||
- Fixed SDKTools compatibility for latest TF2 update.
|
||||
- Removed GivePlayerItem from TF2 (TF2 update broke functionality).
|
||||
- Fixed amb1688: GivePlayerItem offset was wrong for DoD:S Linux.
|
||||
- Fixed amb1657: Server console did not see admin version of sm_who.
|
||||
- Fixed amb1648: Stack corruption from GetClientEyeAngles() on Windows.
|
||||
- Fixed amb1646: NetFlow_Both did not work for client network statistics.
|
||||
- Fixed amb1601: Vote FF menu reading from sv_alltalk cvar instead of mp_friendlyfire.
|
||||
- Fixed amb1591: Fixed listen server crashes on mods like IOS:S which pre-add more than one bot.
|
||||
- Fixed amb1586: GetTeamName() could crash the server if called on load.
|
||||
- Fixed mapchooser's round counting for TF2.
|
||||
- Fixed a bug where an RTE on plugin load would throw a message referring to the plugin as "-1".
|
||||
- Symbols are no longer stripped on Linux.
|
||||
- Minor SourceMod SDK fixes.
|
||||
|
||||
Notes:
|
||||
|
||||
The extension interface version has been bumped. Any extensions compiled against 1.0.1 will require 1.0.1 or higher to run. Extensions against 1.0.0 will continue to run normally.
|
||||
@@ -0,0 +1,12 @@
|
||||
// Custom admin menu commands.
|
||||
// For more information:
|
||||
//
|
||||
// http://wiki.alliedmods.net/Custom_Admin_Menu_%28SourceMod%29
|
||||
//
|
||||
// Note: This file must be in Valve KeyValues format (no multiline comments)
|
||||
//
|
||||
|
||||
"Commands"
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Add group options to be added to 'group' or 'groupplayer' type submenus
|
||||
* The left side is the name that will show in the menu, right is the command that will be fired
|
||||
*
|
||||
* For more information: http://wiki.alliedmods.net/Custom_Admin_Menu_%28SourceMod%29
|
||||
*/
|
||||
|
||||
Groups
|
||||
{
|
||||
"All" "@all"
|
||||
"Bots" "@bots"
|
||||
"Alive" "@alive"
|
||||
"Dead" "@dead"
|
||||
"Humans" "@humans"
|
||||
"Current aim" "@aim"
|
||||
|
||||
/* You can enable these if you are using Counter-Strike Source and running the cstrike extension */
|
||||
// "Terrorists" "@t"
|
||||
// "Counter-Terrorists" "@ct"
|
||||
|
||||
}
|
||||
@@ -88,4 +88,35 @@
|
||||
* "off" - Translate using default server's language
|
||||
*/
|
||||
"AllowClLanguageVar" "On"
|
||||
|
||||
/**
|
||||
* Enables or Disables SourceMod's automatic gamedata updating.
|
||||
*
|
||||
* The default value is "no". A value of "yes" will block the Auto Updater.
|
||||
*/
|
||||
"DisableAutoUpdate" "no"
|
||||
|
||||
/**
|
||||
* If set to yes, a successful gamedata update will attempt to restart SourceMod.
|
||||
* SourceMod is unloaded and reloaded, and the map is changed to the current map.
|
||||
* Since gamedata updates occur when the server loads, impact should be minimal.
|
||||
* But to be safe, this option is disabled by default.
|
||||
*/
|
||||
"ForceRestartAfterUpdate" "no"
|
||||
|
||||
/**
|
||||
* Sets the server to connect to for auotmatic gamedata updates.
|
||||
*/
|
||||
"AutoUpdateServer" "smupdate.alliedmods.net"
|
||||
|
||||
/**
|
||||
* Sets the port to connect to on the AutoUpdateServer server
|
||||
*/
|
||||
"AutoUpdatePort" "6500"
|
||||
|
||||
/**
|
||||
* Whether to show debug spew.
|
||||
* Currently this will log details about the gamedata updating process.
|
||||
*/
|
||||
"DebugSpew" "no"
|
||||
}
|
||||
|
||||
@@ -18,4 +18,15 @@
|
||||
"driver" "sqlite"
|
||||
"database" "sourcemod-local"
|
||||
}
|
||||
|
||||
"clientprefs"
|
||||
{
|
||||
"driver" "sqlite"
|
||||
"host" "localhost"
|
||||
"database" "clientprefs-sqlite"
|
||||
"user" "root"
|
||||
"pass" ""
|
||||
//"timeout" "0"
|
||||
//"port" "0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"Languages"
|
||||
{
|
||||
"en" "English"
|
||||
"es" "Español"
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,15 @@
|
||||
"target" "default"
|
||||
}
|
||||
|
||||
/* For the "randomcycle" plugin */
|
||||
/* For the "rockthevote" plugin */
|
||||
"rockthevote"
|
||||
{
|
||||
"target" "default"
|
||||
}
|
||||
|
||||
/* For the "nominations" plugin */
|
||||
"nominations"
|
||||
{
|
||||
"target" "default"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
* Available properties for plugins are:
|
||||
* "pause" - Whether or not the plugin should load paused - "yes" or "no" (default)
|
||||
* "lifetime" - Lifetime of the plugin. Options:
|
||||
* "mapsync" - Plugins should be reloaded on mapchange if changed (default)
|
||||
* "global" - Plugin will never be unloaded or updated
|
||||
* "mapsync" - Plugins should be reloaded on mapchange if changed (default)
|
||||
* "global" - Plugin will never be unloaded or updated
|
||||
* "blockload" - Plugin will always be blocked from loading. Implicit (automatic) loads
|
||||
* produce no error, but explicit (manual) loads will show an error message.
|
||||
* (Options are one of "yes" or "no")
|
||||
*
|
||||
* You can also have an "Options" section declaring options to pass onto the JIT:
|
||||
* "debug" - Whether or not to load the plugin in debug mode
|
||||
* "profile" - Bit flags for profiling level. Add flags together to reach a value.
|
||||
* WARNING: Profiler is _ALPHA_ software! Use it at your own risk for
|
||||
* development cycles only (not production setups).
|
||||
@@ -32,7 +31,6 @@
|
||||
|
||||
"Options"
|
||||
{
|
||||
"debug" "no"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE sm_cookies
|
||||
(
|
||||
id INTEGER unsigned NOT NULL auto_increment,
|
||||
name varchar(30) NOT NULL UNIQUE,
|
||||
description varchar(255),
|
||||
access INTEGER,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_cookie_cache
|
||||
(
|
||||
player varchar(65) NOT NULL,
|
||||
cookie_id int(10) NOT NULL,
|
||||
value varchar(100),
|
||||
timestamp int NOT NULL,
|
||||
PRIMARY KEY (player, cookie_id)
|
||||
);
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE sm_cookies
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name varchar(30) NOT NULL UNIQUE,
|
||||
description varchar(255),
|
||||
access INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE sm_cookie_cache
|
||||
(
|
||||
player varchar(65) NOT NULL,
|
||||
cookie_id int(10) NOT NULL,
|
||||
value varchar(100),
|
||||
timestamp int,
|
||||
PRIMARY KEY (player, cookie_id)
|
||||
);
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+367
-6
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -41,12 +41,14 @@
|
||||
#include "sourcemod.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_srvcmds.h"
|
||||
|
||||
#define LEVEL_STATE_NONE 0
|
||||
#define LEVEL_STATE_LEVELS 1
|
||||
#define LEVEL_STATE_FLAGS 2
|
||||
|
||||
AdminCache g_Admins;
|
||||
char g_ReverseFlags[26];
|
||||
AdminFlag g_FlagLetters[26];
|
||||
bool g_FlagSet[26];
|
||||
|
||||
@@ -160,8 +162,6 @@ private:
|
||||
|
||||
c -= (unsigned)'a';
|
||||
|
||||
assert(c >= 0 && c < 26);
|
||||
|
||||
if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
|
||||
{
|
||||
ParseError(states, "Unrecognized admin level \"%s\"", key);
|
||||
@@ -299,8 +299,23 @@ void AdminCache::OnSourceModAllInitialized()
|
||||
|
||||
void AdminCache::OnSourceModLevelChange(const char *mapName)
|
||||
{
|
||||
int i;
|
||||
AdminFlag flag;
|
||||
|
||||
/* For now, we only read these once per level. */
|
||||
s_FlagReader.LoadLevels();
|
||||
|
||||
for (i = 0; i < 26; i++)
|
||||
{
|
||||
if (FindFlag('a' + i, &flag))
|
||||
{
|
||||
g_ReverseFlags[flag] = 'a' + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ReverseFlags[flag] = '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdminCache::OnSourceModShutdown()
|
||||
@@ -434,7 +449,9 @@ AdminId AdminCache::CreateAdmin(const char *name)
|
||||
assert(pUser->magic == USR_MAGIC_UNSET);
|
||||
id = m_FreeUserList;
|
||||
m_FreeUserList = pUser->next_user;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
|
||||
pUser->grp_size = 0;
|
||||
pUser->grp_table = -1;
|
||||
@@ -454,19 +471,28 @@ AdminId AdminCache::CreateAdmin(const char *name)
|
||||
{
|
||||
m_FirstUser = id;
|
||||
m_LastUser = id;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
|
||||
pPrev->next_user = id;
|
||||
pUser->prev_user = m_LastUser;
|
||||
m_LastUser = id;
|
||||
}
|
||||
|
||||
/* Since we always append to the tail, we should invalidate their next */
|
||||
pUser->next_user = -1;
|
||||
|
||||
if (name && name[0] != '\0')
|
||||
{
|
||||
int nameidx = m_pStrings->AddString(name);
|
||||
pUser = (AdminUser *)m_pMemory->GetAddress(id);
|
||||
pUser->nameidx = nameidx;
|
||||
}
|
||||
else
|
||||
{
|
||||
pUser->nameidx = -1;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -1156,6 +1182,12 @@ bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ide
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the id was a steam id strip off the STEAM_*: part */
|
||||
if (strcmp(auth, "steam") == 0 && strncmp(ident, "STEAM_", 6) == 0)
|
||||
{
|
||||
ident += 8;
|
||||
}
|
||||
|
||||
if (sm_trie_retrieve(pTable, ident, NULL))
|
||||
{
|
||||
return false;
|
||||
@@ -1178,6 +1210,12 @@ AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
|
||||
return INVALID_ADMIN_ID;
|
||||
}
|
||||
|
||||
/* If the id was a steam id strip off the STEAM_*: part */
|
||||
if (strcmp(auth, "steam") == 0 && strncmp(identity, "STEAM_", 6) == 0)
|
||||
{
|
||||
identity += 8;
|
||||
}
|
||||
|
||||
void *object;
|
||||
if (!sm_trie_retrieve(pTable, identity, &object))
|
||||
{
|
||||
@@ -1412,6 +1450,12 @@ void AdminCache::SetAdminPassword(AdminId id, const char *password)
|
||||
return;
|
||||
}
|
||||
|
||||
if (password[0] == '\0')
|
||||
{
|
||||
pUser->password = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int i_password = m_pStrings->AddString(password);
|
||||
pUser = (AdminUser *)m_pMemory->GetAddress(id);
|
||||
pUser->password = i_password;
|
||||
@@ -1587,7 +1631,9 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
|
||||
|
||||
bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
|
||||
{
|
||||
if (c < 'a' || c > 'z')
|
||||
if (c < 'a'
|
||||
|| c > 'z'
|
||||
|| !g_FlagSet[(unsigned)c - (unsigned)'a'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1600,6 +1646,21 @@ bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdminCache::FindFlagChar(AdminFlag flag, char *c)
|
||||
{
|
||||
if (!g_FlagSet[flag])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
*c = g_ReverseFlags[flag];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
|
||||
{
|
||||
FlagBits bits = 0;
|
||||
@@ -1730,3 +1791,303 @@ bool AdminCache::CheckAccess(int client, const char *cmd, FlagBits flags, bool o
|
||||
|
||||
return g_ConCmds.CheckCommandAccess(client, cmd, bits) ? 1 : 0;
|
||||
}
|
||||
|
||||
void iterator_glob_basic_override(Trie *pTrie, const char *key, void **value, void *data)
|
||||
{
|
||||
FILE *fp;
|
||||
int flags;
|
||||
char flagstr[64];
|
||||
|
||||
fp = (FILE *)data;
|
||||
flags = (int)*value;
|
||||
g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
|
||||
|
||||
fprintf(fp, "\t\"%s\"\t\t\"%s\"\n", key, flagstr);
|
||||
}
|
||||
|
||||
void iterator_glob_grp_override(Trie *pTrie, const char *key, void **value, void *data)
|
||||
{
|
||||
FILE *fp;
|
||||
int flags;
|
||||
char flagstr[64];
|
||||
|
||||
fp = (FILE *)data;
|
||||
flags = (int)*value;
|
||||
g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
|
||||
|
||||
fprintf(fp, "\t\"@%s\"\t\t\"%s\"\n", key, flagstr);
|
||||
}
|
||||
|
||||
void iterator_group_basic_override(Trie *pTrie, const char *key, void **value, void *data)
|
||||
{
|
||||
FILE *fp;
|
||||
int flags;
|
||||
char flagstr[64];
|
||||
|
||||
fp = (FILE *)data;
|
||||
flags = (int)*value;
|
||||
g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
|
||||
|
||||
fprintf(fp, "\t\t\t\"%s\"\t\t\"%s\"\n", key, flagstr);
|
||||
}
|
||||
|
||||
void iterator_group_grp_override(Trie *pTrie, const char *key, void **value, void *data)
|
||||
{
|
||||
FILE *fp;
|
||||
int flags;
|
||||
char flagstr[64];
|
||||
|
||||
fp = (FILE *)data;
|
||||
flags = (int)*value;
|
||||
g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
|
||||
|
||||
fprintf(fp, "\t\t\t\"@%s\"\t\t\"%s\"\n", key, flagstr);
|
||||
}
|
||||
|
||||
void AdminCache::DumpCache(FILE *fp)
|
||||
{
|
||||
int *itable;
|
||||
AdminId aid;
|
||||
GroupId gid;
|
||||
char flagstr[64];
|
||||
unsigned int num;
|
||||
AdminUser *pAdmin;
|
||||
AdminGroup *pGroup;
|
||||
char name_buffer[512];
|
||||
|
||||
fprintf(fp, "\"Groups\"\n{\n");
|
||||
|
||||
num = 0;
|
||||
gid = m_FirstGroup;
|
||||
while (gid != INVALID_GROUP_ID
|
||||
&& (pGroup = GetGroup(gid)) != NULL)
|
||||
{
|
||||
num++;
|
||||
FillFlagString(pGroup->addflags, flagstr, sizeof(flagstr));
|
||||
|
||||
fprintf(fp, "\t/* num = %d, gid = 0x%X */\n", num, gid);
|
||||
fprintf(fp, "\t\"%s\"\n\t{\n", GetString(pGroup->nameidx));
|
||||
fprintf(fp, "\t\t\"flags\"\t\t\t\"%s\"\n", flagstr);
|
||||
fprintf(fp, "\t\t\"immunity\"\t\t\"%d\"\n", pGroup->immunity_level);
|
||||
|
||||
if (pGroup->immune_table != -1
|
||||
&& (itable = (int *)m_pMemory->GetAddress(pGroup->immune_table)) != NULL)
|
||||
{
|
||||
AdminGroup *pAltGroup;
|
||||
const char *gname, *mod;
|
||||
|
||||
for (int i = 1; i <= itable[0]; i++)
|
||||
{
|
||||
if ((pAltGroup = GetGroup(itable[i])) == NULL)
|
||||
{
|
||||
/* Assume the rest of the table is corrupt */
|
||||
break;
|
||||
}
|
||||
gname = GetString(pAltGroup->nameidx);
|
||||
if (atoi(gname) != 0)
|
||||
{
|
||||
mod = "@";
|
||||
}
|
||||
else
|
||||
{
|
||||
mod = "";
|
||||
}
|
||||
fprintf(fp, "\t\t\"immunity\"\t\t\"%s%s\"\n", mod, gname);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
|
||||
if (pGroup->pCmdGrpTable != NULL)
|
||||
{
|
||||
sm_trie_bad_iterator(pGroup->pCmdGrpTable,
|
||||
name_buffer,
|
||||
sizeof(name_buffer),
|
||||
iterator_group_grp_override,
|
||||
fp);
|
||||
}
|
||||
if (pGroup->pCmdTable != NULL)
|
||||
{
|
||||
sm_trie_bad_iterator(pGroup->pCmdTable,
|
||||
name_buffer,
|
||||
sizeof(name_buffer),
|
||||
iterator_group_basic_override,
|
||||
fp);
|
||||
}
|
||||
fprintf(fp, "\t\t}\n");
|
||||
|
||||
fprintf(fp, "\t}\n");
|
||||
|
||||
if ((gid = pGroup->next_grp) != INVALID_GROUP_ID)
|
||||
{
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "}\n\n");
|
||||
fprintf(fp, "\"Admins\"\n{\n");
|
||||
|
||||
num = 0;
|
||||
aid = m_FirstUser;
|
||||
while (aid != INVALID_ADMIN_ID
|
||||
&& (pAdmin = GetUser(aid)) != NULL)
|
||||
{
|
||||
num++;
|
||||
FillFlagString(pAdmin->flags, flagstr, sizeof(flagstr));
|
||||
|
||||
fprintf(fp, "\t/* num = %d, aid = 0x%X, serialno = 0x%X*/\n", num, aid, pAdmin->serialchange);
|
||||
|
||||
if (pAdmin->nameidx != -1)
|
||||
{
|
||||
fprintf(fp, "\t\"%s\"\n\t{\n", GetString(pAdmin->nameidx));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(fp, "\t\"\"\n\t{\n");
|
||||
}
|
||||
|
||||
if (pAdmin->auth.identidx != -1)
|
||||
{
|
||||
fprintf(fp, "\t\t\"auth\"\t\t\t\"%s\"\n", GetMethodName(pAdmin->auth.index));
|
||||
fprintf(fp, "\t\t\"identity\"\t\t\"%s\"\n", GetString(pAdmin->auth.identidx));
|
||||
}
|
||||
if (pAdmin->password != -1)
|
||||
{
|
||||
fprintf(fp, "\t\t\"password\"\t\t\"%s\"\n", GetString(pAdmin->password));
|
||||
}
|
||||
fprintf(fp, "\t\t\"flags\"\t\t\t\"%s\"\n", flagstr);
|
||||
fprintf(fp, "\t\t\"immunity\"\t\t\"%d\"\n", pAdmin->immunity_level);
|
||||
|
||||
if (pAdmin->grp_count != 0
|
||||
&& pAdmin->grp_table != -1
|
||||
&& (itable = (int *)m_pMemory->GetAddress(pAdmin->grp_table)) != NULL)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < pAdmin->grp_count; i++)
|
||||
{
|
||||
if ((pGroup = GetGroup(itable[i])) == NULL)
|
||||
{
|
||||
/* Assume the rest of the table is corrupt */
|
||||
break;
|
||||
}
|
||||
fprintf(fp, "\t\t\"group\"\t\t\t\"%s\"\n", GetString(pGroup->nameidx));
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "\t}\n");
|
||||
|
||||
if ((aid = pAdmin->next_user) != INVALID_ADMIN_ID)
|
||||
{
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "}\n\n");
|
||||
|
||||
fprintf(fp, "\"Overrides\"\n{\n");
|
||||
if (m_pCmdGrpOverrides != NULL)
|
||||
{
|
||||
sm_trie_bad_iterator(m_pCmdGrpOverrides,
|
||||
name_buffer,
|
||||
sizeof(name_buffer),
|
||||
iterator_glob_grp_override,
|
||||
fp);
|
||||
}
|
||||
if (m_pCmdOverrides != NULL)
|
||||
{
|
||||
sm_trie_bad_iterator(m_pCmdOverrides,
|
||||
name_buffer,
|
||||
sizeof(name_buffer),
|
||||
iterator_glob_basic_override,
|
||||
fp);
|
||||
}
|
||||
fprintf(fp, "}\n");
|
||||
}
|
||||
|
||||
AdminGroup *AdminCache::GetGroup(GroupId gid)
|
||||
{
|
||||
AdminGroup *pGroup;
|
||||
|
||||
pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
|
||||
if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pGroup;
|
||||
}
|
||||
|
||||
AdminUser *AdminCache::GetUser(AdminId aid)
|
||||
{
|
||||
AdminUser *pAdmin;
|
||||
|
||||
pAdmin = (AdminUser *)m_pMemory->GetAddress(aid);
|
||||
if (!pAdmin || pAdmin->magic != USR_MAGIC_SET)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pAdmin;
|
||||
}
|
||||
|
||||
const char *AdminCache::GetMethodName(unsigned int index)
|
||||
{
|
||||
List<AuthMethod>::iterator iter;
|
||||
for (iter=m_AuthMethods.begin();
|
||||
iter!=m_AuthMethods.end();
|
||||
iter++)
|
||||
{
|
||||
if (index-- == 0)
|
||||
{
|
||||
return (*iter).name.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *AdminCache::GetString(int idx)
|
||||
{
|
||||
return m_pStrings->GetString(idx);
|
||||
}
|
||||
|
||||
size_t AdminCache::FillFlagString(FlagBits bits, char *buffer, size_t maxlen)
|
||||
{
|
||||
size_t pos;
|
||||
unsigned int i, num_flags;
|
||||
AdminFlag flags[AdminFlags_TOTAL];
|
||||
|
||||
num_flags = FlagBitsToArray(bits, flags, AdminFlags_TOTAL);
|
||||
|
||||
pos = 0;
|
||||
for (i = 0; pos < maxlen && i < num_flags; i++)
|
||||
{
|
||||
if (FindFlagChar(flags[i], &buffer[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
buffer[pos] = '\0';
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
CON_COMMAND(sm_dump_admcache, "Dumps the admin cache for debugging")
|
||||
{
|
||||
FILE *fp;
|
||||
char buffer[PLATFORM_MAX_PATH];
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM, buffer, sizeof(buffer), "data/admin_cache_dump.txt");
|
||||
|
||||
if ((fp = fopen(buffer, "wt")) == NULL)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Could not open file for writing: %s", buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
g_Admins.DumpCache(fp);
|
||||
|
||||
g_RootMenu.ConsolePrint("Admin cache dumped to: %s", buffer);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
+8
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -153,6 +153,7 @@ public: //IAdminSystem
|
||||
bool FindFlag(const char *str, AdminFlag *pFlag);
|
||||
bool FindFlag(char c, AdminFlag *pAdmFlag);
|
||||
FlagBits ReadFlagString(const char *flags, const char **end);
|
||||
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
|
||||
unsigned int GetAdminSerialChange(AdminId id);
|
||||
bool CanAdminUseCommand(int client, const char *cmd);
|
||||
const char *GetGroupName(GroupId gid);
|
||||
@@ -164,8 +165,13 @@ public: //IAdminSystem
|
||||
const char *cmd,
|
||||
FlagBits flags,
|
||||
bool override_only);
|
||||
bool FindFlagChar(AdminFlag flag, char *c);
|
||||
public:
|
||||
bool IsValidAdmin(AdminId id);
|
||||
void DumpCache(FILE *fp);
|
||||
AdminGroup *GetGroup(GroupId gid);
|
||||
AdminUser *GetUser(AdminId id);
|
||||
const char *GetString(int idx);
|
||||
private:
|
||||
void _UnsetCommandOverride(const char *cmd);
|
||||
void _UnsetCommandGroupOverride(const char *group);
|
||||
@@ -174,6 +180,7 @@ private:
|
||||
void DumpCommandOverrideCache(OverrideType type);
|
||||
Trie *GetMethodByIndex(unsigned int index);
|
||||
bool GetMethodIndex(const char *name, unsigned int *_index);
|
||||
const char *GetMethodName(unsigned int index);
|
||||
void NameFlag(const char *str, AdminFlag flag);
|
||||
public:
|
||||
BaseStringTable *m_pStrings;
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -29,7 +29,7 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "CDataPack.h"
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+13
-3
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -29,7 +29,7 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern HandleType_t htCellArray;
|
||||
@@ -40,14 +40,17 @@ public:
|
||||
CellArray(size_t blocksize) : m_Data(NULL), m_BlockSize(blocksize), m_AllocSize(0), m_Size(0)
|
||||
{
|
||||
}
|
||||
|
||||
~CellArray()
|
||||
{
|
||||
free(m_Data);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
cell_t *push()
|
||||
{
|
||||
if (!GrowIfNeeded(1))
|
||||
@@ -58,18 +61,22 @@ public:
|
||||
m_Size++;
|
||||
return arr;
|
||||
}
|
||||
|
||||
cell_t *at(size_t b) const
|
||||
{
|
||||
return &m_Data[b * m_BlockSize];
|
||||
}
|
||||
|
||||
size_t blocksize() const
|
||||
{
|
||||
return m_BlockSize;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_Size = 0;
|
||||
}
|
||||
|
||||
bool swap(size_t item1, size_t item2)
|
||||
{
|
||||
/* Make sure there is extra space available */
|
||||
@@ -90,6 +97,7 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void remove(size_t index)
|
||||
{
|
||||
/* If we're at the end, take the easy way out */
|
||||
@@ -107,6 +115,7 @@ public:
|
||||
|
||||
m_Size--;
|
||||
}
|
||||
|
||||
cell_t *insert_at(size_t index)
|
||||
{
|
||||
/* Make sure it'll fit */
|
||||
@@ -124,6 +133,7 @@ public:
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
bool resize(size_t count)
|
||||
{
|
||||
if (count <= m_Size)
|
||||
@@ -132,7 +142,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!GrowIfNeeded(count - m_Size))
|
||||
if (!GrowIfNeeded(count - m_Size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+8
-13
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -57,7 +57,6 @@ extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegat
|
||||
|
||||
ChatTriggers g_ChatTriggers;
|
||||
bool g_bSupressSilentFails = false;
|
||||
CPhraseFile *g_pFloodPhrases = NULL;
|
||||
|
||||
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
|
||||
m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
|
||||
@@ -114,10 +113,7 @@ void ChatTriggers::OnSourceModAllInitialized()
|
||||
|
||||
void ChatTriggers::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
unsigned int file_id;
|
||||
|
||||
file_id = g_Translator.FindOrAddPhraseFile("antiflood.phrases.txt");
|
||||
g_pFloodPhrases = g_Translator.GetFileByIndex(file_id);
|
||||
g_pCorePhrases->AddPhraseFile("antiflood.phrases");
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModGameInitialized()
|
||||
@@ -216,15 +212,14 @@ void ChatTriggers::OnSayCommand_Pre()
|
||||
{
|
||||
char buffer[128];
|
||||
|
||||
/* :TODO: log an error? */
|
||||
if (g_Translator.CoreTransEx(g_pFloodPhrases,
|
||||
client,
|
||||
buffer,
|
||||
if (!CoreTranslate(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"Flooding the server",
|
||||
"%T",
|
||||
2,
|
||||
NULL,
|
||||
NULL)
|
||||
!= Trans_Okay)
|
||||
"Flooding the server",
|
||||
&client))
|
||||
{
|
||||
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+32
-8
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -296,7 +296,32 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
|
||||
ConCmdInfo *pInfo;
|
||||
if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
|
||||
{
|
||||
return;
|
||||
/* Unfortunately, we now have to do a slow lookup because Valve made client commands
|
||||
* case-insensitive. We can't even use our sortedness.
|
||||
*/
|
||||
if (client == 0 && !engine->IsDedicatedServer())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<ConCmdInfo *>::iterator iter;
|
||||
|
||||
pInfo = NULL;
|
||||
iter = m_CmdList.begin();
|
||||
while (iter != m_CmdList.end())
|
||||
{
|
||||
if (strcasecmp((*iter)->pCmd->GetName(), cmd) == 0)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
if (pInfo == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a hack to prevent say triggers from firing on messages that were
|
||||
@@ -379,14 +404,14 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
|
||||
/* On a listen server, sometimes the server host's client index can be set as 0.
|
||||
* So index 1 is passed to the command callback to correct this potential problem.
|
||||
*/
|
||||
if (client == 0 && !engine->IsDedicatedServer())
|
||||
if (!engine->IsDedicatedServer())
|
||||
{
|
||||
pHook->pf->PushCell(1);
|
||||
} else {
|
||||
pHook->pf->PushCell(client);
|
||||
client = g_Players.ListenClient();
|
||||
}
|
||||
|
||||
pHook->pf->PushCell(client);
|
||||
pHook->pf->PushCell(args);
|
||||
|
||||
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
|
||||
{
|
||||
if (tempres > result)
|
||||
@@ -494,8 +519,7 @@ bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmi
|
||||
|
||||
/* If we got here, the command failed... */
|
||||
char buffer[128];
|
||||
if (g_Translator.CoreTrans(client, buffer, sizeof(buffer), "No Access", NULL, NULL)
|
||||
!= Trans_Okay)
|
||||
if (!CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "No Access", &client))
|
||||
{
|
||||
UTIL_Format(buffer, sizeof(buffer), "You do not have access to this command");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+125
-5
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -40,23 +40,83 @@
|
||||
#include "Logger.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ForwardSys.h"
|
||||
#include "frame_hooks.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
|
||||
#endif
|
||||
|
||||
IForward *g_pOnServerCfg = NULL;
|
||||
IForward *g_pOnConfigsExecuted = NULL;
|
||||
IForward *g_pOnAutoConfigsBuffered = NULL;
|
||||
CoreConfig g_CoreConfig;
|
||||
bool g_bConfigsExecd = false;
|
||||
bool g_bServerExecd = false;
|
||||
bool g_bGotServerStart = false;
|
||||
bool g_bGotTrigger = false;
|
||||
ConCommand *g_pExecPtr = NULL;
|
||||
ConVar *g_ServerCfgFile = NULL;
|
||||
|
||||
void CheckAndFinalizeConfigs();
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
void Hook_ExecDispatchPre(const CCommand &cmd)
|
||||
#else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
void Hook_ExecDispatchPre()
|
||||
#endif
|
||||
{
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
CCommand cmd;
|
||||
#endif
|
||||
|
||||
const char *arg = cmd.Arg(1);
|
||||
|
||||
if (!g_bServerExecd
|
||||
&& arg != NULL
|
||||
&& strcmp(arg, g_ServerCfgFile->GetString()) == 0)
|
||||
{
|
||||
g_bGotTrigger = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void Hook_ExecDispatchPost(const CCommand &cmd)
|
||||
#else
|
||||
void Hook_ExecDispatchPost()
|
||||
#endif
|
||||
{
|
||||
if (g_bGotTrigger)
|
||||
{
|
||||
g_bGotTrigger = false;
|
||||
g_bServerExecd = true;
|
||||
CheckAndFinalizeConfigs();
|
||||
}
|
||||
}
|
||||
|
||||
void CheckAndFinalizeConfigs()
|
||||
{
|
||||
if ((g_bServerExecd || g_ServerCfgFile == NULL)
|
||||
&& g_bGotServerStart)
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
g_PendingInternalPush = true;
|
||||
#else
|
||||
SM_InternalCmdTrigger();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CoreConfig::OnSourceModAllInitialized()
|
||||
{
|
||||
g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
|
||||
g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
|
||||
g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
|
||||
g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
|
||||
}
|
||||
|
||||
void CoreConfig::OnSourceModShutdown()
|
||||
@@ -64,11 +124,61 @@ void CoreConfig::OnSourceModShutdown()
|
||||
g_RootMenu.RemoveRootConsoleCommand("config", this);
|
||||
g_Forwards.ReleaseForward(g_pOnServerCfg);
|
||||
g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
|
||||
g_Forwards.ReleaseForward(g_pOnAutoConfigsBuffered);
|
||||
|
||||
if (g_pExecPtr != NULL)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
|
||||
g_pExecPtr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoreConfig::OnSourceModLevelChange(const char *mapName)
|
||||
{
|
||||
static bool already_checked = false;
|
||||
|
||||
if (!already_checked)
|
||||
{
|
||||
if (engine->IsDedicatedServer())
|
||||
{
|
||||
g_ServerCfgFile = icvar->FindVar("servercfgfile");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ServerCfgFile = icvar->FindVar("lservercfgfile");
|
||||
}
|
||||
|
||||
if (g_ServerCfgFile != NULL)
|
||||
{
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
while (pBase != NULL)
|
||||
{
|
||||
if (pBase->IsCommand() && strcmp(pBase->GetName(), "exec") == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
g_pExecPtr = (ConCommand *)pBase;
|
||||
if (g_pExecPtr != NULL)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ServerCfgFile = NULL;
|
||||
}
|
||||
}
|
||||
already_checked = true;
|
||||
}
|
||||
|
||||
g_bConfigsExecd = false;
|
||||
g_bServerExecd = false;
|
||||
g_bGotServerStart = false;
|
||||
g_bGotTrigger = false;
|
||||
}
|
||||
|
||||
void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||
@@ -165,7 +275,7 @@ inline bool IsPathSepChar(char c)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return (c == '\\' || c == '/');
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_LINUX || defined PLATFORM_POSIX
|
||||
return (c == '/');
|
||||
#endif
|
||||
}
|
||||
@@ -382,7 +492,7 @@ void SM_ExecuteForPlugin(IPluginContext *ctx)
|
||||
|
||||
void SM_ExecuteAllConfigs()
|
||||
{
|
||||
if (g_bConfigsExecd)
|
||||
if (g_bGotServerStart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -403,7 +513,8 @@ void SM_ExecuteAllConfigs()
|
||||
}
|
||||
iter->Release();
|
||||
|
||||
engine->ServerCommand("sm internal 1\n");
|
||||
g_bGotServerStart = true;
|
||||
CheckAndFinalizeConfigs();
|
||||
}
|
||||
|
||||
void SM_ConfigsExecuted_Global()
|
||||
@@ -418,3 +529,12 @@ void SM_ConfigsExecuted_Global()
|
||||
g_pOnServerCfg->Execute(NULL);
|
||||
g_pOnConfigsExecuted->Execute(NULL);
|
||||
}
|
||||
|
||||
void SM_InternalCmdTrigger()
|
||||
{
|
||||
/* Order is important here. We need to buffer things before we send the command out. */
|
||||
g_pOnAutoConfigsBuffered->Execute(NULL);
|
||||
engine->ServerCommand("sm internal 1\n");
|
||||
g_PendingInternalPush = false;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -68,6 +68,7 @@ extern void SM_ExecuteAllConfigs();
|
||||
extern void SM_ExecuteForPlugin(IPluginContext *ctx);
|
||||
extern void SM_ConfigsExecuted_Global();
|
||||
extern void SM_ConfigsExecuted_Plugin(unsigned int serial);
|
||||
extern void SM_InternalCmdTrigger();
|
||||
|
||||
extern CoreConfig g_CoreConfig;
|
||||
|
||||
|
||||
+110
-56
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -29,12 +29,74 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "Tlhelp32.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "minidump.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
bool HookImportAddrTable(BYTE *base, const char *func, DWORD hookfunc, char *err, size_t maxlength)
|
||||
{
|
||||
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)base;
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "%s", "Could not detect valid DOS signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
|
||||
if (nt->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "%s", "Could not detect valid NT signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_IMPORT_DESCRIPTOR *desc =
|
||||
(IMAGE_IMPORT_DESCRIPTOR *)
|
||||
(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
if (base == (BYTE *)desc)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "%s", "Could not find IAT");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool entryFound = false;
|
||||
while (desc->Name)
|
||||
{
|
||||
if (desc->FirstThunk != 0)
|
||||
{
|
||||
IMAGE_THUNK_DATA *data = (IMAGE_THUNK_DATA *)(base + desc->OriginalFirstThunk);
|
||||
DWORD *iat = (DWORD *)(base + desc->FirstThunk);
|
||||
while (data->u1.Function)
|
||||
{
|
||||
if ((data->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != IMAGE_ORDINAL_FLAG32)
|
||||
{
|
||||
IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME *)(base + data->u1.AddressOfData);
|
||||
if (strcmp((char *)import->Name, func) == 0)
|
||||
{
|
||||
DWORD oldprot, oldprot2;
|
||||
VirtualProtect(iat, 4, PAGE_READWRITE, &oldprot);
|
||||
*iat = hookfunc;
|
||||
VirtualProtect(iat, 4, oldprot, &oldprot2);
|
||||
entryFound = true;
|
||||
}
|
||||
}
|
||||
data++;
|
||||
iat++;
|
||||
}
|
||||
}
|
||||
desc++;
|
||||
}
|
||||
|
||||
if (!entryFound)
|
||||
{
|
||||
UTIL_Format(err, maxlength, "Could not find IAT entry for %s", func);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
@@ -62,6 +124,24 @@ FARPROC WINAPI GetProcAddress2(HMODULE hModule, LPCSTR lpProcName)
|
||||
return GetProcAddress(hModule, lpProcName);
|
||||
}
|
||||
|
||||
HMODULE WINAPI LoadLibraryEx2(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags)
|
||||
{
|
||||
HMODULE lib = LoadLibraryEx(lpFileName, hFile, dwFlags);
|
||||
|
||||
/* Steam.dll seems to get loaded using an abs path, thus the use of stristr() */
|
||||
if (stristr(lpFileName, "steam.dll"))
|
||||
{
|
||||
char err[64];
|
||||
if (!HookImportAddrTable((BYTE *)lib, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
|
||||
{
|
||||
Error("[SM] %s in steam.dll\n", err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
class CrazyWindowsDebugger : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
@@ -69,6 +149,9 @@ public:
|
||||
{
|
||||
HANDLE hModuleList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
|
||||
MODULEENTRY32 me32;
|
||||
BYTE *engine = NULL;
|
||||
BYTE *steam = NULL;
|
||||
char err[64];
|
||||
|
||||
me32.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
@@ -77,69 +160,40 @@ public:
|
||||
Error("Could not initialize crazy debugger!");
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
do
|
||||
{
|
||||
if (strcasecmp(me32.szModule, "steam.dll") == 0)
|
||||
if (strcasecmp(me32.szModule, "engine.dll") == 0)
|
||||
{
|
||||
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)me32.modBaseAddr;
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
Error("[SM] Could not detect steam.dll with valid DOS signature");
|
||||
}
|
||||
char *base = (char *)dos;
|
||||
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
|
||||
if (nt->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
Error("[SM] Could not detect steam.dll with valid NT signature");
|
||||
}
|
||||
IMAGE_IMPORT_DESCRIPTOR *desc =
|
||||
(IMAGE_IMPORT_DESCRIPTOR *)
|
||||
(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
if (base == (char *)desc)
|
||||
{
|
||||
Error("[SM] Could not find the steam.dll IAT");
|
||||
}
|
||||
while (desc->Name)
|
||||
{
|
||||
if (desc->FirstThunk != 0)
|
||||
{
|
||||
IMAGE_THUNK_DATA *data = (IMAGE_THUNK_DATA *)(base + desc->OriginalFirstThunk);
|
||||
DWORD *iat = (DWORD *)(base + desc->FirstThunk);
|
||||
while (data->u1.Function)
|
||||
{
|
||||
if ((data->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != IMAGE_ORDINAL_FLAG32)
|
||||
{
|
||||
IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME *)(base + data->u1.AddressOfData);
|
||||
if (strcmp((char *)import->Name, "GetProcAddress") == 0)
|
||||
{
|
||||
DWORD oldprot, oldprot2;
|
||||
VirtualProtect(iat, 4, PAGE_READWRITE, &oldprot);
|
||||
*iat = (DWORD)GetProcAddress2;
|
||||
VirtualProtect(iat, 4, oldprot, &oldprot2);
|
||||
found = true;
|
||||
goto _end;
|
||||
}
|
||||
}
|
||||
data++;
|
||||
iat++;
|
||||
}
|
||||
}
|
||||
desc++;
|
||||
}
|
||||
break;
|
||||
engine = me32.modBaseAddr;
|
||||
}
|
||||
else if (strcasecmp(me32.szModule, "steam.dll") == 0)
|
||||
{
|
||||
steam = me32.modBaseAddr;
|
||||
}
|
||||
} while (Module32Next(hModuleList, &me32));
|
||||
|
||||
_end:
|
||||
CloseHandle(hModuleList);
|
||||
|
||||
if (!found)
|
||||
/* This really should not happen, but ... */
|
||||
if (!engine)
|
||||
{
|
||||
Error("Could not find steam.dll's GetProcAddress IAT entry");
|
||||
Error("[SM] Could not find engine.dll\n");
|
||||
}
|
||||
|
||||
CloseHandle(hModuleList);
|
||||
/* Steam.dll isn't loaded yet */
|
||||
if (!steam)
|
||||
{
|
||||
if (!HookImportAddrTable(engine, "LoadLibraryExA", (DWORD)LoadLibraryEx2, err, sizeof(err)))
|
||||
{
|
||||
Error("[SM] %s in engine.dll)\n", err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!HookImportAddrTable(steam, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
|
||||
{
|
||||
Error("[SM] %s in steam.dll)\n", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} s_CrazyDebugger;
|
||||
#endif
|
||||
|
||||
+7
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -717,3 +717,9 @@ const char *DBManager::GetDefaultDriverName()
|
||||
{
|
||||
return m_DefDriver.c_str();
|
||||
}
|
||||
|
||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||
{
|
||||
g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -92,6 +92,7 @@ public: //IDBManager
|
||||
Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken);
|
||||
HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
|
||||
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
|
||||
void AddDependency(IExtension *myself, IDBDriver *driver);
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
|
||||
+21
-11
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -36,16 +36,23 @@
|
||||
|
||||
DebugReport g_DbgReporter;
|
||||
|
||||
/* I'm really lazy. This should probably be exported to ISourcePawnEngine someday,
|
||||
* but we need to make sure the JIT will deal with the version bump.
|
||||
*/
|
||||
extern const char *GetSourcePawnErrorMessage(int error);
|
||||
|
||||
void DebugReport::OnSourceModAllInitialized()
|
||||
{
|
||||
g_pSourcePawn->SetDebugListener(this);
|
||||
}
|
||||
|
||||
void DebugReport::OnDebugSpew(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, msg);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
g_Logger.LogMessage("[SM] %s", buffer);
|
||||
}
|
||||
|
||||
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -56,7 +63,7 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c
|
||||
va_end(ap);
|
||||
|
||||
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
const char *error = GetSourcePawnErrorMessage(err);
|
||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -73,7 +80,7 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c
|
||||
{
|
||||
func_idx >>= 1;
|
||||
sp_public_t *function;
|
||||
if (ctx->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
|
||||
if (ctx->GetRuntime()->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
|
||||
}
|
||||
@@ -91,7 +98,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
va_end(ap);
|
||||
|
||||
const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
|
||||
const char *error = GetSourcePawnErrorMessage(err);
|
||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -103,7 +110,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
|
||||
IPluginDebugInfo *pDebug;
|
||||
if ((pDebug = pContext->GetDebugInfo()) == NULL)
|
||||
if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL)
|
||||
{
|
||||
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
||||
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
||||
@@ -181,6 +188,9 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
||||
}
|
||||
|
||||
iter->Release();
|
||||
return -1;
|
||||
|
||||
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
|
||||
|
||||
return g_PluginSys.GetPluginCount() + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -43,6 +43,8 @@ public: // SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
public: // IDebugListener
|
||||
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
||||
void OnDebugSpew(const char *msg, ...);
|
||||
public:
|
||||
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
||||
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
||||
private:
|
||||
|
||||
+13
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -359,6 +359,12 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
IChangeableForward *pForward;
|
||||
const char *name;
|
||||
cell_t res = Pl_Continue;
|
||||
|
||||
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
|
||||
if (!pEvent)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
/* Get the event name, we're going to need this for passing to post hooks */
|
||||
name = pEvent->GetName();
|
||||
@@ -407,6 +413,12 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
const char *name;
|
||||
Handle_t hndl = 0;
|
||||
|
||||
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
|
||||
if (!pEvent)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
name = m_EventNames.front();
|
||||
|
||||
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -266,43 +266,12 @@ void CExtension::MarkAllLoaded()
|
||||
}
|
||||
}
|
||||
|
||||
void CExtension::AddPlugin(IPlugin *pPlugin)
|
||||
void CExtension::AddPlugin(CPlugin *pPlugin)
|
||||
{
|
||||
/* Unfortunately we have to do this :( */
|
||||
if (m_Plugins.find(pPlugin) != m_Plugins.end())
|
||||
if (m_Dependents.find(pPlugin) != m_Dependents.end())
|
||||
{
|
||||
m_Plugins.push_back(pPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
void CExtension::RemovePlugin(IPlugin *pPlugin)
|
||||
{
|
||||
m_Plugins.remove(pPlugin);
|
||||
|
||||
List<WeakNative>::iterator iter = m_WeakNatives.begin();
|
||||
while (iter != m_WeakNatives.end())
|
||||
{
|
||||
if ((*iter).pl == pPlugin)
|
||||
{
|
||||
iter = m_WeakNatives.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
iter = m_ReplacedNatives.begin();
|
||||
while (iter != m_ReplacedNatives.end())
|
||||
{
|
||||
if ((*iter).pl == pPlugin)
|
||||
{
|
||||
iter = m_ReplacedNatives.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
m_Dependents.push_back(pPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +305,7 @@ bool CLocalExtension::IsLoaded()
|
||||
return (m_pLib != NULL);
|
||||
}
|
||||
|
||||
void CExtension::AddDependency(IfaceInfo *pInfo)
|
||||
void CExtension::AddDependency(const IfaceInfo *pInfo)
|
||||
{
|
||||
if (m_Deps.find(*pInfo) == m_Deps.end())
|
||||
{
|
||||
@@ -664,6 +633,20 @@ void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface)
|
||||
{
|
||||
CExtension *pExt = (CExtension *)ext;
|
||||
CExtension *pOwner = GetExtensionFromIdent(other);
|
||||
|
||||
IfaceInfo info;
|
||||
|
||||
info.iface = (SMInterface *)iface;
|
||||
info.owner = pOwner;
|
||||
|
||||
pExt->AddDependency(&info);
|
||||
pOwner->AddChildDependent(pExt, (SMInterface *)iface);
|
||||
}
|
||||
|
||||
void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
|
||||
{
|
||||
CExtension *pExt = (CExtension *)pOwner;
|
||||
@@ -671,7 +654,7 @@ void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface
|
||||
pExt->AddInterface(pInterface);
|
||||
}
|
||||
|
||||
void CExtensionManager::BindChildPlugin(IExtension *pParent, IPlugin *pPlugin)
|
||||
void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
|
||||
{
|
||||
CExtension *pExt = (CExtension *)pParent;
|
||||
|
||||
@@ -684,7 +667,7 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
|
||||
|
||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
||||
{
|
||||
(*iter)->RemovePlugin(plugin);
|
||||
(*iter)->DropRefsTo((CPlugin *)plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,77 +692,6 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
{
|
||||
IPluginContext *pContext = pPlugin->GetBaseContext();
|
||||
|
||||
List<CExtension *> exts;
|
||||
|
||||
uint32_t natives = pContext->GetNativesNum();
|
||||
sp_native_t *native;
|
||||
sm_extnative_t *x_native;
|
||||
sm_repnative_t *r_native;
|
||||
for (uint32_t i=0; i<natives; i++)
|
||||
{
|
||||
/* Make sure the native is valid */
|
||||
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure the native is not already bound */
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
/* If it is bound, see if there is a replacement. */
|
||||
if ((r_native = m_RepNatives.retrieve(native->name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Rewrite the address. Whee! */
|
||||
native->pfn = r_native->info.func;
|
||||
|
||||
/* Make sure this will unload safely */
|
||||
WeakNative wn((CPlugin *)pPlugin, i);
|
||||
r_native->owner->m_ReplacedNatives.push_back(wn);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* See if we've got this native in our cache */
|
||||
if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Try and bind it */
|
||||
if (pContext->BindNativeToIndex(i, x_native->info->func) != SP_ERROR_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* See if it's optional */
|
||||
if (native->flags & SP_NTVFLAG_OPTIONAL)
|
||||
{
|
||||
WeakNative wkn = WeakNative((CPlugin *)pPlugin, i);
|
||||
x_native->owner->m_WeakNatives.push_back(wkn);
|
||||
}
|
||||
else if (exts.find(x_native->owner) == exts.end())
|
||||
{
|
||||
exts.push_back(x_native->owner);
|
||||
}
|
||||
}
|
||||
|
||||
List<CExtension *>::iterator iter;
|
||||
for (iter = exts.begin(); iter != exts.end(); iter++)
|
||||
{
|
||||
CExtension *pExt = (*iter);
|
||||
if (pExt->m_Plugins.find(pPlugin) != pExt->m_Plugins.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pExt->m_Plugins.push_back(pPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
{
|
||||
if (!_pExt)
|
||||
@@ -804,12 +716,12 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
if (pExt->IsLoaded())
|
||||
{
|
||||
/* Unload any dependent plugins */
|
||||
List<IPlugin *>::iterator p_iter = pExt->m_Plugins.begin();
|
||||
while (p_iter != pExt->m_Plugins.end())
|
||||
List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin();
|
||||
while (p_iter != pExt->m_Dependents.end())
|
||||
{
|
||||
/* We have to manually unlink ourselves here, since we're no longer being managed */
|
||||
g_PluginSys.UnloadPlugin((*p_iter));
|
||||
p_iter = pExt->m_Plugins.erase(p_iter);
|
||||
p_iter = pExt->m_Dependents.erase(p_iter);
|
||||
}
|
||||
|
||||
List<String>::iterator s_iter;
|
||||
@@ -820,30 +732,6 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
||||
}
|
||||
|
||||
/* Unbind weak natives */
|
||||
List<WeakNative>::iterator wkn_iter;
|
||||
for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
|
||||
{
|
||||
WeakNative & wkn = (*wkn_iter);
|
||||
sp_context_t *ctx = wkn.pl->GetContext();
|
||||
ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
|
||||
}
|
||||
|
||||
/* Unbind replacement natives, link them back to their originals */
|
||||
for (wkn_iter = pExt->m_ReplacedNatives.begin();
|
||||
wkn_iter != pExt->m_ReplacedNatives.end();
|
||||
wkn_iter++)
|
||||
{
|
||||
WeakNative & wkn = (*wkn_iter);
|
||||
sp_context_t *ctx = wkn.pl->GetContext();
|
||||
sm_repnative_t *r_native = m_RepNatives.retrieve(ctx->natives[wkn.idx].name);
|
||||
if (r_native == NULL || ctx->natives[wkn.idx].pfn != r_native->info.func)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ctx->natives[wkn.idx].pfn = r_native->original;
|
||||
}
|
||||
|
||||
/* Notify and/or unload all dependencies */
|
||||
List<CExtension *>::iterator c_iter;
|
||||
CExtension *pDep;
|
||||
@@ -898,44 +786,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
}
|
||||
|
||||
/* Unbind our natives from Core */
|
||||
List<const sp_nativeinfo_t *>::iterator native_iter;
|
||||
for (native_iter = pExt->m_Natives.begin();
|
||||
native_iter != pExt->m_Natives.end();
|
||||
native_iter++)
|
||||
{
|
||||
const sp_nativeinfo_t *natives = (*native_iter);
|
||||
sm_extnative_t *x_native;
|
||||
for (unsigned int n = 0;
|
||||
natives[n].name != NULL && natives[n].func != NULL;
|
||||
n++)
|
||||
{
|
||||
x_native = m_ExtNatives.retrieve(natives[n].name);
|
||||
if (x_native && x_native->owner == pExt)
|
||||
{
|
||||
m_ExtNatives.remove(natives[n].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unbind our replacement natives */
|
||||
List<sm_repnative_t>::iterator rep_iter = m_RepNativeList.begin();
|
||||
while (rep_iter != m_RepNativeList.end())
|
||||
{
|
||||
sm_repnative_t & r_native = (*rep_iter);
|
||||
if (r_native.owner == pExt)
|
||||
{
|
||||
m_RepNatives.remove(r_native.info.name);
|
||||
rep_iter = m_RepNativeList.erase(rep_iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell it to unload */
|
||||
pAPI = pExt->GetAPI();
|
||||
pAPI->OnExtensionUnload();
|
||||
pExt->DropEverything();
|
||||
}
|
||||
|
||||
IdentityToken_t *pIdentity;
|
||||
@@ -949,6 +800,13 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell it to unload */
|
||||
if (pExt->IsLoaded())
|
||||
{
|
||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||
pAPI->OnExtensionUnload();
|
||||
}
|
||||
|
||||
pExt->Unload();
|
||||
delete pExt;
|
||||
|
||||
@@ -962,44 +820,6 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
CExtension *pExt = (CExtension *)pOwner;
|
||||
|
||||
pExt->m_Natives.push_back(natives);
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if (m_ExtNatives.retrieve(natives[i].name) != NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sm_extnative_t x_native;
|
||||
x_native.info = &natives[i];
|
||||
x_native.owner = pExt;
|
||||
m_ExtNatives.insert(natives[i].name, x_native);
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
SPVM_NATIVE_FUNC orig;
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((orig = g_PluginSys.FindCoreNative(natives[i].name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sm_repnative_t rep;
|
||||
rep.info = natives[i];
|
||||
rep.owner = (CExtension *)myself;
|
||||
rep.original = orig;
|
||||
m_RepNativeList.push_back(rep);
|
||||
m_RepNatives.insert(natives[i].name, rep);
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::MarkAllLoaded()
|
||||
{
|
||||
List<CExtension *>::iterator iter;
|
||||
@@ -1206,7 +1026,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
}
|
||||
|
||||
if (!pExt->IsLoaded()
|
||||
|| (!pExt->m_ChildDeps.size() && !pExt->m_Plugins.size()))
|
||||
|| (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
|
||||
{
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||
@@ -1216,7 +1036,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
}
|
||||
else
|
||||
{
|
||||
List<IPlugin *> plugins;
|
||||
List<CPlugin *> plugins;
|
||||
if (pExt->m_ChildDeps.size())
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
|
||||
@@ -1246,9 +1066,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
|
||||
/* Add to plugin unload list */
|
||||
List<IPlugin *>::iterator p_iter;
|
||||
for (p_iter=pOther->m_Plugins.begin();
|
||||
p_iter!=pOther->m_Plugins.end();
|
||||
List<CPlugin *>::iterator p_iter;
|
||||
for (p_iter=pOther->m_Dependents.begin();
|
||||
p_iter!=pOther->m_Dependents.end();
|
||||
p_iter++)
|
||||
{
|
||||
if (plugins.find((*p_iter)) == plugins.end())
|
||||
@@ -1260,12 +1080,12 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pExt->m_Plugins.size())
|
||||
if (pExt->m_Dependents.size())
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
|
||||
List<IPlugin *>::iterator iter;
|
||||
IPlugin *pPlugin;
|
||||
for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++)
|
||||
List<CPlugin *>::iterator iter;
|
||||
CPlugin *pPlugin;
|
||||
for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
|
||||
{
|
||||
pPlugin = (*iter);
|
||||
if (plugins.find(pPlugin) == plugins.end())
|
||||
@@ -1369,3 +1189,20 @@ IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
|
||||
return pExt;
|
||||
}
|
||||
|
||||
void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
{
|
||||
IExtensionInterface *pAPI;
|
||||
List<CExtension *>::iterator iter;
|
||||
|
||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
||||
{
|
||||
if ((pAPI = (*iter)->GetAPI()) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pAPI->GetExtensionVersion() > 3)
|
||||
{
|
||||
pAPI->OnCoreMapStart(pEdictList, edictCount, clientMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <IPluginSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include "PluginSys.h"
|
||||
#include "NativeOwner.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
@@ -55,15 +56,9 @@ struct sm_extnative_t
|
||||
const sp_nativeinfo_t *info;
|
||||
};
|
||||
|
||||
/* Replacement native */
|
||||
struct sm_repnative_t
|
||||
{
|
||||
CExtension *owner;
|
||||
sp_nativeinfo_t info;
|
||||
SPVM_NATIVE_FUNC original;
|
||||
};
|
||||
|
||||
class CExtension : public IExtension
|
||||
class CExtension :
|
||||
public IExtension,
|
||||
public CNativeOwner
|
||||
{
|
||||
friend class CExtensionManager;
|
||||
public:
|
||||
@@ -78,11 +73,10 @@ public: //IExtension
|
||||
bool IsRunning(char *error, size_t maxlength);
|
||||
public:
|
||||
void SetError(const char *error);
|
||||
void AddDependency(IfaceInfo *pInfo);
|
||||
void AddDependency(const IfaceInfo *pInfo);
|
||||
void AddChildDependent(CExtension *pOther, SMInterface *iface);
|
||||
void AddInterface(SMInterface *pInterface);
|
||||
void AddPlugin(IPlugin *pPlugin);
|
||||
void RemovePlugin(IPlugin *pPlugin);
|
||||
void AddPlugin(CPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddLibrary(const char *library);
|
||||
public:
|
||||
@@ -103,10 +97,6 @@ protected:
|
||||
List<IfaceInfo> m_Deps; /** Dependencies */
|
||||
List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
|
||||
List<SMInterface *> m_Interfaces;
|
||||
List<IPlugin *> m_Plugins;
|
||||
List<const sp_nativeinfo_t *> m_Natives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
List<WeakNative> m_ReplacedNatives;
|
||||
List<String> m_Libraries;
|
||||
unsigned int unload_code;
|
||||
bool m_bFullyLoaded;
|
||||
@@ -169,25 +159,26 @@ public:
|
||||
IExtension *LoadAutoExtension(const char *path);
|
||||
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
||||
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
|
||||
void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin);
|
||||
void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives);
|
||||
void BindAllNativesToPlugin(IPlugin *pPlugin);
|
||||
void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
|
||||
void TryAutoload();
|
||||
void AddLibrary(IExtension *pSource, const char *library);
|
||||
bool LibraryExists(const char *library);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
void Shutdown();
|
||||
CNativeOwner *GetNativeOwner(IExtension *pExt)
|
||||
{
|
||||
CExtension *p = (CExtension *)pExt;
|
||||
return p;
|
||||
}
|
||||
private:
|
||||
CExtension *FindByOrder(unsigned int num);
|
||||
private:
|
||||
List<CExtension *> m_Libs;
|
||||
List<sm_repnative_t> m_RepNativeList;
|
||||
KTrie<sm_repnative_t> m_RepNatives;
|
||||
KTrie<sm_extnative_t> m_ExtNatives;
|
||||
};
|
||||
|
||||
extern CExtensionManager g_Extensions;
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -186,6 +186,11 @@ void CForwardManager::ReleaseForward(IForward *forward)
|
||||
|
||||
void CForwardManager::ForwardFree(CForward *fwd)
|
||||
{
|
||||
if (fwd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_FreeForwards.push(fwd);
|
||||
m_managed.remove(fwd);
|
||||
}
|
||||
@@ -283,15 +288,11 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (filter)
|
||||
{
|
||||
filter->OnExecuteBegin();
|
||||
}
|
||||
|
||||
FuncIter iter = m_functions.begin();
|
||||
IPluginFunction *func;
|
||||
cell_t cur_result = 0;
|
||||
cell_t high_result = 0;
|
||||
cell_t low_result = 0;
|
||||
int err;
|
||||
unsigned int failed=0, success=0;
|
||||
unsigned int num_params = m_curparam;
|
||||
@@ -311,12 +312,16 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
{
|
||||
int err = SP_ERROR_PARAM;
|
||||
param = &temp_info[i];
|
||||
|
||||
if (i >= m_numparams || m_types[i] == Param_Any)
|
||||
{
|
||||
type = param->pushedas;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
type = m_types[i];
|
||||
}
|
||||
|
||||
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
@@ -325,26 +330,30 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
if (type == Param_String)
|
||||
{
|
||||
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
|
||||
} else if (type == Param_Float || type == Param_Cell) {
|
||||
}
|
||||
else if (type == Param_Float || type == Param_Cell)
|
||||
{
|
||||
err = func->PushCellByRef(¶m->val);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we're not byref or not vararg, our job is a bit easier. */
|
||||
assert(type == Param_Cell || type == Param_Float);
|
||||
err = func->PushCell(param->val);
|
||||
}
|
||||
|
||||
if (err != SP_ERROR_NONE)
|
||||
{
|
||||
if (!filter || !filter->OnErrorReport(this, func, err))
|
||||
{
|
||||
g_DbgReporter.GenerateError(func->GetParentContext(),
|
||||
func->GetFunctionID(),
|
||||
err,
|
||||
"Failed to push parameter while executing forward");
|
||||
}
|
||||
g_DbgReporter.GenerateError(func->GetParentContext(),
|
||||
func->GetFunctionID(),
|
||||
err,
|
||||
"Failed to push parameter while executing forward");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -352,12 +361,10 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
/* Call the function and deal with the return value. */
|
||||
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
||||
{
|
||||
if (filter)
|
||||
{
|
||||
filter->OnErrorReport(this, func, err);
|
||||
}
|
||||
failed++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
success++;
|
||||
switch (m_ExecType)
|
||||
{
|
||||
@@ -381,14 +388,12 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ET_Custom:
|
||||
case ET_LowEvent:
|
||||
{
|
||||
if (filter)
|
||||
/* Check if the current result is the lowest so far (or if it's the first result) */
|
||||
if (cur_result < low_result || success == 1)
|
||||
{
|
||||
if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
low_result = cur_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -401,25 +406,39 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
|
||||
switch (m_ExecType)
|
||||
{
|
||||
cur_result = high_result;
|
||||
} else if (m_ExecType == ET_Ignore) {
|
||||
cur_result = 0;
|
||||
case ET_Ignore:
|
||||
{
|
||||
cur_result = 0;
|
||||
break;
|
||||
}
|
||||
case ET_Event:
|
||||
case ET_Hook:
|
||||
{
|
||||
cur_result = high_result;
|
||||
break;
|
||||
}
|
||||
case ET_LowEvent:
|
||||
{
|
||||
cur_result = low_result;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
*result = cur_result;
|
||||
}
|
||||
}
|
||||
|
||||
if (filter)
|
||||
{
|
||||
filter->OnExecuteEnd(&cur_result, success, failed);
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -43,7 +43,7 @@ using namespace SourceHook;
|
||||
|
||||
typedef List<IPluginFunction *>::iterator FuncIter;
|
||||
|
||||
//:TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX
|
||||
/* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
|
||||
#define FORWARDS_NAME_MAX 64
|
||||
|
||||
struct ByrefInfo
|
||||
+83
-2
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "LibrarySys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "sm_crc32.h"
|
||||
#include "GameDataFetcher.h"
|
||||
|
||||
#if defined PLATFORM_LINUX
|
||||
#include <dlfcn.h>
|
||||
@@ -64,6 +65,7 @@ char g_GameName[256] = {'$', '\0'};
|
||||
#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
|
||||
#define PSTATE_GAMEDEFS_CRC 9
|
||||
#define PSTATE_GAMEDEFS_CRC_BINARY 10
|
||||
#define PSTATE_GAMEDEFS_CUSTOM 11
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
#define PLATFORM_NAME "windows"
|
||||
@@ -71,6 +73,9 @@ char g_GameName[256] = {'$', '\0'};
|
||||
#elif defined PLATFORM_LINUX
|
||||
#define PLATFORM_NAME "linux"
|
||||
#define PLATFORM_SERVER_BINARY "server_i486.so"
|
||||
#elif defined PLATFORM_APPLE
|
||||
#define PLATFORM_NAME "undef"
|
||||
#define PLATFORM_SERVER_BINARY "undef.dylib"
|
||||
#endif
|
||||
|
||||
struct TempSigInfo
|
||||
@@ -95,6 +100,9 @@ CGameConfig::CGameConfig(const char *file)
|
||||
m_pSigs = sm_trie_create();
|
||||
m_pStrings = new BaseStringTable(512);
|
||||
m_RefCount = 0;
|
||||
|
||||
m_CustomLevel = 0;
|
||||
m_CustomHandler = NULL;
|
||||
}
|
||||
|
||||
CGameConfig::~CGameConfig()
|
||||
@@ -171,6 +179,17 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
}
|
||||
else
|
||||
{
|
||||
ITextListener_SMC **pListen = g_GameConfigs.m_customHandlers.retrieve(name);
|
||||
|
||||
if (pListen != NULL)
|
||||
{
|
||||
m_CustomLevel = 0;
|
||||
m_ParseState = PSTATE_GAMEDEFS_CUSTOM;
|
||||
m_CustomHandler = *pListen;
|
||||
m_CustomHandler->ReadSMC_ParseStart();
|
||||
break;
|
||||
}
|
||||
|
||||
m_IgnoreLevel++;
|
||||
}
|
||||
break;
|
||||
@@ -220,6 +239,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
s_ServerBinCRC = UTIL_CRC32(buffer, size);
|
||||
free(buffer);
|
||||
s_ServerBinCRC_Ok = true;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
if (error[0] != '\0')
|
||||
@@ -232,6 +252,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PSTATE_GAMEDEFS_CUSTOM:
|
||||
{
|
||||
m_CustomLevel++;
|
||||
return m_CustomHandler->ReadSMC_NewSection(states, name);
|
||||
break;
|
||||
}
|
||||
/* No sub-sections allowed:
|
||||
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
||||
case PSTATE_GAMEDEFS_KEYS:
|
||||
@@ -299,6 +325,8 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
||||
bShouldBeReadingDefault = true;
|
||||
}
|
||||
}
|
||||
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
|
||||
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
@@ -312,6 +340,13 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
if (m_CustomLevel)
|
||||
{
|
||||
m_CustomLevel--;
|
||||
m_CustomHandler->ReadSMC_LeavingSection(states);
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
switch (m_ParseState)
|
||||
{
|
||||
case PSTATE_GAMES:
|
||||
@@ -324,6 +359,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
m_ParseState = PSTATE_GAMES;
|
||||
break;
|
||||
}
|
||||
case PSTATE_GAMEDEFS_CUSTOM:
|
||||
{
|
||||
m_ParseState = PSTATE_GAMEDEFS;
|
||||
m_CustomHandler->ReadSMC_ParseEnd(false, false);
|
||||
break;
|
||||
}
|
||||
case PSTATE_GAMEDEFS_KEYS:
|
||||
case PSTATE_GAMEDEFS_OFFSETS:
|
||||
{
|
||||
@@ -522,6 +563,15 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
|
||||
state.line,
|
||||
state.col,
|
||||
msg ? msg : "Unknown error");
|
||||
|
||||
if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
|
||||
{
|
||||
//error occurred while parsing a custom section
|
||||
m_CustomHandler->ReadSMC_ParseEnd(true, true);
|
||||
m_CustomHandler = NULL;
|
||||
m_CustomLevel = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -598,7 +648,7 @@ void GameConfigManager::OnSourceModStartup(bool late)
|
||||
strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1);
|
||||
|
||||
KeyValues *pGameInfo = new KeyValues("GameInfo");
|
||||
if (pGameInfo->LoadFromFile(basefilesystem, "gameinfo.txt"))
|
||||
if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
|
||||
{
|
||||
const char *str;
|
||||
if ((str = pGameInfo->GetString("game", NULL)) != NULL)
|
||||
@@ -630,6 +680,13 @@ void GameConfigManager::OnSourceModAllShutdown()
|
||||
|
||||
bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
|
||||
{
|
||||
/* A crash was detected during last load - We block the gamedata loading so it hopefully won't happen again */
|
||||
if (g_blockGameDataLoad)
|
||||
{
|
||||
UTIL_Format(error, maxlength, "GameData loaded blocked due to detected crash");
|
||||
return false;
|
||||
}
|
||||
|
||||
CGameConfig *pConfig;
|
||||
|
||||
if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
|
||||
@@ -684,3 +741,27 @@ IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
void GameConfigManager::AddUserConfigHook( const char *sectionname, ITextListener_SMC *listener )
|
||||
{
|
||||
m_customHandlers.insert(sectionname, listener);
|
||||
}
|
||||
|
||||
void GameConfigManager::RemoveUserConfigHook( const char *sectionname, ITextListener_SMC *listener )
|
||||
{
|
||||
ITextListener_SMC **pListener = m_customHandlers.retrieve(sectionname);
|
||||
|
||||
if (pListener == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (*pListener != listener)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_customHandlers.remove(sectionname);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+10
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "sm_trie.h"
|
||||
#include "sm_globals.h"
|
||||
#include "sm_memtable.h"
|
||||
#include "sm_trie_tpl.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
@@ -82,6 +83,10 @@ private:
|
||||
char m_offset[64];
|
||||
char m_Game[256];
|
||||
bool bShouldBeReadingDefault;
|
||||
|
||||
/* Custom Sections */
|
||||
unsigned int m_CustomLevel;
|
||||
ITextListener_SMC *m_CustomHandler;
|
||||
};
|
||||
|
||||
class GameConfigManager :
|
||||
@@ -97,6 +102,8 @@ public: //IGameConfigManager
|
||||
IGameConfig *ReadHandle(Handle_t hndl,
|
||||
IdentityToken_t *ident,
|
||||
HandleError *err);
|
||||
void AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener);
|
||||
void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener);
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
@@ -104,6 +111,8 @@ public: //SMGlobalClass
|
||||
private:
|
||||
List<CGameConfig *> m_cfgs;
|
||||
Trie *m_pLookup;
|
||||
public:
|
||||
KTrie<ITextListener_SMC *> m_customHandlers;
|
||||
};
|
||||
|
||||
extern GameConfigManager g_GameConfigs;
|
||||
|
||||
@@ -0,0 +1,909 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "GameDataFetcher.h"
|
||||
#include "bitbuf.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define INVALID_SOCKET -1
|
||||
#define closesocket close
|
||||
#define WSAGetLastError() errno
|
||||
#endif
|
||||
|
||||
#include "sh_vector.h"
|
||||
#include "sh_string.h"
|
||||
#include "sm_version.h"
|
||||
|
||||
#ifdef ORANGEBOX_BUILD
|
||||
#include "convar_sm_ob.h"
|
||||
#else
|
||||
#include "convar_sm.h"
|
||||
#endif
|
||||
|
||||
#include "sourcemm_api.h"
|
||||
#include "time.h"
|
||||
#include "TimerSys.h"
|
||||
#include "compat_wrappers.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "md5.h"
|
||||
#include "frame_hooks.h"
|
||||
|
||||
#define QUERY_MAX_LENGTH 1024
|
||||
|
||||
static BuildMD5ableBuffer g_MD5Builder;
|
||||
static FetcherThread g_FetchThread;
|
||||
|
||||
static FILE *logfile = NULL;
|
||||
|
||||
bool g_disableGameDataUpdate = false;
|
||||
|
||||
/**
|
||||
* Note on this. If we issue a reload and changelevel, my srcds.exe will emit
|
||||
* Assertion Failed: !m_bServiceStarted
|
||||
* on quit. This seems like a non-issue, because before we just terminated the
|
||||
* server anyway. If anyone notices and files a bug, we can look into it further.
|
||||
*/
|
||||
bool g_restartAfterUpdate = false;
|
||||
|
||||
static bool was_level_started = false;
|
||||
static int g_serverPort = 6500;
|
||||
static char g_serverAddress[100] = "smupdate.alliedmods.net";
|
||||
|
||||
static void _ForceRestart(void *data)
|
||||
{
|
||||
char cmd[300];
|
||||
g_Logger.LogMessage("Automatically restarting SourceMod after a successful gamedata update.");
|
||||
UTIL_Format(cmd, sizeof(cmd), "meta unload %d\n", g_PLID);
|
||||
engine->ServerCommand(cmd);
|
||||
UTIL_Format(cmd, sizeof(cmd), "changelevel \"%s\"\n", STRING(gpGlobals->mapname));
|
||||
engine->ServerCommand(cmd);
|
||||
UTIL_Format(cmd, sizeof(cmd), "echo SourceMod restarted after gamedata update.\n");
|
||||
engine->ServerCommand(cmd);
|
||||
}
|
||||
|
||||
static void ForceRestart()
|
||||
{
|
||||
FrameAction action;
|
||||
|
||||
action.action = _ForceRestart;
|
||||
action.data = NULL;
|
||||
AddFrameAction(action);
|
||||
}
|
||||
|
||||
void FetcherThread::RunThread(IThreadHandle *pHandle)
|
||||
{
|
||||
char lock_path[PLATFORM_MAX_PATH];
|
||||
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp");
|
||||
g_LibSys.CreateFolder(lock_path);
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
|
||||
|
||||
char log_path[PLATFORM_MAX_PATH];
|
||||
g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata");
|
||||
|
||||
g_LibSys.CreateFolder(log_path);
|
||||
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
log_path,
|
||||
sizeof(log_path),
|
||||
"logs/gamedata/L%04d%02d%02d.log",
|
||||
curtime->tm_year + 1900,
|
||||
curtime->tm_mon + 1,
|
||||
curtime->tm_mday);
|
||||
|
||||
logfile = fopen(log_path, "at");
|
||||
|
||||
if (!logfile)
|
||||
{
|
||||
/* :( */
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a blank lock file
|
||||
FILE *fp = fopen(lock_path, "w");
|
||||
if (fp)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
char query[QUERY_MAX_LENGTH];
|
||||
|
||||
/* Check for updated gamedata files */
|
||||
int len = BuildGameDataQuery(query, QUERY_MAX_LENGTH);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
g_Logger.LogToFileOnly(logfile, "Could not build gamedata query!");
|
||||
fclose(logfile);
|
||||
unlink(lock_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We check this late so we have the MD5 sums available. This may change in the future. */
|
||||
if (g_disableGameDataUpdate)
|
||||
{
|
||||
g_Logger.LogToFileOnly(logfile, "Skipping gamedata fetcher (DisableAutoUpdate set)");
|
||||
fclose(logfile);
|
||||
unlink(lock_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new socket for this connection */
|
||||
int socketDescriptor = ConnectSocket();
|
||||
|
||||
if (socketDescriptor == INVALID_SOCKET)
|
||||
{
|
||||
fclose(logfile);
|
||||
unlink(lock_path);
|
||||
return;
|
||||
}
|
||||
|
||||
int sent = SendData(socketDescriptor, query, len);
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Sent gamedata query");
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
if (sent == 0)
|
||||
{
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Failed to send gamedata query data to remote host");
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
closesocket(socketDescriptor);
|
||||
fclose(logfile);
|
||||
unlink(lock_path);
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessGameDataQuery(socketDescriptor);
|
||||
|
||||
/* And we're done! */
|
||||
closesocket(socketDescriptor);
|
||||
fclose(logfile);
|
||||
unlink(lock_path);
|
||||
}
|
||||
|
||||
void FetcherThread::OnTerminate(IThreadHandle *pHandle, bool cancel)
|
||||
{
|
||||
g_blockGameDataLoad = false;
|
||||
|
||||
if (cancel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (wasSuccess)
|
||||
{
|
||||
HandleUpdateStatus(updateStatus, build);
|
||||
|
||||
if (needsRestart)
|
||||
{
|
||||
if (g_restartAfterUpdate)
|
||||
{
|
||||
if (was_level_started)
|
||||
{
|
||||
ForceRestart();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Logger.LogMessage("Your gamedata files have been updated, please restart your server.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!g_disableGameDataUpdate)
|
||||
{
|
||||
g_Logger.LogError("An error occurred in the gamedata fetcher, see your gamedata log files for more information.");
|
||||
}
|
||||
}
|
||||
|
||||
int FetcherThread::BuildGameDataQuery(char *buffer, int maxlen)
|
||||
{
|
||||
char gamedata_path[PLATFORM_MAX_PATH];
|
||||
g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata");
|
||||
|
||||
IDirectory *dir = g_LibSys.OpenDirectory(gamedata_path);
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bf_write Writer = bf_write("GameDataQuery", buffer, maxlen);
|
||||
|
||||
Writer.WriteByte('A'); //Generic Header char
|
||||
Writer.WriteByte('G'); //G for gamedata query, or green, like my hat.
|
||||
|
||||
short build[4] = { SVN_FILE_VERSION };
|
||||
|
||||
Writer.WriteBytes(&build[0], 8);
|
||||
|
||||
Writer.WriteByte(0); // Initialize the file counter - Index 10
|
||||
|
||||
while (dir->MoreFiles())
|
||||
{
|
||||
if (dir->IsEntryFile())
|
||||
{
|
||||
const char *name = dir->GetEntryName();
|
||||
size_t len = strlen(name);
|
||||
if (len >= 4 && strcmp(&name[len-4], ".txt") == 0)
|
||||
{
|
||||
MD5 md5;
|
||||
SMCError err;
|
||||
SMCStates states;
|
||||
unsigned char raw[16];
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
|
||||
g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name);
|
||||
|
||||
g_MD5Builder.checksum = &md5;
|
||||
if ((err = g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states)) == SMCError_Okay)
|
||||
{
|
||||
md5.raw_digest(raw);
|
||||
(uint8_t)buffer[10]++; //Increment the file counter
|
||||
Writer.WriteBytes(raw, 16);
|
||||
|
||||
FileData *data = new FileData();
|
||||
data->filename = new SourceHook::String(file);
|
||||
md5.hex_digest(data->checksum);
|
||||
filenames.push_back(data);
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Parsed file: %s as %s", file, data->checksum);
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
IF_DEBUG_SPEW
|
||||
const char *error = g_TextParser.GetSMCErrorString(err);
|
||||
g_Logger.LogToFileOnly(logfile, "Parsing of file %s failed: %s", file, error);
|
||||
ENDIF_DEBUG_SPEW
|
||||
}
|
||||
}
|
||||
}
|
||||
dir->NextEntry();
|
||||
}
|
||||
|
||||
return Writer.GetNumBytesWritten();
|
||||
}
|
||||
|
||||
int FetcherThread::ConnectSocket()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
WSADATA wsaData;
|
||||
WSAStartup(0x0101, &wsaData);
|
||||
#endif
|
||||
|
||||
struct protoent *ptrp;
|
||||
|
||||
if ((ptrp = getprotobyname("tcp")) == NULL)
|
||||
{
|
||||
g_Logger.LogToFileOnly(logfile, "Error: Failed to find TCP protocol");
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
int socketDescriptor = socket(AF_INET, SOCK_STREAM, ptrp->p_proto);
|
||||
|
||||
if (socketDescriptor == INVALID_SOCKET)
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
|
||||
g_Logger.LogToFileOnly(logfile, "Error: Failed to create socket: %s", error);
|
||||
closesocket(socketDescriptor);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
struct hostent *he;
|
||||
struct sockaddr_in local_addr;
|
||||
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_port = htons((u_short)g_serverPort);
|
||||
|
||||
he = gethostbyname(g_serverAddress);
|
||||
|
||||
if (!he)
|
||||
{
|
||||
if ((local_addr.sin_addr.s_addr = inet_addr(g_serverAddress)) == INADDR_NONE)
|
||||
{
|
||||
g_Logger.LogToFileOnly(logfile, "Couldn't locate address: %s", g_serverAddress);
|
||||
closesocket(socketDescriptor);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&local_addr.sin_addr, (struct in_addr *)he->h_addr, he->h_length);
|
||||
}
|
||||
|
||||
if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
|
||||
g_Logger.LogToFileOnly(logfile, "Couldn't connect to %s: %s", g_serverAddress, error);
|
||||
closesocket(socketDescriptor);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return socketDescriptor;
|
||||
}
|
||||
|
||||
void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Waiting for reply!");
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
//Read in the header bytes
|
||||
int returnLen = RecvData(socketDescriptor, buffer, 12);
|
||||
|
||||
|
||||
if (returnLen == 0)
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
|
||||
g_Logger.LogToFileOnly(logfile, "Did not receive reply: %s", error);
|
||||
return;
|
||||
}
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Received Header!");
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
bf_read Reader = bf_read("GameDataQuery", buffer, 12);
|
||||
|
||||
if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G')
|
||||
{
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Unknown Query Response");
|
||||
ENDIF_DEBUG_SPEW
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus = (UpdateStatus)Reader.ReadByte();
|
||||
|
||||
build[0] = Reader.ReadShort();
|
||||
build[1] = Reader.ReadShort();
|
||||
build[2] = Reader.ReadShort();
|
||||
build[3] = Reader.ReadShort();
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile,
|
||||
"Update Status: %i - Latest %i.%i.%i.%i",
|
||||
updateStatus,
|
||||
build[0],
|
||||
build[1],
|
||||
build[2],
|
||||
build[3]);
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
int changedFiles = Reader.ReadByte();
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Files to download: %i", changedFiles);
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
for (int i=0; i<changedFiles; i++)
|
||||
{
|
||||
//Read in the file index and byte count
|
||||
returnLen = RecvData(socketDescriptor, buffer, 5);
|
||||
|
||||
if (returnLen == 0)
|
||||
{
|
||||
/* Timeout or fail? */
|
||||
return;
|
||||
}
|
||||
|
||||
Reader.StartReading(buffer, 5);
|
||||
|
||||
int index = Reader.ReadByte();
|
||||
int tempLen = Reader.ReadUBitLong(32);
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "File index %i and length %i", index, tempLen);
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
void *memPtr;
|
||||
memtable->CreateMem(tempLen+1, &memPtr);
|
||||
|
||||
//Read the contents of our file into the memtable
|
||||
returnLen = RecvData(socketDescriptor, (char *)memPtr, tempLen);
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Received %i bytes", returnLen);
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
if (returnLen == 0)
|
||||
{
|
||||
/* Timeout or fail? */
|
||||
return;
|
||||
}
|
||||
|
||||
((unsigned char *)memPtr)[tempLen] = '\0';
|
||||
|
||||
FileData *data = filenames.at(index);
|
||||
const char *filename;
|
||||
if (data != NULL)
|
||||
{
|
||||
filename = data->filename->c_str();
|
||||
|
||||
FILE *fp = fopen(filename, "w");
|
||||
|
||||
if (fp)
|
||||
{
|
||||
fprintf(fp, "%s", (const char *)memPtr);
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Logger.LogToFileOnly(logfile, "Failed to open file \"%s\" for writing", filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = "";
|
||||
}
|
||||
|
||||
memtable->Reset();
|
||||
|
||||
g_Logger.LogToFileOnly(logfile, "Updated file: %s", filename);
|
||||
}
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "File Downloads Completed!");
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
needsRestart = false;
|
||||
|
||||
if (changedFiles > 0)
|
||||
{
|
||||
needsRestart = true;
|
||||
}
|
||||
|
||||
//Read changed file count
|
||||
returnLen = RecvData(socketDescriptor, buffer, 1);
|
||||
|
||||
if (returnLen == 0)
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
|
||||
g_Logger.LogToFileOnly(logfile, "Did not receive count reply: %s", error);
|
||||
return;
|
||||
}
|
||||
|
||||
Reader.StartReading(buffer, 1);
|
||||
|
||||
changedFiles = Reader.ReadByte();
|
||||
|
||||
if (changedFiles < 1)
|
||||
{
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "No unknown files. We're all done");
|
||||
ENDIF_DEBUG_SPEW
|
||||
return;
|
||||
}
|
||||
|
||||
char *changedFileIndexes = new char[changedFiles];
|
||||
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "%i files were unknown", changedFiles);
|
||||
ENDIF_DEBUG_SPEW
|
||||
|
||||
returnLen = RecvData(socketDescriptor, changedFileIndexes, changedFiles);
|
||||
|
||||
if (returnLen == 0)
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
|
||||
g_Logger.LogToFileOnly(logfile, "Did not receive list reply: %s", error);
|
||||
return;
|
||||
}
|
||||
|
||||
Reader.StartReading(changedFileIndexes, changedFiles);
|
||||
|
||||
for (int i=0; i<changedFiles; i++)
|
||||
{
|
||||
int index = Reader.ReadByte();
|
||||
char fileName[30];
|
||||
|
||||
FileData *data = filenames.at(index);
|
||||
const char* pathname;
|
||||
if (data != NULL)
|
||||
{
|
||||
pathname = data->filename->c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
pathname = "";
|
||||
}
|
||||
|
||||
g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname);
|
||||
IF_DEBUG_SPEW
|
||||
g_Logger.LogToFileOnly(logfile, "Unknown File %i : %s", index, fileName);
|
||||
ENDIF_DEBUG_SPEW
|
||||
}
|
||||
|
||||
delete [] changedFileIndexes;
|
||||
|
||||
wasSuccess = true;
|
||||
}
|
||||
|
||||
int FetcherThread::RecvData(int socketDescriptor, char *buffer, int len)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
/* Create a 10 Second Timeout */
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
int bytesReceivedTotal = 0;
|
||||
|
||||
while (bytesReceivedTotal < len)
|
||||
{
|
||||
/* Add our socket to a socket set */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(socketDescriptor, &fds);
|
||||
|
||||
/* Wait max of 10 seconds for recv to become available */
|
||||
select(socketDescriptor+1, &fds, NULL, NULL, &tv);
|
||||
|
||||
int bytesReceived = 0;
|
||||
|
||||
/* Is there a limit on how much we can receive? Some site said 1024 bytes, which will be well short of a file */
|
||||
if (FD_ISSET(socketDescriptor, &fds))
|
||||
{
|
||||
bytesReceived = recv(socketDescriptor, buffer+bytesReceivedTotal, len-bytesReceivedTotal, 0);
|
||||
}
|
||||
|
||||
if (bytesReceived == 0 || bytesReceived == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesReceivedTotal += bytesReceived;
|
||||
}
|
||||
|
||||
return bytesReceivedTotal;
|
||||
}
|
||||
|
||||
int FetcherThread::SendData(int socketDescriptor, char *buffer, int len)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
int sentBytesTotal = 0;
|
||||
|
||||
while (sentBytesTotal < len)
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(socketDescriptor, &fds);
|
||||
|
||||
select(socketDescriptor+1, NULL, &fds, NULL, &tv);
|
||||
|
||||
int sentBytes = 0;
|
||||
|
||||
if (FD_ISSET(socketDescriptor, &fds))
|
||||
{
|
||||
sentBytes = send(socketDescriptor, buffer+sentBytesTotal, len-sentBytesTotal, 0);
|
||||
}
|
||||
|
||||
if (sentBytes == 0 || sentBytes == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sentBytesTotal += sentBytes;
|
||||
}
|
||||
|
||||
return sentBytesTotal;
|
||||
}
|
||||
|
||||
void FetcherThread::HandleUpdateStatus(UpdateStatus status, short version[4])
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Update_Unknown:
|
||||
case Update_Current:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case Update_NewBuild:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case Update_MinorAvailable:
|
||||
{
|
||||
g_Logger.LogMessage("SourceMod Update: A new release of SourceMod is now available from sourcemod.net");
|
||||
g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
case Update_MajorAvailable:
|
||||
{
|
||||
g_Logger.LogMessage("SourceMod Update: An major release of SourceMod is now available from sourcemod.net");
|
||||
g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
case Update_CriticalAvailable:
|
||||
{
|
||||
g_Logger.LogError("SourceMod Update: A critical SourceMod release is available from sourcemod.net. It is strongly recommended that you update!");
|
||||
g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool g_blockGameDataLoad = false;
|
||||
static IThreadHandle *fetch_thread_hndl;
|
||||
|
||||
class InitFetch : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
void OnSourceModAllInitialized_Post()
|
||||
{
|
||||
char lock_path[PLATFORM_MAX_PATH];
|
||||
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
|
||||
|
||||
if (g_LibSys.IsPathFile(lock_path) && g_LibSys.PathExists(lock_path))
|
||||
{
|
||||
g_Logger.LogError("sourcemod/data/temp/gamedata.lock file detected. This is most likely due to a crash during GameData updating - Blocking GameData loading");
|
||||
g_Logger.LogError("If this error persists delete the file manually");
|
||||
g_blockGameDataLoad = true;
|
||||
}
|
||||
|
||||
ThreadParams fetchThreadParams = ThreadParams();
|
||||
fetchThreadParams.prio = ThreadPrio_Low;
|
||||
fetch_thread_hndl = g_pThreader->MakeThread(&g_FetchThread, &fetchThreadParams);
|
||||
}
|
||||
|
||||
void OnSourceModShutdown()
|
||||
{
|
||||
fetch_thread_hndl->WaitForThread();
|
||||
fetch_thread_hndl->DestroyThis();
|
||||
}
|
||||
|
||||
void OnSourceModLevelActivated()
|
||||
{
|
||||
was_level_started = true;
|
||||
|
||||
if (g_restartAfterUpdate &&
|
||||
g_FetchThread.wasSuccess &&
|
||||
g_FetchThread.needsRestart)
|
||||
{
|
||||
ForceRestart();
|
||||
}
|
||||
}
|
||||
|
||||
void OnSourceModLevelEnd()
|
||||
{
|
||||
was_level_started = false;
|
||||
}
|
||||
|
||||
ConfigResult OnSourceModConfigChanged(const char *key,
|
||||
const char *value,
|
||||
ConfigSource source,
|
||||
char *error,
|
||||
size_t maxlength)
|
||||
{
|
||||
if (strcasecmp(key, "DisableAutoUpdate") == 0)
|
||||
{
|
||||
if (strcasecmp(value, "yes") == 0)
|
||||
{
|
||||
g_disableGameDataUpdate = true;
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
else if (strcasecmp(value, "no") == 0)
|
||||
{
|
||||
g_disableGameDataUpdate = false;
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
return ConfigResult_Reject;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "ForceRestartAfterUpdate") == 0)
|
||||
{
|
||||
if (strcasecmp(value, "yes") == 0)
|
||||
{
|
||||
g_restartAfterUpdate = true;
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
else if (strcasecmp(value, "no") == 0)
|
||||
{
|
||||
g_restartAfterUpdate = false;
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
return ConfigResult_Reject;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "AutoUpdateServer") == 0)
|
||||
{
|
||||
UTIL_Format(g_serverAddress, sizeof(g_serverAddress), "%s", value);
|
||||
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "AutoUpdatePort") == 0)
|
||||
{
|
||||
int port = atoi(value);
|
||||
|
||||
if (!port)
|
||||
{
|
||||
return ConfigResult_Reject;
|
||||
}
|
||||
|
||||
g_serverPort = port;
|
||||
|
||||
return ConfigResult_Accept;
|
||||
}
|
||||
|
||||
return ConfigResult_Ignore;
|
||||
}
|
||||
} g_InitFetch;
|
||||
|
||||
BuildMD5ableBuffer::BuildMD5ableBuffer()
|
||||
{
|
||||
stringTable = new BaseStringTable(2048);
|
||||
}
|
||||
|
||||
BuildMD5ableBuffer::~BuildMD5ableBuffer()
|
||||
{
|
||||
delete stringTable;
|
||||
}
|
||||
|
||||
void BuildMD5ableBuffer::ReadSMC_ParseStart()
|
||||
{
|
||||
stringTable->Reset();
|
||||
}
|
||||
|
||||
SMCResult BuildMD5ableBuffer::ReadSMC_KeyValue(const SMCStates *states,
|
||||
const char *key,
|
||||
const char *value)
|
||||
{
|
||||
stringTable->AddString(key);
|
||||
stringTable->AddString(value);
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
SMCResult BuildMD5ableBuffer::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
{
|
||||
stringTable->AddString(name);
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
void BuildMD5ableBuffer::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||
{
|
||||
if (halted || failed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *data = stringTable->GetMemTable()->GetAddress(0);
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
checksum->update((unsigned char *)data, stringTable->GetMemTable()->GetActualMemUsed());
|
||||
}
|
||||
|
||||
checksum->finalize();
|
||||
}
|
||||
|
||||
CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
|
||||
{
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
CCommand args;
|
||||
#endif
|
||||
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *file = args.Arg(1);
|
||||
if (!file || file[0] == '\0')
|
||||
{
|
||||
g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SourceHook::CVector<FileData *>::iterator iter = g_FetchThread.filenames.begin();
|
||||
|
||||
FileData *curData;
|
||||
|
||||
while (iter != g_FetchThread.filenames.end())
|
||||
{
|
||||
curData = (*iter);
|
||||
|
||||
char fileName[30];
|
||||
|
||||
g_LibSys.GetFileFromPath(fileName, sizeof(fileName), curData->filename->c_str());
|
||||
|
||||
if (strcmpi(fileName, file) == 0)
|
||||
{
|
||||
g_SMAPI->ConPrintf("MD5 Sum: %s\n", curData->checksum);
|
||||
return;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
g_SMAPI->ConPrint("File not found!\n");
|
||||
}
|
||||
|
||||
FetcherThread::~FetcherThread()
|
||||
{
|
||||
SourceHook::CVector<FileData *>::iterator iter = filenames.begin();
|
||||
|
||||
FileData *curData;
|
||||
|
||||
while (iter != filenames.end())
|
||||
{
|
||||
curData = (*iter);
|
||||
delete curData->filename;
|
||||
delete curData;
|
||||
iter = filenames.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
FetcherThread::FetcherThread()
|
||||
{
|
||||
memtable = new BaseMemTable(4096);
|
||||
wasSuccess = false;
|
||||
needsRestart = false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
|
||||
#define _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
|
||||
|
||||
#include "sourcemod.h"
|
||||
#include "TextParsers.h"
|
||||
#include "IThreader.h"
|
||||
#include "Logger.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "ThreadSupport.h"
|
||||
#include "sm_memtable.h"
|
||||
#include <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
|
||||
enum UpdateStatus
|
||||
{
|
||||
Update_Unknown = 0, /* Version wasn't recognised or version querying is unsupported */
|
||||
Update_Current = 1, /* Server is running latest version */
|
||||
Update_NewBuild = 2, /* Server is on a svn release and a newer version is available */
|
||||
Update_MinorAvailable = 3, /* Server is on a release and a minor release has superceeded it */
|
||||
Update_MajorAvailable = 4, /* Server is on a release and a major release has superceeded it */
|
||||
Update_CriticalAvailable = 5, /* A critical update has been released (security fixes etc) */
|
||||
};
|
||||
|
||||
class MD5;
|
||||
|
||||
class BuildMD5ableBuffer : public ITextListener_SMC
|
||||
{
|
||||
public:
|
||||
BuildMD5ableBuffer();
|
||||
~BuildMD5ableBuffer();
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
void ReadSMC_ParseEnd(bool halted, bool failed);
|
||||
public:
|
||||
MD5 *checksum;
|
||||
private:
|
||||
BaseStringTable *stringTable;
|
||||
};
|
||||
|
||||
struct FileData
|
||||
{
|
||||
SourceHook::String *filename;
|
||||
char checksum[33];
|
||||
};
|
||||
|
||||
class FetcherThread : public IThread
|
||||
{
|
||||
public:
|
||||
FetcherThread();
|
||||
~FetcherThread();
|
||||
public:
|
||||
void RunThread(IThreadHandle *pHandle);
|
||||
void OnTerminate(IThreadHandle *pHandle, bool cancel);
|
||||
private:
|
||||
int BuildGameDataQuery(char *buffer, int maxlen);
|
||||
void ProcessGameDataQuery(int SocketDescriptor);
|
||||
int RecvData(int socketDescriptor, char *buffer, int len);
|
||||
int SendData(int socketDescriptor, char *buffer, int len);
|
||||
int ConnectSocket();
|
||||
void HandleUpdateStatus(UpdateStatus status, short version[4]);
|
||||
public:
|
||||
SourceHook::CVector<FileData *> filenames;
|
||||
bool needsRestart;
|
||||
bool wasSuccess;
|
||||
private:
|
||||
UpdateStatus updateStatus;
|
||||
BaseMemTable *memtable;
|
||||
short build[4];
|
||||
};
|
||||
|
||||
extern bool g_blockGameDataLoad;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
|
||||
|
||||
+70
-3
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -114,8 +114,6 @@ void CHalfLife2::OnSourceModAllInitialized()
|
||||
m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
|
||||
m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
|
||||
FindInSendTable("CTFPlayer", "m_nDisguiseClass");
|
||||
}
|
||||
|
||||
#if !defined METAMOD_PLAPI_VERSION
|
||||
@@ -437,6 +435,47 @@ bool CHalfLife2::IsLANServer()
|
||||
return (sv_lan->GetInt() != 0);
|
||||
}
|
||||
|
||||
bool CHalfLife2::KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID)
|
||||
{
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
|
||||
#else
|
||||
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
|
||||
#endif
|
||||
{
|
||||
Assert(filesystem);
|
||||
#ifdef _MSC_VER
|
||||
Assert(_heapchk() == _HEAPOK);
|
||||
#endif
|
||||
|
||||
FileHandle_t f = filesystem->Open(resourceName, "rb", pathID);
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
// load file into a null-terminated buffer
|
||||
int fileSize = filesystem->Size(f);
|
||||
char *buffer = (char *)MemAllocScratch(fileSize + 1);
|
||||
|
||||
Assert(buffer);
|
||||
|
||||
filesystem->Read(buffer, fileSize, f); // read into local buffer
|
||||
|
||||
buffer[fileSize] = 0; // null terminate file as EOF
|
||||
|
||||
filesystem->Close( f ); // close file after reading
|
||||
|
||||
bool retOK = kv->LoadFromBuffer( resourceName, buffer, filesystem );
|
||||
|
||||
MemFreeScratch();
|
||||
|
||||
return retOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return kv->LoadFromFile(filesystem, resourceName, pathID);
|
||||
}
|
||||
}
|
||||
|
||||
void CHalfLife2::PushCommandStack(const CCommand *cmd)
|
||||
{
|
||||
CachedCommandInfo info;
|
||||
@@ -472,3 +511,31 @@ const char *CHalfLife2::CurrentCommandName()
|
||||
return m_CommandStack.front().cmd;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
|
||||
{
|
||||
DelayedKickInfo kick;
|
||||
|
||||
kick.client = client;
|
||||
kick.userid = userid;
|
||||
UTIL_Format(kick.buffer, sizeof(kick.buffer), "%s", msg);
|
||||
|
||||
m_DelayedKicks.push(kick);
|
||||
}
|
||||
|
||||
void CHalfLife2::ProcessDelayedKicks()
|
||||
{
|
||||
while (!m_DelayedKicks.empty())
|
||||
{
|
||||
DelayedKickInfo info = m_DelayedKicks.first();
|
||||
m_DelayedKicks.pop();
|
||||
|
||||
CPlayer *player = g_Players.GetPlayerByIndex(info.client);
|
||||
if (player == NULL || player->GetUserId() != info.userid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player->Kick(info.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "sm_queue.h"
|
||||
#include <IGameHelpers.h>
|
||||
#include <KeyValues.h>
|
||||
#include <server_class.h>
|
||||
#include <datamap.h>
|
||||
|
||||
class CCommand;
|
||||
|
||||
@@ -77,6 +79,13 @@ struct CachedCommandInfo
|
||||
#endif
|
||||
};
|
||||
|
||||
struct DelayedKickInfo
|
||||
{
|
||||
int userid;
|
||||
int client;
|
||||
char buffer[384];
|
||||
};
|
||||
|
||||
class CHalfLife2 :
|
||||
public SMGlobalClass,
|
||||
public IGameHelpers
|
||||
@@ -99,6 +108,7 @@ public: //IGameHelpers
|
||||
bool HintTextMsg(int client, const char *msg);
|
||||
bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show);
|
||||
bool IsLANServer();
|
||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
||||
public:
|
||||
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
||||
void ProcessFakeCliCmdQueue();
|
||||
@@ -107,6 +117,8 @@ public:
|
||||
void PopCommandStack();
|
||||
const CCommand *PeekCommandStack();
|
||||
const char *CurrentCommandName();
|
||||
void AddDelayedKick(int client, int userid, const char *msg);
|
||||
void ProcessDelayedKicks();
|
||||
#if !defined METAMOD_PLAPI_VERSION
|
||||
bool IsOriginalEngine();
|
||||
#endif
|
||||
@@ -122,6 +134,7 @@ private:
|
||||
Queue<DelayedFakeCliCmd *> m_CmdQueue;
|
||||
CStack<DelayedFakeCliCmd *> m_FreeCmds;
|
||||
CStack<CachedCommandInfo> m_CommandStack;
|
||||
Queue<DelayedKickInfo> m_DelayedKicks;
|
||||
};
|
||||
|
||||
extern CHalfLife2 g_HL2;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -493,7 +493,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
||||
unsigned int serial = (handle >> 16);
|
||||
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
||||
|
||||
if (index == 0 || index == 0xFFFF)
|
||||
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
||||
{
|
||||
return HandleError_Index;
|
||||
}
|
||||
@@ -910,6 +910,15 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove it from the type cache. */
|
||||
if (pType->nameIdx != -1)
|
||||
{
|
||||
const char *typeName;
|
||||
|
||||
typeName = m_strtab->GetString(pType->nameIdx);
|
||||
sm_trie_delete(m_TypeLookup, typeName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -990,7 +999,7 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
|
||||
g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
|
||||
|
||||
highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS;
|
||||
highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
|
||||
|
||||
return g_PluginSys.UnloadPlugin(highest_owner);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -138,7 +138,7 @@ bool CDirectory::IsEntryDirectory()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_POSIX
|
||||
char temppath[PLATFORM_MAX_PATH];
|
||||
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
return g_LibSys.IsPathDirectory(temppath);
|
||||
@@ -160,7 +160,7 @@ const char *CDirectory::GetEntryName()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return m_fd.cFileName;
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_POSIX
|
||||
return ep ? ep->d_name : "";
|
||||
#endif
|
||||
}
|
||||
@@ -174,7 +174,7 @@ bool CDirectory::IsValid()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return (m_dir != INVALID_HANDLE_VALUE);
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_POSIX
|
||||
return (m_dir != NULL);
|
||||
#endif
|
||||
}
|
||||
@@ -214,7 +214,7 @@ bool LibrarySystem::IsPathFile(const char *path)
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
|
||||
if (stat(path, &s) != 0)
|
||||
@@ -272,25 +272,51 @@ IDirectory *LibrarySystem::OpenDirectory(const char *path)
|
||||
}
|
||||
|
||||
void LibrarySystem::GetPlatformError(char *error, size_t maxlength)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return GetPlatformErrorEx(GetLastError(), error, maxlength);
|
||||
#elif defined PLATFORM_POSIX
|
||||
return GetPlatformErrorEx(errno, error, maxlength);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LibrarySystem::GetPlatformErrorEx(int code, char *error, size_t maxlength)
|
||||
{
|
||||
if (error && maxlength)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
(DWORD)code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)error,
|
||||
maxlength,
|
||||
NULL);
|
||||
#elif defined PLATFORM_LINUX
|
||||
const char *ae = strerror_r(code, error, maxlength);
|
||||
if (ae != error)
|
||||
{
|
||||
UTIL_Format(error, maxlength, "%s", ae);
|
||||
}
|
||||
#elif defined PLATFORM_POSIX
|
||||
snprintf(error, maxlength, "%s", strerror(errno));
|
||||
strerror_r(code, error, maxlength);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
GetPlatformError(buffer, maxlength);
|
||||
#elif defined PLATFORM_POSIX
|
||||
if (buffer != NULL && maxlength)
|
||||
{
|
||||
strncopy(buffer, dlerror(), maxlength);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LibrarySystem::CloseDirectory(IDirectory *dir)
|
||||
{
|
||||
delete dir;
|
||||
@@ -301,20 +327,16 @@ ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxle
|
||||
LibraryHandle lib;
|
||||
#if defined PLATFORM_WINDOWS
|
||||
lib = LoadLibraryA(path);
|
||||
if (!lib)
|
||||
{
|
||||
GetPlatformError(error, maxlength);
|
||||
return false;
|
||||
}
|
||||
#elif defined PLATFORM_POSIX
|
||||
lib = dlopen(path, RTLD_NOW);
|
||||
if (!lib)
|
||||
{
|
||||
GetPlatformError(error, maxlength);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lib == NULL)
|
||||
{
|
||||
GetLoaderError(error, maxlength);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CLibrary(lib);
|
||||
}
|
||||
|
||||
@@ -344,21 +366,26 @@ size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...)
|
||||
|
||||
const char *LibrarySystem::GetFileExtension(const char *filename)
|
||||
{
|
||||
size_t end = strlen(filename) - 1;
|
||||
size_t len, end;
|
||||
|
||||
for (size_t i = end; i >= 0; i--)
|
||||
len = strlen(filename);
|
||||
|
||||
/* Minimum string length for filename with ext would be 3; example: a.a */
|
||||
if (len < 3)
|
||||
{
|
||||
if (i > end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = len - 1;
|
||||
|
||||
for (size_t i = end; i <= end; i--)
|
||||
{
|
||||
if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (filename[i] == '.' && i != end)
|
||||
if (filename[i] == '.' && i != end && i != 0)
|
||||
{
|
||||
return &filename[++i];
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -90,11 +90,13 @@ public:
|
||||
bool IsPathFile(const char *path);
|
||||
bool IsPathDirectory(const char *path);
|
||||
void GetPlatformError(char *error, size_t maxlength);
|
||||
void GetPlatformErrorEx(int code, char *error, size_t maxlength);
|
||||
size_t PathFormat(char *buffer, size_t len, const char *fmt, ...);
|
||||
const char *GetFileExtension(const char *filename);
|
||||
bool CreateFolder(const char *path);
|
||||
size_t GetFileFromPath(char *buffer, size_t maxlength, const char *path);
|
||||
bool FileTime(const char *path, FileTimeType type, time_t *pTime);
|
||||
void GetLoaderError(char *buffer, size_t maxlength);
|
||||
};
|
||||
|
||||
extern LibrarySystem g_LibSys;
|
||||
+35
-2
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "Logger.h"
|
||||
#include "systems/LibrarySys.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "TimerSys.h"
|
||||
#include "sm_version.h"
|
||||
|
||||
@@ -245,6 +245,19 @@ void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
LogToFileOnlyEx(fp, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
@@ -265,6 +278,26 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
||||
g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
|
||||
}
|
||||
|
||||
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[3072];
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
char date[32];
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void Logger::LogMessage(const char *vafmt, ...)
|
||||
{
|
||||
if (!m_Active)
|
||||
|
||||
+4
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -78,6 +78,9 @@ public:
|
||||
void LogFatal(const char *msg, ...);
|
||||
void LogToOpenFile(FILE *fp, const char *msg, ...);
|
||||
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
|
||||
/* This version does not print to console, and is thus thread-safe */
|
||||
void LogToFileOnly(FILE *fp, const char *msg, ...);
|
||||
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
|
||||
void MapChange(const char *mapname);
|
||||
const char *GetLogFileName(LogType type) const;
|
||||
LoggingMode GetLoggingMode() const;
|
||||
|
||||
+73
-71
@@ -1,21 +1,15 @@
|
||||
#(C)2004-2008 Metamod:Source Development Team
|
||||
# (C)2004-2008 SourceMod Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
#Local paths
|
||||
SMSDK = ..
|
||||
SRCDS_BASE = ~/srcds
|
||||
HL2SDK_ORIG = ../../hl2sdk
|
||||
HL2SDK_OB = ../../hl2sdk-ob
|
||||
SOURCEMM14 = ../../sourcemm-1.4
|
||||
SOURCEMM16 = ../../sourcemm-1.6
|
||||
SRCDS_BASE = ~/srcds
|
||||
SMSDK = ..
|
||||
|
||||
#Project options
|
||||
OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing
|
||||
GCC4_FLAGS = -fvisibility=hidden
|
||||
GCC4_CPP_FLAGS = -fvisibility-inlines-hidden
|
||||
DEBUG_FLAGS = -g -ggdb3
|
||||
CPP = gcc-4.1
|
||||
MMSOURCE17 = ../../mmsource-1.7
|
||||
|
||||
#####################################
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
#####################################
|
||||
|
||||
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
|
||||
Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \
|
||||
@@ -23,111 +17,119 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC
|
||||
sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
|
||||
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
|
||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
|
||||
frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp
|
||||
frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp PhraseCollection.cpp NextMap.cpp \
|
||||
NativeOwner.cpp GameDataFetcher.cpp md5.cpp
|
||||
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
|
||||
smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp \
|
||||
smn_handles.cpp smn_keyvalues.cpp smn_banning.cpp smn_maplists.cpp \
|
||||
smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \
|
||||
smn_usermsgs.cpp smn_menus.cpp smn_database.cpp smn_vector.cpp smn_adt_array.cpp \
|
||||
smn_adt_trie.cpp smn_hudtext.cpp
|
||||
OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \
|
||||
systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \
|
||||
systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_function.cpp
|
||||
smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp
|
||||
OBJECTS += ExtensionSys.cpp \
|
||||
ForwardSys.cpp \
|
||||
HandleSys.cpp \
|
||||
LibrarySys.cpp \
|
||||
PluginInfoDatabase.cpp \
|
||||
PluginSys.cpp \
|
||||
ShareSys.cpp
|
||||
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
|
||||
OBJECTS_C = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \
|
||||
zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \
|
||||
zlib/uncompr.c zlib/zutil.c
|
||||
OBJECTS_SM16 = vm/sp_vm_engine.cpp
|
||||
|
||||
##############################################
|
||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||
##############################################
|
||||
|
||||
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
|
||||
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
|
||||
C_GCC4_FLAGS = -fvisibility=hidden
|
||||
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
|
||||
CPP = gcc
|
||||
|
||||
override ENGSET = false
|
||||
ifeq "$(ENGINE)" "original"
|
||||
HL2SDK = $(HL2SDK_ORIG)
|
||||
HL2PUB = $(HL2SDK_ORIG)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
METAMOD = $(SOURCEMM14)
|
||||
INCLUDE += -I$(HL2PUB)/dlls
|
||||
HL2LIB = $(HL2SDK_ORIG)/linux_sdk
|
||||
METAMOD = $(MMSOURCE17)/core-legacy
|
||||
INCLUDE += -I$(HL2SDK)/public/dlls
|
||||
SRCDS = $(SRCDS_BASE)
|
||||
BINARY = sourcemod.1.ep1.so
|
||||
override ENGSET = true
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangebox"
|
||||
HL2SDK = $(HL2SDK_OB)
|
||||
HL2PUB = $(HL2SDK_OB)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
HL2LIB = $(HL2SDK_OB)/lib/linux
|
||||
CFLAGS += -DORANGEBOX_BUILD
|
||||
METAMOD = $(SOURCEMM16)
|
||||
INCLUDE += -I$(HL2PUB)/game/server
|
||||
METAMOD = $(MMSOURCE17)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
SRCDS = $(SRCDS_BASE)/orangebox
|
||||
BINARY = sourcemod.2.ep2.so
|
||||
endif
|
||||
ifeq "$(BINARY)" ""
|
||||
echo "You must supply ENGINE=orangebox or ENGINE=original"
|
||||
false
|
||||
override ENGSET = true
|
||||
endif
|
||||
|
||||
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
|
||||
tier0_i486.so -lpthread -static-libgcc
|
||||
|
||||
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/mathlib -I$(HL2PUB)/vstdlib \
|
||||
-I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook \
|
||||
-I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
||||
|
||||
INCLUDE_SMSDK = -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions
|
||||
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||
-Wno-uninitialized -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -m32
|
||||
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
||||
|
||||
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
|
||||
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook -I$(METAMOD)/sourcemm \
|
||||
-I$(HL2PUB)/mathlib -Isystems $(INCLUDE_SMSDK)
|
||||
|
||||
SM16_INCLUDE = -I. -I.. -I$(SOURCEMM16)/sourcehook $(INCLUDE_SMSDK)
|
||||
################################################
|
||||
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||
################################################
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug.$(ENGINE)
|
||||
CFLAGS += $(DEBUG_FLAGS)
|
||||
CFLAGS += $(C_DEBUG_FLAGS)
|
||||
else
|
||||
BIN_DIR = Release.$(ENGINE)
|
||||
CFLAGS += $(OPT_FLAGS)
|
||||
CFLAGS += $(C_OPT_FLAGS)
|
||||
endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp -Wall -Wno-uninitialized -Werror -mfpmath=sse -msse \
|
||||
-DSOURCEMOD_BUILD -DSM_DEFAULT_THREADER -m32
|
||||
CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
CPPFLAGS += $(GCC4_CPP_FLAGS)
|
||||
CFLAGS += $(C_GCC4_FLAGS)
|
||||
CPPFLAGS += $(CPP_GCC4_FLAGS)
|
||||
endif
|
||||
|
||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.ox)
|
||||
OBJ_LINUX_C := $(OBJECTS_C:%.c=$(BIN_DIR)/%.oc)
|
||||
OBJ_LINUX_SM16 := $(OBJECTS_SM16:%.cpp=$(BIN_DIR)/%.ok)
|
||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
||||
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
|
||||
|
||||
$(BIN_DIR)/%.ox: %.cpp
|
||||
$(BIN_DIR)/%.o: %.cpp
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
||||
|
||||
$(BIN_DIR)/%.oc: %.c
|
||||
$(BIN_DIR)/%.o: %.c
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
$(BIN_DIR)/%.ok: %.cpp
|
||||
$(CPP) $(SM16_INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
||||
|
||||
all:
|
||||
all: check
|
||||
mkdir -p $(BIN_DIR)/systems
|
||||
mkdir -p $(BIN_DIR)/vm
|
||||
mkdir -p $(BIN_DIR)/zlib
|
||||
mkdir -p $(BIN_DIR)/thread
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
|
||||
$(MAKE) -f Makefile sourcemod
|
||||
|
||||
sourcemod: $(OBJ_LINUX) $(OBJ_LINUX_C) $(OBJ_LINUX_SM16)
|
||||
$(CPP) $(OBJ_LINUX) $(OBJ_LINUX_C) $(OBJ_LINUX_SM16) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
check:
|
||||
if [ "$(ENGSET)" = "false" ]; then \
|
||||
echo "You must supply ENGINE=orangebox or ENGINE=original"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
sourcemod: check $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) -f Makefile all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
rm -rf $(BIN_DIR)/*.ox
|
||||
rm -rf $(BIN_DIR)/systems/*.ox
|
||||
rm -rf $(BIN_DIR)/zlib/*.oc
|
||||
rm -rf $(BIN_DIR)/vm/*.ox
|
||||
rm -rf $(BIN_DIR)/thread/*.ox
|
||||
clean: check
|
||||
rm -rf $(BIN_DIR)/*.o
|
||||
rm -rf $(BIN_DIR)/systems/*.o
|
||||
rm -rf $(BIN_DIR)/thread/*.o
|
||||
rm -rf $(BIN_DIR)/$(BINARY)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+28
-5
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "ShareSys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "Translator.h"
|
||||
|
||||
MenuManager g_Menus;
|
||||
VoteMenuHandler s_VoteHandler;
|
||||
@@ -585,14 +586,20 @@ skip_search:
|
||||
{
|
||||
if (exitBackButton)
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Back", NULL);
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
|
||||
{
|
||||
UTIL_Format(text, sizeof(text), "Back");
|
||||
}
|
||||
dr.style = ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
slots[position].type = ItemSel_ExitBack;
|
||||
}
|
||||
else
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Previous", NULL);
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
|
||||
{
|
||||
UTIL_Format(text, sizeof(text), "Previous");
|
||||
}
|
||||
dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
slots[position].type = ItemSel_Back;
|
||||
@@ -610,7 +617,10 @@ skip_search:
|
||||
/* NEXT */
|
||||
if (displayNext || canDrawDisabled)
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Next", NULL);
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
|
||||
{
|
||||
UTIL_Format(text, sizeof(text), "Next");
|
||||
}
|
||||
dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
slots[position].type = ItemSel_Next;
|
||||
@@ -638,7 +648,10 @@ skip_search:
|
||||
/* EXIT */
|
||||
if (exitButton)
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL);
|
||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
|
||||
{
|
||||
UTIL_Format(text, sizeof(text), "Exit");
|
||||
}
|
||||
dr.style = ITEMDRAW_CONTROL;
|
||||
position = panel->DrawItem(dr);
|
||||
slots[position].type = ItemSel_Exit;
|
||||
@@ -777,3 +790,13 @@ unsigned int MenuManager::GetRemainingVoteDelay()
|
||||
{
|
||||
return s_VoteHandler.GetRemainingVoteDelay();
|
||||
}
|
||||
|
||||
bool MenuManager::IsClientInVotePool(int client)
|
||||
{
|
||||
return s_VoteHandler.IsClientInVotePool(client);
|
||||
}
|
||||
|
||||
bool MenuManager::RedrawClientVoteMenu(int client)
|
||||
{
|
||||
return s_VoteHandler.RedrawToClient(client);
|
||||
}
|
||||
|
||||
+3
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -89,6 +89,8 @@ public:
|
||||
bool IsVoteInProgress();
|
||||
void CancelVoting();
|
||||
unsigned int GetRemainingVoteDelay();
|
||||
bool IsClientInVotePool(int client);
|
||||
bool RedrawClientVoteMenu(int client);
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+89
-11
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -113,14 +113,19 @@ void VoteMenuHandler::OnClientDisconnected(int client)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wipe out their vote if they had one */
|
||||
/* Wipe out their vote if they had one. We have to make sure the the the
|
||||
* newly connected client is not allowed to vote.
|
||||
*/
|
||||
int item;
|
||||
if ((item = m_ClientVotes[client]) >= 0)
|
||||
if ((item = m_ClientVotes[client]) >= -1)
|
||||
{
|
||||
assert((unsigned)item < m_Items);
|
||||
assert(m_Votes[item] > 0);
|
||||
m_Votes[item]--;
|
||||
m_ClientVotes[client] = -1;
|
||||
if (item >= 0)
|
||||
{
|
||||
assert((unsigned)item < m_Items);
|
||||
assert(m_Votes[item] > 0);
|
||||
m_Votes[item]--;
|
||||
}
|
||||
m_ClientVotes[client] = -2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,18 +134,28 @@ bool VoteMenuHandler::IsVoteInProgress()
|
||||
return (m_pCurMenu != NULL);
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags/* =0 */)
|
||||
bool VoteMenuHandler::StartVote(IBaseMenu *menu,
|
||||
unsigned int num_clients,
|
||||
int clients[],
|
||||
unsigned int max_time,
|
||||
unsigned int flags/* =0 */)
|
||||
{
|
||||
if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Note: we can use game time and not universal time because
|
||||
* if we're voting then players are in-game.
|
||||
*/
|
||||
|
||||
float fVoteDelay = sm_vote_delay.GetFloat();
|
||||
if (fVoteDelay < 1.0)
|
||||
{
|
||||
g_next_vote = 0.0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This little trick breaks for infinite votes!
|
||||
* However, we just ignore that since those 1) shouldn't exist and
|
||||
* 2) people must be checking IsVoteInProgress() beforehand anyway.
|
||||
@@ -148,8 +163,15 @@ bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int c
|
||||
g_next_vote = gpGlobals->curtime + fVoteDelay + (float)max_time;
|
||||
}
|
||||
|
||||
m_fStartTime = gpGlobals->curtime;
|
||||
m_nMenuTime = max_time;
|
||||
|
||||
for (unsigned int i=0; i<num_clients; i++)
|
||||
{
|
||||
if (clients[i] < 1 || clients[i] > 256)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
menu->Display(clients[i], max_time, this);
|
||||
}
|
||||
|
||||
@@ -158,6 +180,58 @@ bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int c
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::IsClientInVotePool(int client)
|
||||
{
|
||||
if (client < 1
|
||||
|| client > g_Players.MaxClients()
|
||||
|| m_pCurMenu == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (m_ClientVotes[client] > -2);
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
|
||||
{
|
||||
if (!IsClientInVotePool(client)
|
||||
|| m_ClientVotes[client] == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*pItem = m_ClientVotes[client];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::RedrawToClient(int client)
|
||||
{
|
||||
unsigned int time_limit;
|
||||
|
||||
if (!IsClientInVotePool(client))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_nMenuTime == MENU_TIME_FOREVER)
|
||||
{
|
||||
time_limit = m_nMenuTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_limit = (int)((float)m_nMenuTime - (gpGlobals->curtime - m_fStartTime));
|
||||
|
||||
/* Make sure this doesn't round to zero */
|
||||
if (time_limit == MENU_TIME_FOREVER)
|
||||
{
|
||||
time_limit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return m_pCurMenu->Display(client, time_limit, this);
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
|
||||
IMenuHandler *handler,
|
||||
unsigned int time,
|
||||
@@ -187,7 +261,9 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
|
||||
m_Votes[i] = 0;
|
||||
}
|
||||
m_Votes.resize(m_Items, 0);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i=0; i<m_Items; i++)
|
||||
{
|
||||
m_Votes[i] = 0;
|
||||
@@ -252,7 +328,9 @@ void VoteMenuHandler::EndVoting()
|
||||
if (fVoteDelay < 1.0)
|
||||
{
|
||||
g_next_vote = 0.0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
g_next_vote = gpGlobals->curtime + fVoteDelay;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -72,6 +72,9 @@ public:
|
||||
IBaseMenu *GetCurrentMenu();
|
||||
bool IsCancelling();
|
||||
unsigned int GetRemainingVoteDelay();
|
||||
bool IsClientInVotePool(int client);
|
||||
bool GetClientVoteChoice(int client, unsigned int *pItem);
|
||||
bool RedrawToClient(int client);
|
||||
private:
|
||||
void Reset(IMenuHandler *mh);
|
||||
void DecrementPlayerCount();
|
||||
@@ -93,6 +96,8 @@ private:
|
||||
unsigned int m_NumVotes;
|
||||
unsigned int m_VoteTime;
|
||||
unsigned int m_VoteFlags;
|
||||
float m_fStartTime;
|
||||
unsigned int m_nMenuTime;
|
||||
int m_ClientVotes[256+1];
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
#include "PluginSys.h"
|
||||
|
||||
CNativeOwner::CNativeOwner() : m_nMarkSerial(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CNativeOwner::SetMarkSerial(unsigned int serial)
|
||||
{
|
||||
m_nMarkSerial = serial;
|
||||
}
|
||||
|
||||
unsigned int CNativeOwner::GetMarkSerial()
|
||||
{
|
||||
return m_nMarkSerial;
|
||||
}
|
||||
|
||||
void CNativeOwner::AddDependent(CPlugin *pPlugin)
|
||||
{
|
||||
m_Dependents.push_back(pPlugin);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddWeakRef(const WeakNative & ref)
|
||||
{
|
||||
m_WeakRefs.push_back(ref);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((pEntry = g_ShareSys.AddNativeToCache(this, &natives[i])) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Natives.push_back(pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::PropogateMarkSerial(unsigned int serial)
|
||||
{
|
||||
CNativeOwner *pOwner;
|
||||
List<CPlugin *>::iterator iter;
|
||||
|
||||
for (iter = m_Dependents.begin();
|
||||
iter != m_Dependents.end();
|
||||
iter++)
|
||||
{
|
||||
pOwner = (*iter);
|
||||
pOwner->SetMarkSerial(serial);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::UnbindWeakRef(const WeakNative & ref)
|
||||
{
|
||||
sp_native_t *native;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = ref.pl->GetBaseContext();
|
||||
if ((pContext->GetNativeByIndex(ref.idx, &native)) == SP_ERROR_NONE)
|
||||
{
|
||||
/* If there is no reference, the native must be unbound */
|
||||
if (ref.entry == NULL)
|
||||
{
|
||||
native->status = SP_NATIVE_UNBOUND;
|
||||
native->pfn = NULL;
|
||||
}
|
||||
/* If we've cached a reference, it's a core native we can
|
||||
* rebind back to its original (this was a replacement).
|
||||
*/
|
||||
else
|
||||
{
|
||||
native->pfn = ref.entry->func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropEverything()
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
List<WeakNative>::iterator iter;
|
||||
List<NativeEntry *>::iterator ntv_iter;
|
||||
|
||||
/* Unbind and remove all weak references to us */
|
||||
iter = m_WeakRefs.begin();
|
||||
while (iter != m_WeakRefs.end())
|
||||
{
|
||||
UnbindWeakRef((*iter));
|
||||
iter = m_WeakRefs.erase(iter);
|
||||
}
|
||||
|
||||
/* Unmark our replacement natives */
|
||||
ntv_iter = m_ReplacedNatives.begin();
|
||||
while (ntv_iter != m_ReplacedNatives.end())
|
||||
{
|
||||
pEntry = (*ntv_iter);
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
ntv_iter = m_ReplacedNatives.erase(ntv_iter);
|
||||
}
|
||||
|
||||
/* Strip all of our natives from the cache */
|
||||
ntv_iter = m_Natives.begin();
|
||||
while (ntv_iter != m_Natives.end())
|
||||
{
|
||||
g_ShareSys.ClearNativeFromCache(this, (*ntv_iter)->name);
|
||||
ntv_iter = m_Natives.erase(ntv_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropWeakRefsTo(CPlugin *pPlugin)
|
||||
{
|
||||
List<WeakNative>::iterator iter;
|
||||
|
||||
iter = m_WeakRefs.begin();
|
||||
while (iter != m_WeakRefs.end())
|
||||
{
|
||||
WeakNative & ref = (*iter);
|
||||
|
||||
if (ref.pl == pPlugin)
|
||||
{
|
||||
iter = m_WeakRefs.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropRefsTo(CPlugin *pPlugin)
|
||||
{
|
||||
m_Dependents.remove(pPlugin);
|
||||
DropWeakRefsTo(pPlugin);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddReplacedNative(NativeEntry *pEntry)
|
||||
{
|
||||
m_ReplacedNatives.push_back(pEntry);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
|
||||
#define _INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <sh_list.h>
|
||||
|
||||
class CPlugin;
|
||||
struct NativeEntry;
|
||||
|
||||
struct WeakNative
|
||||
{
|
||||
WeakNative(CPlugin *plugin, uint32_t index) :
|
||||
pl(plugin), idx(index), entry(NULL)
|
||||
{
|
||||
pl = plugin;
|
||||
idx = index;
|
||||
}
|
||||
WeakNative(CPlugin *plugin, uint32_t index, NativeEntry *pEntry) :
|
||||
pl(plugin), idx(index), entry(pEntry)
|
||||
{
|
||||
pl = plugin;
|
||||
idx = index;
|
||||
}
|
||||
CPlugin *pl;
|
||||
uint32_t idx;
|
||||
NativeEntry *entry;
|
||||
};
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
class CNativeOwner
|
||||
{
|
||||
public:
|
||||
CNativeOwner();
|
||||
public:
|
||||
virtual void DropEverything();
|
||||
public:
|
||||
void AddNatives(const sp_nativeinfo_t *info);
|
||||
public:
|
||||
void SetMarkSerial(unsigned int serial);
|
||||
unsigned int GetMarkSerial();
|
||||
void PropogateMarkSerial(unsigned int serial);
|
||||
public:
|
||||
void AddDependent(CPlugin *pPlugin);
|
||||
void AddWeakRef(const WeakNative & ref);
|
||||
void DropRefsTo(CPlugin *pPlugin);
|
||||
void AddReplacedNative(NativeEntry *pEntry);
|
||||
private:
|
||||
void DropWeakRefsTo(CPlugin *pPlugin);
|
||||
void UnbindWeakRef(const WeakNative & ref);
|
||||
protected:
|
||||
List<CPlugin *> m_Dependents;
|
||||
unsigned int m_nMarkSerial;
|
||||
List<WeakNative> m_WeakRefs;
|
||||
List<NativeEntry *> m_Natives;
|
||||
List<NativeEntry *> m_ReplacedNatives;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
|
||||
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "NextMap.h"
|
||||
#include "Logger.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcehook.h"
|
||||
#include "sm_srvcmds.h"
|
||||
|
||||
NextMapManager g_NextMap;
|
||||
|
||||
SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *);
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
ConCommand *changeLevelCmd = NULL;
|
||||
|
||||
ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
|
||||
|
||||
bool g_forcedChange = false;
|
||||
|
||||
void NextMapManager::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#else
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
||||
#endif
|
||||
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
ConCommand *pCmd = NULL;
|
||||
while (pBase)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), "changelevel") == 0)
|
||||
{
|
||||
/* Don't want to return convar with same name */
|
||||
if (!pBase->IsCommand())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pCmd = (ConCommand *)pBase;
|
||||
break;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
if (pCmd != NULL)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdChangeLevelCallback, false);
|
||||
changeLevelCmd = pCmd;
|
||||
}
|
||||
}
|
||||
|
||||
void NextMapManager::OnSourceModShutdown()
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#else
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
||||
#endif
|
||||
|
||||
if (changeLevelCmd != NULL)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, changeLevelCmd, CmdChangeLevelCallback, false);
|
||||
}
|
||||
|
||||
SourceHook::List<MapChangeData *>::iterator iter;
|
||||
iter = m_mapHistory.begin();
|
||||
|
||||
while (iter != m_mapHistory.end())
|
||||
{
|
||||
delete (MapChangeData *)*iter;
|
||||
iter = m_mapHistory.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
const char *NextMapManager::GetNextMap()
|
||||
{
|
||||
return sm_nextmap.GetString();
|
||||
}
|
||||
|
||||
bool NextMapManager::SetNextMap(const char *map)
|
||||
{
|
||||
if (!engine->IsMapValid(map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sm_nextmap.SetValue(map);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
||||
{
|
||||
if (g_forcedChange)
|
||||
{
|
||||
g_Logger.LogMessage("[SM] Changed map to \"%s\"", map);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
const char *newmap = sm_nextmap.GetString();
|
||||
|
||||
if (newmap[0] == 0 || !engine->IsMapValid(newmap))
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
|
||||
|
||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");
|
||||
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
|
||||
}
|
||||
|
||||
void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
||||
{
|
||||
/* Skip the first 'mapchange' when the server starts up */
|
||||
if (m_tempChangeInfo.startTime != 0)
|
||||
{
|
||||
if (strcmp(mapName, m_tempChangeInfo.m_mapName) == 0)
|
||||
{
|
||||
/* The map change was as we expected */
|
||||
m_mapHistory.push_back(new MapChangeData(lastMap, m_tempChangeInfo.m_changeReason, m_tempChangeInfo.startTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something intercepted the mapchange */
|
||||
char newReason[255];
|
||||
UTIL_Format(newReason, sizeof(newReason), "%s (Map overridden)", m_tempChangeInfo.m_changeReason);
|
||||
m_mapHistory.push_back(new MapChangeData(lastMap, newReason, m_tempChangeInfo.startTime));
|
||||
}
|
||||
|
||||
/* TODO: Should this be customizable? */
|
||||
if (m_mapHistory.size() > 20)
|
||||
{
|
||||
SourceHook::List<MapChangeData *>::iterator iter;
|
||||
iter = m_mapHistory.begin();
|
||||
|
||||
delete (MapChangeData *)*iter;
|
||||
|
||||
m_mapHistory.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
m_tempChangeInfo.m_mapName[0] ='\0';
|
||||
m_tempChangeInfo.m_changeReason[0] = '\0';
|
||||
m_tempChangeInfo.startTime = time(NULL);
|
||||
UTIL_Format(lastMap, sizeof(lastMap), mapName);
|
||||
}
|
||||
|
||||
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
|
||||
{
|
||||
/* Store the mapname and reason */
|
||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
|
||||
|
||||
/* Change level and skip our hook */
|
||||
g_forcedChange = true;
|
||||
engine->ChangeLevel(mapName, NULL);
|
||||
g_forcedChange = false;
|
||||
}
|
||||
|
||||
NextMapManager::NextMapManager()
|
||||
{
|
||||
m_tempChangeInfo = MapChangeData();
|
||||
m_mapHistory = SourceHook::List<MapChangeData *>();
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void CmdChangeLevelCallback(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
void CmdChangeLevelCallback()
|
||||
{
|
||||
CCommand command;
|
||||
#endif
|
||||
|
||||
if (command.ArgC() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_NextMap.m_tempChangeInfo.m_mapName[0] == '\0')
|
||||
{
|
||||
UTIL_Format(g_NextMap.m_tempChangeInfo.m_mapName, sizeof(g_NextMap.m_tempChangeInfo.m_mapName), command.Arg(1));
|
||||
UTIL_Format(g_NextMap.m_tempChangeInfo.m_changeReason, sizeof(g_NextMap.m_tempChangeInfo.m_changeReason), "changelevel Command");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_NEXTMAP_H_
|
||||
#define _INCLUDE_SOURCEMOD_NEXTMAP_H_
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "eiface.h"
|
||||
#include "sh_list.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
struct MapChangeData
|
||||
{
|
||||
MapChangeData(const char *mapName, const char *changeReason, time_t time)
|
||||
{
|
||||
UTIL_Format(m_mapName, sizeof(m_mapName), mapName);
|
||||
UTIL_Format(m_changeReason, sizeof(m_changeReason), changeReason);
|
||||
startTime = time;
|
||||
}
|
||||
|
||||
MapChangeData()
|
||||
{
|
||||
m_mapName[0] = '\0';
|
||||
m_changeReason[0] = '\0';
|
||||
startTime = 0;
|
||||
}
|
||||
|
||||
char m_mapName[32];
|
||||
char m_changeReason[100];
|
||||
time_t startTime;
|
||||
};
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void CmdChangeLevelCallback(const CCommand &command);
|
||||
#else
|
||||
void CmdChangeLevelCallback();
|
||||
#endif
|
||||
|
||||
class NextMapManager : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
NextMapManager();
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
friend void CmdChangeLevelCallback(const CCommand &command);
|
||||
#else
|
||||
friend void CmdChangeLevelCallback();
|
||||
#endif
|
||||
|
||||
void OnSourceModAllInitialized_Post();
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
|
||||
const char *GetNextMap();
|
||||
bool SetNextMap(const char *map);
|
||||
|
||||
void ForceChangeLevel(const char *mapName, const char* changeReason);
|
||||
|
||||
void HookChangeLevel(const char *map, const char *unknown);
|
||||
|
||||
public:
|
||||
SourceHook::List<MapChangeData *> m_mapHistory;
|
||||
|
||||
private:
|
||||
MapChangeData m_tempChangeInfo;
|
||||
char lastMap[32];
|
||||
};
|
||||
|
||||
extern NextMapManager g_NextMap;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_NEXTMAP_H_
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "PhraseCollection.h"
|
||||
#include "Translator.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
CPhraseCollection::CPhraseCollection()
|
||||
{
|
||||
}
|
||||
|
||||
CPhraseCollection::~CPhraseCollection()
|
||||
{
|
||||
}
|
||||
|
||||
void CPhraseCollection::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
IPhraseFile *CPhraseCollection::AddPhraseFile(const char *filename)
|
||||
{
|
||||
size_t i;
|
||||
unsigned int fid;
|
||||
IPhraseFile *pFile;
|
||||
char full_name[PLATFORM_MAX_PATH];
|
||||
|
||||
/* No compat shim here. The user should have read the doc. */
|
||||
UTIL_Format(full_name, sizeof(full_name), "%s.txt", filename);
|
||||
|
||||
fid = g_Translator.FindOrAddPhraseFile(full_name);
|
||||
pFile = g_Translator.GetFileByIndex(fid);
|
||||
|
||||
for (i = 0; i < m_Files.size(); i++)
|
||||
{
|
||||
if (m_Files[i] == pFile)
|
||||
{
|
||||
return pFile;
|
||||
}
|
||||
}
|
||||
|
||||
m_Files.push_back(pFile);
|
||||
|
||||
return pFile;
|
||||
}
|
||||
|
||||
unsigned int CPhraseCollection::GetFileCount()
|
||||
{
|
||||
return (unsigned int)m_Files.size();
|
||||
}
|
||||
|
||||
IPhraseFile *CPhraseCollection::GetFile(unsigned int file)
|
||||
{
|
||||
if (file >= m_Files.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_Files[file];
|
||||
}
|
||||
|
||||
TransError CPhraseCollection::FindTranslation(const char *key, unsigned int langid, Translation *pTrans)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < m_Files.size(); i++)
|
||||
{
|
||||
if (m_Files[i]->GetTranslation(key, langid, pTrans) == Trans_Okay)
|
||||
{
|
||||
return Trans_Okay;
|
||||
}
|
||||
}
|
||||
|
||||
return Trans_BadPhrase;
|
||||
}
|
||||
|
||||
bool CPhraseCollection::FormatString(char *buffer,
|
||||
size_t maxlength,
|
||||
const char *format,
|
||||
void **params,
|
||||
unsigned int numparams,
|
||||
size_t *pOutLength,
|
||||
const char **pFailPhrase)
|
||||
{
|
||||
unsigned int arg;
|
||||
|
||||
arg = 0;
|
||||
if (!gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arg != numparams)
|
||||
{
|
||||
if (pFailPhrase != NULL)
|
||||
{
|
||||
*pFailPhrase = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_PHRASECOLLECTION_H_
|
||||
#define _INCLUDE_SOURCEMOD_PHRASECOLLECTION_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <sh_vector.h>
|
||||
#include <ITranslator.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
class CPhraseCollection : public IPhraseCollection
|
||||
{
|
||||
public:
|
||||
CPhraseCollection();
|
||||
~CPhraseCollection();
|
||||
public:
|
||||
IPhraseFile *AddPhraseFile(const char *filename);
|
||||
unsigned int GetFileCount();
|
||||
IPhraseFile *GetFile(unsigned int file);
|
||||
void Destroy();
|
||||
TransError FindTranslation(const char *key, unsigned int langid, Translation *pTrans);
|
||||
bool FormatString(
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
const char *format,
|
||||
void **params,
|
||||
unsigned int numparams,
|
||||
size_t *pOutLength,
|
||||
const char **pFailPhrase);
|
||||
private:
|
||||
CVector<IPhraseFile *> m_Files;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_PHRASECOLLECTION_H_
|
||||
+220
-61
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -46,12 +46,14 @@
|
||||
#include <inetchannel.h>
|
||||
#include <iclient.h>
|
||||
#include "GameConfigs.h"
|
||||
#include "ExtensionSys.h"
|
||||
|
||||
PlayerManager g_Players;
|
||||
bool g_OnMapStarted = false;
|
||||
IForward *PreAdminCheck = NULL;
|
||||
IForward *PostAdminCheck = NULL;
|
||||
IForward *PostAdminFilter = NULL;
|
||||
IForward *OnClientConnected = NULL;
|
||||
const unsigned int *g_NumPlayersToAuth = NULL;
|
||||
int lifestate_offset = -1;
|
||||
List<ICommandTargetProcessor *> target_processors;
|
||||
@@ -67,6 +69,15 @@ SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *)
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
ConCommand *maxplayersCmd = NULL;
|
||||
|
||||
class KickPlayerTimer : public ITimedEvent
|
||||
{
|
||||
public:
|
||||
@@ -120,7 +131,7 @@ void PlayerManager::OnSourceModAllInitialized()
|
||||
ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
|
||||
ParamType p2[] = {Param_Cell};
|
||||
|
||||
m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
|
||||
m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_LowEvent, 3, p1);
|
||||
m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
|
||||
m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
|
||||
m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
|
||||
@@ -129,10 +140,40 @@ void PlayerManager::OnSourceModAllInitialized()
|
||||
m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
|
||||
m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
|
||||
m_onActivate2 = g_Forwards.CreateForward("OnMapStart", ET_Ignore, 0, NULL);
|
||||
OnClientConnected = g_Forwards.CreateForward("OnClientConnected", ET_Ignore, 1, p2);
|
||||
|
||||
PreAdminCheck = g_Forwards.CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
|
||||
PostAdminCheck = g_Forwards.CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
|
||||
PostAdminFilter = g_Forwards.CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
|
||||
|
||||
m_bIsListenServer = !engine->IsDedicatedServer();
|
||||
m_ListenClient = 0;
|
||||
|
||||
g_ConVarManager.AddConVarChangeListener("tv_enable", this);
|
||||
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
ConCommand *pCmd = NULL;
|
||||
while (pBase)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), "maxplayers") == 0)
|
||||
{
|
||||
/* Don't want to return convar with same name */
|
||||
if (!pBase->IsCommand())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pCmd = (ConCommand *)pBase;
|
||||
break;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
if (pCmd != NULL)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdMaxplayersCallback, true);
|
||||
maxplayersCmd = pCmd;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::OnSourceModShutdown()
|
||||
@@ -155,12 +196,20 @@ void PlayerManager::OnSourceModShutdown()
|
||||
g_Forwards.ReleaseForward(m_clauth);
|
||||
g_Forwards.ReleaseForward(m_onActivate);
|
||||
g_Forwards.ReleaseForward(m_onActivate2);
|
||||
g_Forwards.ReleaseForward(OnClientConnected);
|
||||
|
||||
g_Forwards.ReleaseForward(PreAdminCheck);
|
||||
g_Forwards.ReleaseForward(PostAdminCheck);
|
||||
g_Forwards.ReleaseForward(PostAdminFilter);
|
||||
|
||||
delete [] m_Players;
|
||||
|
||||
g_ConVarManager.RemoveConVarChangeListener("tv_enable", this);
|
||||
|
||||
if (maxplayersCmd != NULL)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, maxplayersCmd, CmdMaxplayersCallback, true);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
|
||||
@@ -198,14 +247,17 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl
|
||||
/* Initialize all players */
|
||||
m_maxClients = clientMax;
|
||||
m_PlayerCount = 0;
|
||||
m_Players = new CPlayer[m_maxClients + 1];
|
||||
m_AuthQueue = new unsigned int[m_maxClients + 1];
|
||||
m_Players = new CPlayer[ABSOLUTE_PLAYER_LIMIT + 1];
|
||||
m_AuthQueue = new unsigned int[ABSOLUTE_PLAYER_LIMIT + 1];
|
||||
m_FirstPass = true;
|
||||
|
||||
memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
|
||||
memset(m_AuthQueue, 0, sizeof(unsigned int) * (ABSOLUTE_PLAYER_LIMIT + 1));
|
||||
|
||||
g_NumPlayersToAuth = &m_AuthQueue[0];
|
||||
|
||||
g_PluginSys.SyncMaxClients(clientMax);
|
||||
}
|
||||
g_Extensions.CallOnCoreMapStart(pEdictList, edictCount, clientMax);
|
||||
m_onActivate->Execute(NULL);
|
||||
m_onActivate2->Execute(NULL);
|
||||
|
||||
@@ -220,6 +272,13 @@ void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int cl
|
||||
|
||||
g_OnMapStarted = true;
|
||||
|
||||
SMGlobalClass *cls = SMGlobalClass::head;
|
||||
while (cls)
|
||||
{
|
||||
cls->OnSourceModLevelActivated();
|
||||
cls = cls->m_pGlobalClassNext;
|
||||
}
|
||||
|
||||
SM_ExecuteAllConfigs();
|
||||
}
|
||||
|
||||
@@ -283,7 +342,7 @@ void PlayerManager::RunAuthChecks()
|
||||
unsigned int removed = 0;
|
||||
for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
|
||||
{
|
||||
pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
|
||||
pPlayer = &m_Players[m_AuthQueue[i]];
|
||||
authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
|
||||
if (authstr && authstr[0] != '\0'
|
||||
&& (strcmp(authstr, "STEAM_ID_PENDING") != 0))
|
||||
@@ -357,6 +416,7 @@ void PlayerManager::RunAuthChecks()
|
||||
bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
|
||||
{
|
||||
int client = engine->IndexOfEdict(pEntity);
|
||||
CPlayer *pPlayer = &m_Players[client];
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
IClientListener *pListener = NULL;
|
||||
@@ -371,23 +431,28 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
||||
|
||||
cell_t res = 1;
|
||||
|
||||
m_Players[client].Initialize(pszName, pszAddress, pEntity);
|
||||
pPlayer->Initialize(pszName, pszAddress, pEntity);
|
||||
m_clconnect->PushCell(client);
|
||||
m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK);
|
||||
m_clconnect->PushCell(maxrejectlen);
|
||||
m_clconnect->Execute(&res, NULL);
|
||||
m_clconnect->Execute(&res);
|
||||
|
||||
if (res)
|
||||
{
|
||||
if (!m_Players[client].IsAuthorized())
|
||||
if (!pPlayer->IsAuthorized())
|
||||
{
|
||||
m_AuthQueue[++m_AuthQueue[0]] = client;
|
||||
}
|
||||
} else {
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
|
||||
m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = client;
|
||||
m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = client;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pPlayer->IsFakeClient())
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -396,7 +461,7 @@ bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName,
|
||||
{
|
||||
int client = engine->IndexOfEdict(pEntity);
|
||||
bool orig_value = META_RESULT_ORIG_RET(bool);
|
||||
CPlayer *pPlayer = GetPlayerByIndex(client);
|
||||
CPlayer *pPlayer = &m_Players[client];
|
||||
|
||||
if (orig_value)
|
||||
{
|
||||
@@ -411,6 +476,21 @@ bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pPlayer->IsFakeClient()
|
||||
&& m_bIsListenServer
|
||||
&& strncmp(pszAddress, "127.0.0.1", 9) == 0)
|
||||
{
|
||||
m_ListenClient = client;
|
||||
}
|
||||
|
||||
cell_t res;
|
||||
OnClientConnected->PushCell(client);
|
||||
OnClientConnected->Execute(&res, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidatePlayer(pPlayer);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -420,8 +500,8 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
{
|
||||
cell_t res;
|
||||
int client = engine->IndexOfEdict(pEntity);
|
||||
CPlayer *pPlayer = &m_Players[client];
|
||||
|
||||
CPlayer *pPlayer = GetPlayerByIndex(client);
|
||||
/* If they're not connected, they're a bot */
|
||||
if (!pPlayer->IsConnected())
|
||||
{
|
||||
@@ -429,6 +509,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
char error[255];
|
||||
const char *authid = engine->GetPlayerNetworkIDString(pEntity);
|
||||
pPlayer->Authorize(authid);
|
||||
pPlayer->m_bFakeClient = true;
|
||||
if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
|
||||
{
|
||||
/* :TODO: kick the bot if it's rejected */
|
||||
@@ -480,7 +561,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
}
|
||||
}
|
||||
|
||||
m_Players[client].Connect();
|
||||
pPlayer->Connect();
|
||||
m_PlayerCount++;
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
@@ -494,9 +575,9 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
||||
m_clputinserver->PushCell(client);
|
||||
m_clputinserver->Execute(&res, NULL);
|
||||
|
||||
if (m_Players[client].IsAuthorized())
|
||||
if (pPlayer->IsAuthorized())
|
||||
{
|
||||
m_Players[client].DoPostConnectAuthorization();
|
||||
pPlayer->DoPostConnectAuthorization();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,17 +598,20 @@ void PlayerManager::OnClientDisconnect(edict_t *pEntity)
|
||||
{
|
||||
cell_t res;
|
||||
int client = engine->IndexOfEdict(pEntity);
|
||||
CPlayer *pPlayer = &m_Players[client];
|
||||
|
||||
if (m_Players[client].IsConnected())
|
||||
if (pPlayer->IsConnected())
|
||||
{
|
||||
m_cldisconnect->PushCell(client);
|
||||
m_cldisconnect->Execute(&res, NULL);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't care, prevent a double call */
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Players[client].WasCountedAsInGame())
|
||||
if (pPlayer->WasCountedAsInGame())
|
||||
{
|
||||
m_PlayerCount--;
|
||||
}
|
||||
@@ -540,29 +624,12 @@ void PlayerManager::OnClientDisconnect(edict_t *pEntity)
|
||||
pListener->OnClientDisconnecting(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove client from auth queue if necessary
|
||||
*/
|
||||
if (!m_Players[client].IsAuthorized())
|
||||
{
|
||||
for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
|
||||
{
|
||||
if (m_AuthQueue[i] == (unsigned)client)
|
||||
{
|
||||
/* Move everything ahead of us back by one */
|
||||
for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
|
||||
{
|
||||
m_AuthQueue[j-1] = m_AuthQueue[j];
|
||||
}
|
||||
/* Remove us and break */
|
||||
m_AuthQueue[0]--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
InvalidatePlayer(pPlayer);
|
||||
|
||||
m_Players[client].Disconnect();
|
||||
m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = 0;
|
||||
if (m_ListenClient == client)
|
||||
{
|
||||
m_ListenClient = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
|
||||
@@ -592,9 +659,9 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
||||
#endif
|
||||
int client = engine->IndexOfEdict(pEntity);
|
||||
cell_t res = Pl_Continue;
|
||||
CPlayer *pPlayer = &m_Players[client];
|
||||
|
||||
CPlayer *pPlayer = GetPlayerByIndex(client);
|
||||
if (!pPlayer || !pPlayer->IsConnected())
|
||||
if (!pPlayer->IsConnected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -646,8 +713,9 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
||||
{
|
||||
cell_t res;
|
||||
int client = engine->IndexOfEdict(pEntity);
|
||||
CPlayer *pPlayer = &m_Players[client];
|
||||
|
||||
if (!m_Players[client].IsConnected())
|
||||
if (!pPlayer->IsConnected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -655,42 +723,42 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
||||
m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity));
|
||||
m_clinfochanged->Execute(&res, NULL);
|
||||
|
||||
IPlayerInfo *info = m_Players[client].GetPlayerInfo();
|
||||
IPlayerInfo *info = pPlayer->GetPlayerInfo();
|
||||
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
|
||||
const char *old_name = m_Players[client].m_Name.c_str();
|
||||
const char *old_name = pPlayer->m_Name.c_str();
|
||||
|
||||
if (strcmp(old_name, new_name) != 0)
|
||||
{
|
||||
AdminId id = g_Admins.FindAdminByIdentity("name", new_name);
|
||||
if (id != INVALID_ADMIN_ID && m_Players[client].GetAdminId() != id)
|
||||
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
||||
{
|
||||
if (!CheckSetAdminName(client, &m_Players[client], id))
|
||||
if (!CheckSetAdminName(client, pPlayer, id))
|
||||
{
|
||||
m_Players[client].Kick("Your name is reserved by SourceMod; set your password to use it.");
|
||||
pPlayer->Kick("Your name is reserved by SourceMod; set your password to use it.");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
} else if ((id = g_Admins.FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
|
||||
if (id == m_Players[client].GetAdminId())
|
||||
if (id == pPlayer->GetAdminId())
|
||||
{
|
||||
/* This player is changing their name; force them to drop admin privileges! */
|
||||
m_Players[client].SetAdminId(INVALID_ADMIN_ID, false);
|
||||
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
||||
}
|
||||
}
|
||||
m_Players[client].SetName(new_name);
|
||||
pPlayer->SetName(new_name);
|
||||
}
|
||||
|
||||
if (m_PassInfoVar.size() > 0)
|
||||
{
|
||||
/* Try for a password change */
|
||||
const char *old_pass = m_Players[client].m_LastPassword.c_str();
|
||||
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)
|
||||
{
|
||||
m_Players[client].m_LastPassword.assign(new_pass);
|
||||
if (m_Players[client].IsInGame() && m_Players[client].IsAuthorized())
|
||||
pPlayer->m_LastPassword.assign(new_pass);
|
||||
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
|
||||
{
|
||||
/* If there is already an admin id assigned, this will just bail out. */
|
||||
m_Players[client].DoBasicAdminChecks();
|
||||
pPlayer->DoBasicAdminChecks();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -841,6 +909,33 @@ void PlayerManager::UnregisterCommandTargetProcessor(ICommandTargetProcessor *pH
|
||||
target_processors.remove(pHandler);
|
||||
}
|
||||
|
||||
void PlayerManager::InvalidatePlayer(CPlayer *pPlayer)
|
||||
{
|
||||
/**
|
||||
* Remove client from auth queue if necessary
|
||||
*/
|
||||
if (!pPlayer->IsAuthorized())
|
||||
{
|
||||
for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
|
||||
{
|
||||
if (m_AuthQueue[i] == (unsigned)pPlayer->m_iIndex)
|
||||
{
|
||||
/* Move everything ahead of us back by one */
|
||||
for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
|
||||
{
|
||||
m_AuthQueue[j-1] = m_AuthQueue[j];
|
||||
}
|
||||
/* Remove us and break */
|
||||
m_AuthQueue[0]--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_UserIdLookUp[engine->GetPlayerUserId(pPlayer->m_pEdict)] = 0;
|
||||
pPlayer->Disconnect();
|
||||
}
|
||||
|
||||
int PlayerManager::InternalFilterCommandTarget(CPlayer *pAdmin, CPlayer *pTarget, int flags)
|
||||
{
|
||||
if ((flags & COMMAND_FILTER_CONNECTED) == COMMAND_FILTER_CONNECTED
|
||||
@@ -1166,6 +1261,68 @@ void PlayerManager::ProcessCommandTarget(cmd_target_info_t *info)
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::OnConVarChanged( ConVar *pConVar, const char *oldValue, float flOldValue )
|
||||
{
|
||||
if (pConVar->GetBool() && !atoi(oldValue))
|
||||
{
|
||||
MaxPlayersChanged(gpGlobals->maxClients + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxPlayersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::OnSourceModMaxPlayersChanged( int newvalue )
|
||||
{
|
||||
m_maxClients = newvalue;
|
||||
}
|
||||
|
||||
void PlayerManager::MaxPlayersChanged( int newvalue /*= -1*/ )
|
||||
{
|
||||
if (newvalue == -1)
|
||||
{
|
||||
newvalue = gpGlobals->maxClients;
|
||||
}
|
||||
|
||||
if (newvalue == MaxClients())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Notify the rest of core */
|
||||
SMGlobalClass *pBase = SMGlobalClass::head;
|
||||
while (pBase)
|
||||
{
|
||||
pBase->OnSourceModMaxPlayersChanged(newvalue);
|
||||
pBase = pBase->m_pGlobalClassNext;
|
||||
}
|
||||
|
||||
/* Notify Extensions */
|
||||
List<IClientListener *>::iterator iter;
|
||||
IClientListener *pListener = NULL;
|
||||
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
|
||||
{
|
||||
pListener = (*iter);
|
||||
if (pListener->GetClientListenerVersion() >= 8)
|
||||
{
|
||||
pListener->OnMaxPlayersChanged(newvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void CmdMaxplayersCallback(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
void CmdMaxplayersCallback()
|
||||
{
|
||||
#endif
|
||||
|
||||
g_Players.MaxPlayersChanged();
|
||||
}
|
||||
|
||||
|
||||
/*******************
|
||||
*** PLAYER CODE ***
|
||||
*******************/
|
||||
@@ -1182,7 +1339,8 @@ CPlayer::CPlayer()
|
||||
m_bAdminCheckSignalled = false;
|
||||
m_bIsInKickQueue = false;
|
||||
m_LastPassword.clear();
|
||||
m_LangId = LANGUAGE_ENGLISH;
|
||||
m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
|
||||
m_bFakeClient = false;
|
||||
}
|
||||
|
||||
void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|
||||
@@ -1250,6 +1408,7 @@ void CPlayer::Disconnect()
|
||||
m_bAdminCheckSignalled = false;
|
||||
m_UserId = -1;
|
||||
m_bIsInKickQueue = false;
|
||||
m_bFakeClient = false;
|
||||
}
|
||||
|
||||
void CPlayer::SetName(const char *name)
|
||||
@@ -1314,7 +1473,7 @@ IPlayerInfo *CPlayer::GetPlayerInfo()
|
||||
|
||||
bool CPlayer::IsFakeClient()
|
||||
{
|
||||
return (strcmp(m_AuthID.c_str(), "BOT") == 0);
|
||||
return m_bFakeClient;
|
||||
}
|
||||
|
||||
void CPlayer::SetAdminId(AdminId id, bool temporary)
|
||||
@@ -1480,7 +1639,7 @@ void CPlayer::DoBasicAdminChecks()
|
||||
}
|
||||
}
|
||||
|
||||
/* Check IP address */
|
||||
/* Check steam id */
|
||||
if ((id = g_Admins.FindAdminByIdentity("steam", m_AuthID.c_str())) != INVALID_ADMIN_ID)
|
||||
{
|
||||
if (g_Players.CheckSetAdmin(client, this, id))
|
||||
|
||||
+22
-2
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_vector.h>
|
||||
#include "ConVarManager.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@@ -105,11 +106,13 @@ private:
|
||||
int m_iIndex;
|
||||
unsigned int m_LangId;
|
||||
int m_UserId;
|
||||
bool m_bFakeClient;
|
||||
};
|
||||
|
||||
class PlayerManager :
|
||||
public SMGlobalClass,
|
||||
public IPlayerManager
|
||||
public IPlayerManager,
|
||||
public IConVarChangeListener
|
||||
{
|
||||
friend class CPlayer;
|
||||
public:
|
||||
@@ -120,6 +123,7 @@ public: //SMGlobalClass
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModLevelEnd();
|
||||
ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
|
||||
void OnSourceModMaxPlayersChanged(int newvalue);
|
||||
public:
|
||||
CPlayer *GetPlayerByIndex(int client) const;
|
||||
void RunAuthChecks();
|
||||
@@ -152,6 +156,8 @@ public: //IPlayerManager
|
||||
void RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||
void ProcessCommandTarget(cmd_target_info_t *info);
|
||||
public: // IConVarChangeListener
|
||||
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||
public:
|
||||
inline int MaxClients()
|
||||
{
|
||||
@@ -161,14 +167,20 @@ public:
|
||||
{
|
||||
return m_PlayerCount;
|
||||
}
|
||||
inline int ListenClient()
|
||||
{
|
||||
return m_ListenClient;
|
||||
}
|
||||
bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id);
|
||||
bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id);
|
||||
const char *GetPassInfoVar();
|
||||
void RecheckAnyAdmins();
|
||||
unsigned int GetReplyTo();
|
||||
unsigned int SetReplyTo(unsigned int reply);
|
||||
void MaxPlayersChanged(int newvalue = -1);
|
||||
private:
|
||||
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
void InvalidatePlayer(CPlayer *pPlayer);
|
||||
private:
|
||||
List<IClientListener *> m_hooks;
|
||||
IForward *m_clconnect;
|
||||
@@ -188,8 +200,16 @@ private:
|
||||
unsigned int *m_AuthQueue;
|
||||
String m_PassInfoVar;
|
||||
bool m_QueryLang;
|
||||
bool m_bIsListenServer;
|
||||
int m_ListenClient;
|
||||
};
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void CmdMaxplayersCallback(const CCommand &command);
|
||||
#else
|
||||
void CmdMaxplayersCallback();
|
||||
#endif
|
||||
|
||||
extern PlayerManager g_Players;
|
||||
extern bool g_OnMapStarted;
|
||||
extern const unsigned int *g_NumPlayersToAuth;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -43,7 +43,6 @@
|
||||
#include <sh_vector.h>
|
||||
#include <sh_string.h>
|
||||
#include "sm_globals.h"
|
||||
#include "vm/sp_vm_basecontext.h"
|
||||
#include "PluginInfoDatabase.h"
|
||||
#include "sm_trie.h"
|
||||
#include "sourcemod.h"
|
||||
@@ -53,6 +52,9 @@
|
||||
#else
|
||||
#include "convar_sm.h"
|
||||
#endif
|
||||
#include "ITranslator.h"
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@@ -106,27 +108,6 @@ using namespace SourceHook;
|
||||
* 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
|
||||
*/
|
||||
|
||||
#define SM_CONTEXTVAR_MYSELF 0
|
||||
|
||||
struct ContextPair
|
||||
{
|
||||
ContextPair() : base(NULL), ctx(NULL), co(NULL)
|
||||
{
|
||||
};
|
||||
BaseContext *base;
|
||||
sp_context_t *ctx;
|
||||
ICompilation *co;
|
||||
IVirtualMachine *vm;
|
||||
};
|
||||
|
||||
struct FakeNative
|
||||
{
|
||||
IPluginContext *ctx;
|
||||
IPluginFunction *call;
|
||||
String name;
|
||||
SPVM_NATIVE_FUNC func;
|
||||
};
|
||||
|
||||
enum LoadRes
|
||||
{
|
||||
LoadRes_Successful,
|
||||
@@ -143,18 +124,10 @@ struct AutoConfig
|
||||
};
|
||||
|
||||
class CPlugin;
|
||||
struct WeakNative
|
||||
{
|
||||
WeakNative(CPlugin *plugin, uint32_t index)
|
||||
{
|
||||
pl = plugin;
|
||||
idx = index;
|
||||
}
|
||||
CPlugin *pl;
|
||||
uint32_t idx;
|
||||
};
|
||||
|
||||
class CPlugin : public IPlugin
|
||||
class CPlugin :
|
||||
public IPlugin,
|
||||
public CNativeOwner
|
||||
{
|
||||
friend class CPluginManager;
|
||||
friend class CFunction;
|
||||
@@ -165,17 +138,19 @@ public:
|
||||
PluginType GetType();
|
||||
SourcePawn::IPluginContext *GetBaseContext();
|
||||
sp_context_t *GetContext();
|
||||
const sm_plugininfo_t *GetPublicInfo();
|
||||
void *GetPluginStructure();
|
||||
const char *GetFilename();
|
||||
bool IsDebugging();
|
||||
PluginStatus GetStatus();
|
||||
const sm_plugininfo_t *GetPublicInfo();
|
||||
bool SetPauseState(bool paused);
|
||||
unsigned int GetSerial();
|
||||
const sp_plugin_t *GetPluginStructure();
|
||||
IdentityToken_t *GetIdentity();
|
||||
unsigned int CalcMemUsage();
|
||||
bool SetProperty(const char *prop, void *ptr);
|
||||
bool GetProperty(const char *prop, void **ptr, bool remove=false);
|
||||
void DropEverything();
|
||||
SourcePawn::IPluginRuntime *GetRuntime();
|
||||
public:
|
||||
/**
|
||||
* Creates a plugin object with default values.
|
||||
@@ -186,16 +161,6 @@ public:
|
||||
*/
|
||||
static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
|
||||
public:
|
||||
/**
|
||||
* Starts the initial compilation of a plugin.
|
||||
* Returns false if another compilation exists or there is a current context set.
|
||||
*/
|
||||
ICompilation *StartMyCompile(IVirtualMachine *vm);
|
||||
/**
|
||||
* Finalizes a compilation. If error buffer is NULL, the error is saved locally.
|
||||
*/
|
||||
bool FinishMyCompile(char *error, size_t maxlength);
|
||||
void CancelMyCompile();
|
||||
|
||||
/**
|
||||
* Sets an error state on the plugin
|
||||
@@ -233,30 +198,15 @@ public:
|
||||
*/
|
||||
void Call_OnAllPluginsLoaded();
|
||||
|
||||
/**
|
||||
* Toggles debug mode in the plugin
|
||||
*/
|
||||
bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Returns true if a plugin is usable.
|
||||
*/
|
||||
bool IsRunnable();
|
||||
|
||||
/**
|
||||
* Adds a language file index to the plugin's list.
|
||||
* Get languages info.
|
||||
*/
|
||||
void AddLangFile(unsigned int index);
|
||||
|
||||
/**
|
||||
* Get language file count for this plugin.
|
||||
*/
|
||||
size_t GetLangFileCount();
|
||||
|
||||
/**
|
||||
* Get language file index based on the vector index.
|
||||
*/
|
||||
unsigned int GetLangFileByIndex(unsigned int index);
|
||||
IPhraseCollection *GetPhrases();
|
||||
public:
|
||||
/**
|
||||
* Returns the modification time during last plugin load.
|
||||
@@ -275,6 +225,7 @@ public:
|
||||
|
||||
Handle_t GetMyHandle();
|
||||
|
||||
bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
void AddConfig(bool autoCreate, const char *cfg, const char *folder);
|
||||
unsigned int GetConfigCount();
|
||||
AutoConfig *GetConfig(unsigned int i);
|
||||
@@ -283,28 +234,23 @@ public:
|
||||
m_Libraries.push_back(name);
|
||||
}
|
||||
void LibraryActions(bool dropping);
|
||||
void SyncMaxClients(int max_clients);
|
||||
protected:
|
||||
void UpdateInfo();
|
||||
bool UpdateInfo();
|
||||
void SetTimeStamp(time_t t);
|
||||
void DependencyDropped(CPlugin *pOwner);
|
||||
private:
|
||||
ContextPair m_ctx;
|
||||
PluginType m_type;
|
||||
char m_filename[PLATFORM_MAX_PATH];
|
||||
PluginStatus m_status;
|
||||
unsigned int m_serial;
|
||||
sm_plugininfo_t m_info;
|
||||
sp_plugin_t *m_plugin;
|
||||
char m_errormsg[256];
|
||||
time_t m_LastAccess;
|
||||
IdentityToken_t *m_ident;
|
||||
Handle_t m_handle;
|
||||
bool m_WasRunning;
|
||||
CVector<unsigned int> m_PhraseFiles;
|
||||
List<CPlugin *> m_dependents;
|
||||
List<CPlugin *> m_dependsOn;
|
||||
List<FakeNative *> m_fakeNatives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
IPhraseCollection *m_pPhrases;
|
||||
List<String> m_RequiredLibs;
|
||||
List<String> m_Libraries;
|
||||
Trie *m_pProps;
|
||||
@@ -312,6 +258,11 @@ private:
|
||||
bool m_LibraryMissing;
|
||||
CVector<AutoConfig *> m_configs;
|
||||
bool m_bGotAllLoaded;
|
||||
int m_FileVersion;
|
||||
char m_DateTime[256];
|
||||
IPluginRuntime *m_pRuntime;
|
||||
IPluginContext *m_pContext;
|
||||
sp_pubvar_t *m_MaxClientsVar;
|
||||
};
|
||||
|
||||
class CPluginManager :
|
||||
@@ -358,6 +309,7 @@ public: //IPluginManager
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
void OnSourceModMaxPlayersChanged(int newvalue);
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
||||
@@ -390,11 +342,6 @@ public:
|
||||
*/
|
||||
bool IsLateLoadTime() const;
|
||||
|
||||
/**
|
||||
* Adds natives from core into the native pool.
|
||||
*/
|
||||
void RegisterNativesFromCore(sp_nativeinfo_t *natives);
|
||||
|
||||
/**
|
||||
* Converts a Handle to an IPlugin if possible.
|
||||
*/
|
||||
@@ -410,10 +357,7 @@ public:
|
||||
/**
|
||||
* Internal version of FindPluginByContext()
|
||||
*/
|
||||
inline CPlugin *GetPluginByCtx(const sp_context_t *ctx)
|
||||
{
|
||||
return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
|
||||
}
|
||||
CPlugin *GetPluginByCtx(const sp_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Gets status text for a status code
|
||||
@@ -449,6 +393,8 @@ public:
|
||||
void UnloadAll();
|
||||
|
||||
CPlugin *FindPluginByConsoleArg(const char *arg);
|
||||
|
||||
void SyncMaxClients(int max_clients);
|
||||
private:
|
||||
LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
|
||||
|
||||
@@ -469,11 +415,6 @@ private:
|
||||
*/
|
||||
bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Adds any globally registered natives to a plugin
|
||||
*/
|
||||
void AddCoreNativesToPlugin(CPlugin *pPlugin);
|
||||
|
||||
/**
|
||||
* Runs an extension pass on a plugin.
|
||||
*/
|
||||
@@ -495,11 +436,7 @@ public:
|
||||
{
|
||||
return m_MyIdent;
|
||||
}
|
||||
public:
|
||||
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
SPVM_NATIVE_FUNC FindCoreNative(const char *name);
|
||||
private:
|
||||
void AddFakeNativesToPlugin(CPlugin *pPlugin);
|
||||
void TryRefreshDependencies(CPlugin *pOther);
|
||||
private:
|
||||
List<IPluginsListener *> m_listeners;
|
||||
@@ -509,11 +446,9 @@ private:
|
||||
Trie *m_LoadLookup;
|
||||
bool m_AllPluginsLoaded;
|
||||
IdentityToken_t *m_MyIdent;
|
||||
Trie *m_pCoreNatives;
|
||||
|
||||
/* Dynamic native stuff */
|
||||
List<FakeNative *> m_Natives;
|
||||
Trie *m_pNativeLookup;
|
||||
|
||||
bool m_LoadingLocked;
|
||||
};
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -0,0 +1,529 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ShareSys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
ShareSystem g_ShareSys;
|
||||
static unsigned int g_mark_serial = 0;
|
||||
|
||||
ShareSystem::ShareSystem()
|
||||
{
|
||||
m_IdentRoot.ident = 0;
|
||||
m_TypeRoot = 0;
|
||||
m_IfaceType = 0;
|
||||
m_CoreType = 0;
|
||||
}
|
||||
|
||||
IdentityToken_t *ShareSystem::CreateCoreIdentity()
|
||||
{
|
||||
if (!m_CoreType)
|
||||
{
|
||||
m_CoreType = CreateIdentType("CORE");
|
||||
}
|
||||
|
||||
return CreateIdentity(m_CoreType, this);
|
||||
}
|
||||
|
||||
void ShareSystem::Initialize()
|
||||
{
|
||||
TypeAccess sec;
|
||||
|
||||
g_HandleSys.InitAccessDefaults(&sec, NULL);
|
||||
sec.ident = GetIdentRoot();
|
||||
|
||||
m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
|
||||
m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
|
||||
|
||||
/* Initialize our static identity handle */
|
||||
m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
|
||||
|
||||
/* Add the Handle System and others... they are too innocent and pure to do it themselves */
|
||||
AddInterface(NULL, &g_HandleSys);
|
||||
AddInterface(NULL, &g_LibSys);
|
||||
}
|
||||
|
||||
void ShareSystem::OnSourceModShutdown()
|
||||
{
|
||||
if (m_CoreType)
|
||||
{
|
||||
g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
|
||||
}
|
||||
|
||||
g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
|
||||
g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
|
||||
}
|
||||
|
||||
IdentityType_t ShareSystem::FindIdentType(const char *name)
|
||||
{
|
||||
HandleType_t type;
|
||||
|
||||
if (g_HandleSys.FindHandleType(name, &type))
|
||||
{
|
||||
if (g_HandleSys.TypeCheck(type, m_TypeRoot))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IdentityType_t ShareSystem::CreateIdentType(const char *name)
|
||||
{
|
||||
if (!m_TypeRoot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
|
||||
}
|
||||
|
||||
void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
|
||||
}
|
||||
|
||||
IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
|
||||
{
|
||||
if (!m_TypeRoot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* :TODO: Cache? */
|
||||
IdentityToken_t *pToken = new IdentityToken_t;
|
||||
|
||||
HandleSecurity sec;
|
||||
sec.pOwner = sec.pIdentity = GetIdentRoot();
|
||||
|
||||
pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
|
||||
pToken->ptr = ptr;
|
||||
pToken->type = type;
|
||||
|
||||
return pToken;
|
||||
}
|
||||
|
||||
bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
|
||||
{
|
||||
if (!iface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IfaceInfo info;
|
||||
|
||||
info.owner = myself;
|
||||
info.iface = iface;
|
||||
|
||||
m_Interfaces.push_back(info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShareSystem::RequestInterface(const char *iface_name,
|
||||
unsigned int iface_vers,
|
||||
IExtension *myself,
|
||||
SMInterface **pIface)
|
||||
{
|
||||
/* See if the interface exists */
|
||||
List<IfaceInfo>::iterator iter;
|
||||
SMInterface *iface;
|
||||
IExtension *iface_owner;
|
||||
bool found = false;
|
||||
for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
|
||||
{
|
||||
IfaceInfo &info = (*iter);
|
||||
iface = info.iface;
|
||||
if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
|
||||
{
|
||||
if (iface->GetInterfaceVersion() == iface_vers
|
||||
|| iface->IsVersionCompatible(iface_vers))
|
||||
{
|
||||
iface_owner = info.owner;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add a dependency node */
|
||||
if (iface_owner)
|
||||
{
|
||||
IfaceInfo info;
|
||||
info.iface = iface;
|
||||
info.owner = iface_owner;
|
||||
g_Extensions.BindDependency(myself, &info);
|
||||
}
|
||||
|
||||
if (pIface)
|
||||
{
|
||||
*pIface = iface;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
CNativeOwner *pOwner;
|
||||
|
||||
pOwner = g_Extensions.GetNativeOwner(myself);
|
||||
|
||||
pOwner->AddNatives(natives);
|
||||
}
|
||||
|
||||
void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
|
||||
{
|
||||
HandleSecurity sec;
|
||||
|
||||
sec.pOwner = GetIdentRoot();
|
||||
sec.pIdentity = GetIdentRoot();
|
||||
|
||||
g_HandleSys.FreeHandle(identity->ident, &sec);
|
||||
delete identity;
|
||||
}
|
||||
|
||||
void ShareSystem::DestroyIdentType(IdentityType_t type)
|
||||
{
|
||||
g_HandleSys.RemoveType(type, GetIdentRoot());
|
||||
}
|
||||
|
||||
void ShareSystem::RemoveInterfaces(IExtension *pExtension)
|
||||
{
|
||||
List<IfaceInfo>::iterator iter = m_Interfaces.begin();
|
||||
|
||||
while (iter != m_Interfaces.end())
|
||||
{
|
||||
if ((*iter).owner == pExtension)
|
||||
{
|
||||
iter = m_Interfaces.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
|
||||
{
|
||||
g_Extensions.AddDependency(myself, filename, require, autoload);
|
||||
}
|
||||
|
||||
void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
|
||||
{
|
||||
g_Extensions.AddLibrary(myself, name);
|
||||
}
|
||||
|
||||
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
unsigned int i;
|
||||
NativeEntry *pEntry;
|
||||
CNativeOwner *pOwner;
|
||||
|
||||
pOwner = g_Extensions.GetNativeOwner(myself);
|
||||
|
||||
for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((pEntry = FindNative(natives[i].name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pEntry->owner != g_pCoreNatives)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pEntry->replacement.owner != NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now it's safe to add the override */
|
||||
pEntry->replacement.func = natives[i].func;
|
||||
pEntry->replacement.owner = pOwner;
|
||||
pOwner->AddReplacedNative(pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
NativeEntry *ShareSystem::FindNative(const char *name)
|
||||
{
|
||||
NativeEntry **ppEntry;
|
||||
|
||||
if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return *ppEntry;
|
||||
}
|
||||
|
||||
void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
sp_native_t *native;
|
||||
uint32_t i, native_count;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = pPlugin->GetBaseContext();
|
||||
|
||||
/* Generate a new serial ID, mark our dependencies with it. */
|
||||
g_mark_serial++;
|
||||
pPlugin->PropogateMarkSerial(g_mark_serial);
|
||||
|
||||
native_count = pContext->GetNativesNum();
|
||||
for (i = 0; i < native_count; i++)
|
||||
{
|
||||
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're bound, check if there is a replacement available.
|
||||
* If not, this native is totally finalized.
|
||||
*/
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
pEntry = (NativeEntry *)native->user;
|
||||
assert(pEntry != NULL);
|
||||
if (pEntry->replacement.owner == NULL
|
||||
|| (pEntry->replacement.owner != NULL
|
||||
&& pEntry->replacement.func == native->pfn))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Otherwise, the native must be in our cache. */
|
||||
else if ((pEntry = FindNative(native->name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bCoreOnly && pEntry->owner != g_pCoreNatives)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BindNativeToPlugin(pPlugin, native, i, pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
|
||||
{
|
||||
uint32_t i;
|
||||
sp_native_t *native;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = pPlugin->GetBaseContext();
|
||||
|
||||
if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BindNativeToPlugin(pPlugin, native, i, pEntry);
|
||||
}
|
||||
|
||||
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin,
|
||||
sp_native_t *native,
|
||||
uint32_t index,
|
||||
NativeEntry *pEntry)
|
||||
{
|
||||
/* Mark as bound... we do the rest next. */
|
||||
native->status = SP_NATIVE_BOUND;
|
||||
native->user = pEntry;
|
||||
|
||||
/* See if a replacement is available. */
|
||||
if (pEntry->replacement.owner != NULL)
|
||||
{
|
||||
/* Perform a replacement bind. */
|
||||
native->pfn = pEntry->replacement.func;
|
||||
pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform a normal bind. */
|
||||
native->pfn = pEntry->func;
|
||||
|
||||
/* We don't bother with dependency crap if the owner is Core. */
|
||||
if (pEntry->owner != g_pCoreNatives)
|
||||
{
|
||||
/* The native is optional, this is a special case */
|
||||
if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
|
||||
{
|
||||
/* Only add if there is a valid owner. */
|
||||
if (pEntry->owner != NULL)
|
||||
{
|
||||
pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
native->status = SP_NATIVE_UNBOUND;
|
||||
}
|
||||
}
|
||||
/* Otherwise, we're a strong dependent and not a weak one */
|
||||
else
|
||||
{
|
||||
/* See if this has already been marked as a dependent.
|
||||
* If it has, it means this relationship has already occurred,
|
||||
* and there is no reason to do it again.
|
||||
*/
|
||||
if (pEntry->owner != pPlugin
|
||||
&& pEntry->owner->GetMarkSerial() != g_mark_serial)
|
||||
{
|
||||
/* This has not been marked as a dependency yet */
|
||||
//pPlugin->AddDependency(pEntry->owner);
|
||||
pEntry->owner->AddDependent(pPlugin);
|
||||
pEntry->owner->SetMarkSerial(g_mark_serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
if ((pEntry = FindNative(ntv->name)) == NULL)
|
||||
{
|
||||
pEntry = new NativeEntry;
|
||||
|
||||
pEntry->owner = pOwner;
|
||||
pEntry->name = ntv->name;
|
||||
pEntry->func = ntv->func;
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
pEntry->fake = NULL;
|
||||
|
||||
m_NtvCache.insert(ntv->name, pEntry);
|
||||
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
if (pEntry->owner != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pEntry->owner = pOwner;
|
||||
pEntry->func = ntv->func;
|
||||
pEntry->name = ntv->name;
|
||||
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
if ((pEntry = FindNative(name)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pEntry->owner != pOwner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pEntry->fake != NULL)
|
||||
{
|
||||
g_pSourcePawn2->DestroyFakeNative(pEntry->func);
|
||||
delete pEntry->fake;
|
||||
pEntry->fake = NULL;
|
||||
}
|
||||
|
||||
pEntry->func = NULL;
|
||||
pEntry->name = NULL;
|
||||
pEntry->owner = NULL;
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
}
|
||||
|
||||
NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
|
||||
{
|
||||
FakeNative *pFake;
|
||||
NativeEntry *pEntry;
|
||||
SPVM_NATIVE_FUNC gate;
|
||||
|
||||
if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFake = new FakeNative;
|
||||
|
||||
if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
|
||||
{
|
||||
delete pFake;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
pEntry = new NativeEntry;
|
||||
m_NtvCache.insert(name, pEntry);
|
||||
}
|
||||
|
||||
pFake->call = pFunc;
|
||||
pFake->ctx = pFunc->GetParentContext();
|
||||
strncopy(pFake->name, name, sizeof(pFake->name));
|
||||
|
||||
pEntry->fake = pFake;
|
||||
pEntry->func = gate;
|
||||
pEntry->name = pFake->name;
|
||||
pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
|
||||
return pEntry;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <IShareSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <sh_list.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemod.h"
|
||||
|
||||
@@ -60,11 +61,38 @@ struct IfaceInfo
|
||||
IExtension *owner;
|
||||
};
|
||||
|
||||
class CNativeOwner;
|
||||
class CPlugin;
|
||||
struct NativeEntry;
|
||||
|
||||
struct ReplaceNative
|
||||
{
|
||||
CNativeOwner *owner;
|
||||
SPVM_NATIVE_FUNC func;
|
||||
};
|
||||
|
||||
struct FakeNative
|
||||
{
|
||||
char name[64];
|
||||
IPluginContext *ctx;
|
||||
IPluginFunction *call;
|
||||
};
|
||||
|
||||
struct NativeEntry
|
||||
{
|
||||
CNativeOwner *owner;
|
||||
SPVM_NATIVE_FUNC func;
|
||||
const char *name;
|
||||
ReplaceNative replacement;
|
||||
FakeNative *fake;
|
||||
};
|
||||
|
||||
class ShareSystem :
|
||||
public IShareSys,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
{
|
||||
friend class CNativeOwner;
|
||||
public:
|
||||
ShareSystem();
|
||||
public: //IShareSys
|
||||
@@ -96,12 +124,25 @@ public:
|
||||
{
|
||||
return &m_IdentRoot;
|
||||
}
|
||||
public:
|
||||
void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
|
||||
void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
|
||||
NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
private:
|
||||
NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
|
||||
void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
|
||||
NativeEntry *FindNative(const char *name);
|
||||
void BindNativeToPlugin(CPlugin *pPlugin,
|
||||
sp_native_t *ntv,
|
||||
uint32_t index,
|
||||
NativeEntry *pEntry);
|
||||
private:
|
||||
List<IfaceInfo> m_Interfaces;
|
||||
HandleType_t m_TypeRoot;
|
||||
IdentityToken_t m_IdentRoot;
|
||||
HandleType_t m_IfaceType;
|
||||
IdentityType_t m_CoreType;
|
||||
KTrie<NativeEntry *> m_NtvCache;
|
||||
};
|
||||
|
||||
extern ShareSystem g_ShareSys;
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+179
-91
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -38,9 +38,11 @@
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemod.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "PhraseCollection.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
Translator g_Translator;
|
||||
CPhraseFile *g_pCorePhrases = NULL;
|
||||
IPhraseCollection *g_pCorePhrases = NULL;
|
||||
unsigned int g_pCorePhraseID = 0;
|
||||
|
||||
struct trans_t
|
||||
@@ -101,7 +103,7 @@ void CPhraseFile::ParseWarning(const char *message, ...)
|
||||
m_FileLogged = true;
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] %s", message);
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
}
|
||||
|
||||
void CPhraseFile::ReparseFile()
|
||||
@@ -150,6 +152,45 @@ void CPhraseFile::ReparseFile()
|
||||
g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
|
||||
g_Logger.LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
|
||||
}
|
||||
|
||||
const char *code;
|
||||
for (unsigned int i = 1; i < m_LangCount; i++)
|
||||
{
|
||||
if (!m_pTranslator->GetLanguageInfo(i, &code, NULL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"translations/%s/%s",
|
||||
code,
|
||||
m_File.c_str());
|
||||
|
||||
/* Speculatively load these. */
|
||||
if (!g_LibSys.PathExists(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((err=textparsers->ParseFile_SMC(path, this, &states)) != SMCError_Okay)
|
||||
{
|
||||
const char *msg = textparsers->GetSMCErrorString(err);
|
||||
if (!msg)
|
||||
{
|
||||
msg = m_ParseError.c_str();
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s/%s\"",
|
||||
code,
|
||||
m_File.c_str());
|
||||
g_Logger.LogError("[SM] Error (line %d, column %d): %s",
|
||||
states.line,
|
||||
states.col,
|
||||
msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPhraseFile::ReadSMC_ParseStart()
|
||||
@@ -176,21 +217,21 @@ SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
m_ParseState = PPS_InPhrase;
|
||||
recognized = true;
|
||||
|
||||
phrase_t *pPhrase;
|
||||
m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase);
|
||||
void *value;
|
||||
if (sm_trie_retrieve(m_pPhraseLookup, name, &value))
|
||||
{
|
||||
m_CurPhrase = reinterpret_cast<int>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
phrase_t *pPhrase;
|
||||
|
||||
m_CurPhrase = m_pMemory->CreateMem(sizeof(phrase_t), (void **)&pPhrase);
|
||||
sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast<void *>(m_CurPhrase));
|
||||
|
||||
/* Create the reverse lookup */
|
||||
if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast<void *>(m_CurPhrase)))
|
||||
{
|
||||
ParseWarning("Skipping duplicate phrase \"%s\" on line %d.", name, states->line);
|
||||
/* :IDEA: prevent memory waste by seeking backwards in memtable? */
|
||||
m_CurPhrase = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Initialize new phrase */
|
||||
trans_t *pTrans;
|
||||
|
||||
|
||||
pPhrase->fmt_count = 0;
|
||||
pPhrase->fmt_list = -1;
|
||||
|
||||
@@ -200,13 +241,14 @@ SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *n
|
||||
|
||||
pPhrase->translations = 0;
|
||||
pPhrase->fmt_bytes = 0;
|
||||
|
||||
|
||||
for (unsigned int i=0; i<m_LangCount; i++)
|
||||
{
|
||||
pTrans[i].stridx = -1;
|
||||
}
|
||||
m_LastPhraseString.assign(name);
|
||||
}
|
||||
|
||||
m_LastPhraseString.assign(name);
|
||||
}
|
||||
else if (m_ParseState == PPS_InPhrase)
|
||||
{
|
||||
@@ -231,15 +273,12 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
||||
}
|
||||
|
||||
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(m_CurPhrase);
|
||||
|
||||
if (key[0] == '#' && strcmp(key, "#format") == 0)
|
||||
{
|
||||
if (pPhrase->fmt_list != -1)
|
||||
{
|
||||
ParseWarning("Ignoring duplicated #format property on line %d", states->line);
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
/* Duplicate format keys get silently ignored. */
|
||||
if (key[0] == '#'
|
||||
&& strcmp(key, "#format") == 0
|
||||
&& pPhrase->fmt_list == -1)
|
||||
{
|
||||
if (pPhrase->translations > 0)
|
||||
{
|
||||
ParseWarning("#format property should come before translations on line %d, ignoring", states->line);
|
||||
@@ -448,7 +487,7 @@ SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
||||
else
|
||||
{
|
||||
size_t len = strlen(key);
|
||||
if (len != 2)
|
||||
if (len < 2 || len > 3)
|
||||
{
|
||||
ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, states->line);
|
||||
return SMCResult_Continue;
|
||||
@@ -663,7 +702,7 @@ const char *CPhraseFile::GetFilename()
|
||||
** MAIN TRANSLATOR CODE **
|
||||
**************************/
|
||||
|
||||
Translator::Translator() : m_ServerLang(LANGUAGE_ENGLISH)
|
||||
Translator::Translator() : m_ServerLang(SOURCEMOD_LANGUAGE_ENGLISH)
|
||||
{
|
||||
m_pStringTab = new BaseStringTable(2048);
|
||||
m_pLCodeLookup = sm_trie_create();
|
||||
@@ -727,11 +766,15 @@ void Translator::OnSourceModAllInitialized()
|
||||
{
|
||||
AddLanguage("en", "English");
|
||||
|
||||
unsigned int id;
|
||||
g_pCorePhrases = CreatePhraseCollection();
|
||||
g_pCorePhrases->AddPhraseFile("core.phrases");
|
||||
|
||||
id = FindOrAddPhraseFile("core.phrases.txt");
|
||||
g_pCorePhraseID = id;
|
||||
g_pCorePhrases = GetFileByIndex(id);
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
void Translator::OnSourceModShutdown()
|
||||
{
|
||||
g_pCorePhrases->Destroy();
|
||||
}
|
||||
|
||||
bool Translator::GetLanguageByCode(const char *code, unsigned int *index)
|
||||
@@ -842,7 +885,7 @@ void Translator::RebuildLanguageDatabase(const char *lang_header_file)
|
||||
g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang);
|
||||
|
||||
strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
|
||||
m_ServerLang = LANGUAGE_ENGLISH;
|
||||
m_ServerLang = SOURCEMOD_LANGUAGE_ENGLISH;
|
||||
}
|
||||
|
||||
m_ServerLang = reinterpret_cast<unsigned int>(serverLang);
|
||||
@@ -893,7 +936,7 @@ SMCResult Translator::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
||||
{
|
||||
size_t len = strlen(key);
|
||||
|
||||
if (len != 2)
|
||||
if (len < 2 || len > 3)
|
||||
{
|
||||
g_Logger.LogError("[SM] Warning encountered parsing languages.cfg file.");
|
||||
g_Logger.LogError("[SM] Invalid language code \"%s\" is being ignored.", key);
|
||||
@@ -914,9 +957,7 @@ bool Translator::AddLanguage(const char *langcode, const char *description)
|
||||
Language *pLanguage = new Language;
|
||||
unsigned int idx = m_Languages.size();
|
||||
|
||||
pLanguage->m_code2[0] = langcode[0];
|
||||
pLanguage->m_code2[1] = langcode[1];
|
||||
pLanguage->m_code2[2] = langcode[2];
|
||||
UTIL_Format(pLanguage->m_code2, sizeof(pLanguage->m_code2), "%s", langcode);
|
||||
pLanguage->m_FullName = m_pStringTab->AddString(description);
|
||||
|
||||
sm_trie_insert(m_pLCodeLookup, langcode, reinterpret_cast<void *>(idx));
|
||||
@@ -936,61 +977,6 @@ CPhraseFile *Translator::GetFileByIndex(unsigned int index)
|
||||
return m_Files[index];
|
||||
}
|
||||
|
||||
size_t Translator::Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans)
|
||||
{
|
||||
void *new_params[MAX_TRANSLATE_PARAMS];
|
||||
|
||||
/* Rewrite the parameter order */
|
||||
for (unsigned int i=0; i<pTrans->fmt_count; i++)
|
||||
{
|
||||
new_params[i] = params[pTrans->fmt_order[i]];
|
||||
}
|
||||
|
||||
return gnprintf(buffer, maxlength, pTrans->szPhrase, new_params);
|
||||
}
|
||||
|
||||
TransError Translator::CoreTransEx(CPhraseFile *pFile,
|
||||
int client,
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
const char *phrase,
|
||||
void **params,
|
||||
size_t *outlen)
|
||||
{
|
||||
Translation trans;
|
||||
TransError err;
|
||||
|
||||
/* Using server lang temporarily until client lang stuff is implemented */
|
||||
if ((err = pFile->GetTranslation(phrase, m_ServerLang, &trans)) != Trans_Okay)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t len = Translate(buffer, maxlength, params, &trans);
|
||||
|
||||
if (outlen)
|
||||
{
|
||||
*outlen = len;
|
||||
}
|
||||
|
||||
return Trans_Okay;
|
||||
}
|
||||
|
||||
TransError Translator::CoreTrans(int client,
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
const char *phrase,
|
||||
void **params,
|
||||
size_t *outlen)
|
||||
{
|
||||
if (!g_pCorePhrases)
|
||||
{
|
||||
return Trans_BadPhraseFile;
|
||||
}
|
||||
|
||||
return CoreTransEx(g_pCorePhrases, client, buffer, maxlength, phrase, params, outlen);
|
||||
}
|
||||
|
||||
unsigned int Translator::GetServerLanguage()
|
||||
{
|
||||
return m_ServerLang;
|
||||
@@ -1021,3 +1007,105 @@ bool Translator::GetLanguageInfo(unsigned int number, const char **code, const c
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *Translator::GetInterfaceName()
|
||||
{
|
||||
return SMINTERFACE_TRANSLATOR_NAME;
|
||||
}
|
||||
|
||||
unsigned int Translator::GetInterfaceVersion()
|
||||
{
|
||||
return SMINTERFACE_TRANSLATOR_VERSION;
|
||||
}
|
||||
|
||||
IPhraseCollection *Translator::CreatePhraseCollection()
|
||||
{
|
||||
return new CPhraseCollection();
|
||||
}
|
||||
|
||||
int Translator::SetGlobalTarget(int index)
|
||||
{
|
||||
return g_SourceMod.SetGlobalTarget(index);
|
||||
}
|
||||
|
||||
int Translator::GetGlobalTarget() const
|
||||
{
|
||||
return g_SourceMod.GetGlobalTarget();
|
||||
}
|
||||
|
||||
bool CoreTranslate(char *buffer,
|
||||
size_t maxlength,
|
||||
const char *format,
|
||||
unsigned int numparams,
|
||||
size_t *pOutLength,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
unsigned int i;
|
||||
const char *fail_phrase;
|
||||
void *params[MAX_TRANSLATE_PARAMS];
|
||||
|
||||
if (numparams > MAX_TRANSLATE_PARAMS)
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
va_start(ap, pOutLength);
|
||||
for (i = 0; i < numparams; i++)
|
||||
{
|
||||
params[i] = va_arg(ap, void *);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (!g_pCorePhrases->FormatString(buffer,
|
||||
maxlength,
|
||||
format,
|
||||
params,
|
||||
numparams,
|
||||
pOutLength,
|
||||
&fail_phrase))
|
||||
{
|
||||
if (fail_phrase != NULL)
|
||||
{
|
||||
g_Logger.LogError("[SM] Could not find core phrase: %s", fail_phrase);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Logger.LogError("[SM] Unknown fatal error while translating a core phrase.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Translator::FormatString(char *buffer,
|
||||
size_t maxlength,
|
||||
const char *format,
|
||||
IPhraseCollection *pPhrases,
|
||||
void **params,
|
||||
unsigned int numparams,
|
||||
size_t *pOutLength,
|
||||
const char **pFailPhrase)
|
||||
{
|
||||
unsigned int arg;
|
||||
|
||||
arg = 0;
|
||||
if (!gnprintf(buffer, maxlength, format, pPhrases, params, numparams, arg, pOutLength, pFailPhrase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arg != numparams)
|
||||
{
|
||||
if (pFailPhrase != NULL)
|
||||
{
|
||||
*pFailPhrase = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+40
-38
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "sm_globals.h"
|
||||
#include "sm_memtable.h"
|
||||
#include "ITextParsers.h"
|
||||
#include <ITranslator.h>
|
||||
|
||||
#define MAX_TRANSLATE_PARAMS 32
|
||||
#define CORELANG_ENGLISH 0
|
||||
@@ -56,29 +57,13 @@ enum PhraseParseState
|
||||
|
||||
struct Language
|
||||
{
|
||||
char m_code2[3];
|
||||
char m_code2[4];
|
||||
int m_FullName;
|
||||
};
|
||||
|
||||
struct Translation
|
||||
{
|
||||
const char *szPhrase; /**< Translated phrase. */
|
||||
unsigned int fmt_count; /**< Number of format parameters. */
|
||||
int *fmt_order; /**< Format phrase order. */
|
||||
};
|
||||
|
||||
#define LANGUAGE_ENGLISH 0
|
||||
|
||||
enum TransError
|
||||
{
|
||||
Trans_Okay = 0,
|
||||
Trans_BadLanguage = 1,
|
||||
Trans_BadPhrase = 2,
|
||||
Trans_BadPhraseLanguage = 3,
|
||||
Trans_BadPhraseFile = 4,
|
||||
};
|
||||
|
||||
class CPhraseFile : public ITextListener_SMC
|
||||
class CPhraseFile :
|
||||
public ITextListener_SMC,
|
||||
public IPhraseFile
|
||||
{
|
||||
public:
|
||||
CPhraseFile(Translator *pTranslator, const char *file);
|
||||
@@ -112,7 +97,8 @@ private:
|
||||
|
||||
class Translator :
|
||||
public ITextListener_SMC,
|
||||
public SMGlobalClass
|
||||
public SMGlobalClass,
|
||||
public ITranslator
|
||||
{
|
||||
public:
|
||||
Translator();
|
||||
@@ -125,6 +111,7 @@ public: // SMGlobalClass
|
||||
size_t maxlength);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
void OnSourceModShutdown();
|
||||
public: // ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
@@ -138,23 +125,30 @@ public:
|
||||
bool GetLanguageInfo(unsigned int number, const char **code, const char **name);
|
||||
bool GetLanguageByCode(const char *code, unsigned int *index);
|
||||
bool GetLanguageByName(const char *name, unsigned int *index);
|
||||
size_t Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans);
|
||||
CPhraseFile *GetFileByIndex(unsigned int index);
|
||||
TransError CoreTransEx(CPhraseFile *pFile,
|
||||
int client,
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
const char *phrase,
|
||||
void **params,
|
||||
size_t *outlen=NULL);
|
||||
TransError CoreTrans(int client,
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
const char *phrase,
|
||||
void **params,
|
||||
size_t *outlen=NULL);
|
||||
public: //ITranslator
|
||||
unsigned int GetServerLanguage();
|
||||
unsigned int GetClientLanguage(int client);
|
||||
const char *GetInterfaceName();
|
||||
unsigned int GetInterfaceVersion();
|
||||
IPhraseCollection *CreatePhraseCollection();
|
||||
int SetGlobalTarget(int index);
|
||||
int GetGlobalTarget() const;
|
||||
size_t FormatString(
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
SourcePawn::IPluginContext *pContext,
|
||||
const cell_t *params,
|
||||
unsigned int param);
|
||||
bool FormatString(
|
||||
char *buffer,
|
||||
size_t maxlength,
|
||||
const char *format,
|
||||
IPhraseCollection *pPhrases,
|
||||
void **params,
|
||||
unsigned int numparams,
|
||||
size_t *pOutLength,
|
||||
const char **pFailPhrase);
|
||||
private:
|
||||
bool AddLanguage(const char *langcode, const char *description);
|
||||
private:
|
||||
@@ -165,10 +159,18 @@ private:
|
||||
bool m_InLanguageSection;
|
||||
String m_CustomError;
|
||||
unsigned int m_ServerLang;
|
||||
char m_InitialLang[3];
|
||||
char m_InitialLang[4];
|
||||
};
|
||||
|
||||
extern CPhraseFile *g_pCorePhrases;
|
||||
/* Nice little wrapper to handle error logging and whatnot */
|
||||
bool CoreTranslate(char *buffer,
|
||||
size_t maxlength,
|
||||
const char *format,
|
||||
unsigned int numparams,
|
||||
size_t *pOutLength,
|
||||
...);
|
||||
|
||||
extern IPhraseCollection *g_pCorePhrases;
|
||||
extern unsigned int g_pCorePhraseID;
|
||||
extern Translator g_Translator;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
|
||||
+63
-3
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -35,15 +35,75 @@
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include "MenuStyle_Radio.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "CoreConfig.h"
|
||||
#include <sm_queue.h>
|
||||
#include "ThreadSupport.h"
|
||||
|
||||
float g_LastMenuTime = 0.0f;
|
||||
float g_LastAuthCheck = 0.0f;
|
||||
static IMutex *frame_mutex;
|
||||
static Queue<FrameAction> *frame_queue;
|
||||
static Queue<FrameAction> *frame_actions;
|
||||
static float g_LastMenuTime = 0.0f;
|
||||
static float g_LastAuthCheck = 0.0f;
|
||||
bool g_PendingInternalPush = false;
|
||||
|
||||
class FrameActionInit : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
void OnSourceModAllInitialized()
|
||||
{
|
||||
frame_queue = new Queue<FrameAction>();
|
||||
frame_actions = new Queue<FrameAction>();
|
||||
frame_mutex = g_pThreader->MakeMutex();
|
||||
}
|
||||
|
||||
void OnSourceModShutdown()
|
||||
{
|
||||
delete frame_queue;
|
||||
delete frame_actions;
|
||||
frame_mutex->DestroyThis();
|
||||
}
|
||||
} s_FrameActionInit;
|
||||
|
||||
void AddFrameAction(const FrameAction & action)
|
||||
{
|
||||
frame_mutex->Lock();
|
||||
frame_queue->push(action);
|
||||
frame_mutex->Unlock();
|
||||
}
|
||||
|
||||
void RunFrameHooks(bool simulating)
|
||||
{
|
||||
/* It's okay if this check races. */
|
||||
if (frame_queue->size())
|
||||
{
|
||||
Queue<FrameAction> *temp;
|
||||
|
||||
/* Very quick lock to move queue/actions back and forth */
|
||||
frame_mutex->Lock();
|
||||
temp = frame_queue;
|
||||
frame_queue = frame_actions;
|
||||
frame_actions = temp;
|
||||
frame_mutex->Unlock();
|
||||
|
||||
/* The server will now be adding to the other queue, so we can process events. */
|
||||
while (!frame_actions->empty())
|
||||
{
|
||||
FrameAction &item = frame_actions->first();
|
||||
frame_actions->pop();
|
||||
item.action(item.data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Frame based hooks */
|
||||
g_DBMan.RunFrame();
|
||||
g_HL2.ProcessFakeCliCmdQueue();
|
||||
g_HL2.ProcessDelayedKicks();
|
||||
|
||||
if (g_PendingInternalPush)
|
||||
{
|
||||
SM_InternalCmdTrigger();
|
||||
}
|
||||
|
||||
g_SourceMod.ProcessGameFrameHooks(simulating);
|
||||
|
||||
float curtime = *g_pUniversalTime;
|
||||
|
||||
+12
-1
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -32,6 +32,17 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
|
||||
#define _INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
|
||||
|
||||
typedef void (*FRAMEACTION)(void *data);
|
||||
|
||||
struct FrameAction
|
||||
{
|
||||
void *data;
|
||||
FRAMEACTION action;
|
||||
};
|
||||
|
||||
extern bool g_PendingInternalPush;
|
||||
|
||||
void AddFrameAction(const FrameAction & action);
|
||||
void RunFrameHooks(bool simulating);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
|
||||
|
||||
+476
@@ -0,0 +1,476 @@
|
||||
// MD5.CC - source code for the C++/object oriented translation and
|
||||
// modification of MD5.
|
||||
|
||||
// Translation and modification (c) 1995 by Mordechai T. Abzug
|
||||
|
||||
// This translation/ modification is provided "as is," without express or
|
||||
// implied warranty of any kind.
|
||||
|
||||
// The translator/ modifier does not claim (1) that MD5 will do what you think
|
||||
// it does; (2) that this translation/ modification is accurate; or (3) that
|
||||
// this software is "merchantible." (Language for this disclaimer partially
|
||||
// copied from the disclaimer below).
|
||||
|
||||
/* based on:
|
||||
|
||||
MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
||||
MDDRIVER.C - test driver for MD2, MD4 and MD5
|
||||
|
||||
|
||||
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
|
||||
*/
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
// MD5 simple initialization method
|
||||
|
||||
MD5::MD5(){
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MD5 block update operation. Continues an MD5 message-digest
|
||||
// operation, processing another message block, and updating the
|
||||
// context.
|
||||
|
||||
void MD5::update (uint1 *input, uint4 input_length) {
|
||||
|
||||
uint4 input_index, buffer_index;
|
||||
uint4 buffer_space; // how much space is left in buffer
|
||||
|
||||
if (finalized){ // so we can't update!
|
||||
/*cerr << "MD5::update: Can't update a finalized digest!" << endl;*/
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute number of bytes mod 64
|
||||
buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
|
||||
|
||||
// Update number of bits
|
||||
if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
|
||||
count[1]++;
|
||||
|
||||
count[1] += ((uint4)input_length >> 29);
|
||||
|
||||
|
||||
buffer_space = 64 - buffer_index; // how much space is left in buffer
|
||||
|
||||
// Transform as many times as possible.
|
||||
if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
|
||||
// fill the rest of the buffer and transform
|
||||
memcpy (buffer + buffer_index, input, buffer_space);
|
||||
transform (buffer);
|
||||
|
||||
// now, transform each 64-byte piece of the input, bypassing the buffer
|
||||
for (input_index = buffer_space; input_index + 63 < input_length;
|
||||
input_index += 64)
|
||||
transform (input+input_index);
|
||||
|
||||
buffer_index = 0; // so we can buffer remaining
|
||||
}
|
||||
else
|
||||
input_index=0; // so we can buffer the whole input
|
||||
|
||||
|
||||
// and here we do the buffering:
|
||||
memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MD5 update for files.
|
||||
// Like above, except that it works on files (and uses above as a primitive.)
|
||||
|
||||
void MD5::update(FILE *file){
|
||||
|
||||
unsigned char buffer[1024];
|
||||
int len;
|
||||
|
||||
while ((len=fread(buffer, 1, 1024, file)))
|
||||
update(buffer, len);
|
||||
|
||||
fclose (file);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
// the message digest and zeroizing the context.
|
||||
|
||||
|
||||
void MD5::finalize (){
|
||||
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
static uint1 PADDING[64]={
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
if (finalized){
|
||||
/* cerr << "MD5::finalize: Already finalized this digest!" << endl;*/
|
||||
return;
|
||||
}
|
||||
|
||||
// Save number of bits
|
||||
encode (bits, count, 8);
|
||||
|
||||
// Pad out to 56 mod 64.
|
||||
index = (uint4) ((count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
update (PADDING, padLen);
|
||||
|
||||
// Append length (before padding)
|
||||
update (bits, 8);
|
||||
|
||||
// Store state in digest
|
||||
encode (digest, state, 16);
|
||||
|
||||
// Zeroize sensitive information
|
||||
memset (buffer, 0, sizeof(*buffer));
|
||||
|
||||
finalized=1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
MD5::MD5(FILE *file){
|
||||
|
||||
init(); // must be called be all constructors
|
||||
update(file);
|
||||
finalize ();
|
||||
}
|
||||
|
||||
unsigned char *MD5::raw_digest(){
|
||||
|
||||
uint1 *s = new uint1[16];
|
||||
|
||||
if (!finalized){
|
||||
/* cerr << "MD5::raw_digest: Can't get digest if you haven't "<<
|
||||
"finalized the digest!" <<endl;*/
|
||||
return ( (unsigned char*) "");
|
||||
}
|
||||
|
||||
memcpy(s, digest, 16);
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned char *MD5::raw_digest(unsigned char buffer[16])
|
||||
{
|
||||
if (!finalized)
|
||||
{
|
||||
return ( (unsigned char*) "");
|
||||
}
|
||||
|
||||
memcpy(buffer, digest, 16);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *MD5::hex_digest(){
|
||||
|
||||
int i;
|
||||
char *s= new char[33];
|
||||
|
||||
assert(finalized);
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
sprintf(s+i*2, "%02x", digest[i]);
|
||||
|
||||
s[32]='\0';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
char *MD5::hex_digest(char buffer[33]){
|
||||
|
||||
int i;
|
||||
|
||||
assert(finalized);
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
sprintf(buffer+i*2, "%02x", digest[i]);
|
||||
|
||||
buffer[32]='\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// PRIVATE METHODS:
|
||||
|
||||
|
||||
|
||||
void MD5::init(){
|
||||
finalized=0; // we just started!
|
||||
|
||||
// Nothing counted, so count=0
|
||||
count[0] = 0;
|
||||
count[1] = 0;
|
||||
|
||||
// Load magic initialization constants.
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Constants for MD5Transform routine.
|
||||
// Although we could use C++ style constants, defines are actually better,
|
||||
// since they let us easily evade scope clashes.
|
||||
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
|
||||
|
||||
|
||||
// MD5 basic transformation. Transforms state based on block.
|
||||
void MD5::transform (uint1 block[64]){
|
||||
|
||||
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
decode (x, block, 64);
|
||||
|
||||
assert(!finalized); // not just a user error, since the method is private
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
// Zeroize sensitive information.
|
||||
memset ( (uint1 *) x, 0, sizeof(x));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
// a multiple of 4.
|
||||
void MD5::encode (uint1 *output, uint4 *input, uint4 len) {
|
||||
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (uint1) (input[i] & 0xff);
|
||||
output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
// a multiple of 4.
|
||||
void MD5::decode (uint4 *output, uint1 *input, uint4 len){
|
||||
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
|
||||
(((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Note: Replace "for loop" with standard memcpy if possible.
|
||||
void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){
|
||||
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Note: Replace "for loop" with standard memset if possible.
|
||||
void MD5::memset (uint1 *output, uint1 value, uint4 len){
|
||||
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ROTATE_LEFT rotates x left n bits.
|
||||
|
||||
inline unsigned int MD5::rotate_left (uint4 x, uint4 n){
|
||||
return (x << n) | (x >> (32-n)) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// F, G, H and I are basic MD5 functions.
|
||||
|
||||
inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){
|
||||
return (x & y) | (~x & z);
|
||||
}
|
||||
|
||||
inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){
|
||||
return (x & z) | (y & ~z);
|
||||
}
|
||||
|
||||
inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){
|
||||
return x ^ y ^ z;
|
||||
}
|
||||
|
||||
inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){
|
||||
return y ^ (x | ~z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
// Rotation is separate from addition to prevent recomputation.
|
||||
|
||||
|
||||
inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac){
|
||||
a += F(b, c, d) + x + ac;
|
||||
a = rotate_left (a, s) +b;
|
||||
}
|
||||
|
||||
inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac){
|
||||
a += G(b, c, d) + x + ac;
|
||||
a = rotate_left (a, s) +b;
|
||||
}
|
||||
|
||||
inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac){
|
||||
a += H(b, c, d) + x + ac;
|
||||
a = rotate_left (a, s) +b;
|
||||
}
|
||||
|
||||
inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac){
|
||||
a += I(b, c, d) + x + ac;
|
||||
a = rotate_left (a, s) +b;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
// MD5.CC - source code for the C++/object oriented translation and
|
||||
// modification of MD5.
|
||||
|
||||
// Translation and modification (c) 1995 by Mordechai T. Abzug
|
||||
|
||||
// This translation/ modification is provided "as is," without express or
|
||||
// implied warranty of any kind.
|
||||
|
||||
// The translator/ modifier does not claim (1) that MD5 will do what you think
|
||||
// it does; (2) that this translation/ modification is accurate; or (3) that
|
||||
// this software is "merchantible." (Language for this disclaimer partially
|
||||
// copied from the disclaimer below).
|
||||
|
||||
/* based on:
|
||||
|
||||
MD5.H - header file for MD5C.C
|
||||
MDDRIVER.C - test driver for MD2, MD4 and MD5
|
||||
|
||||
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
//#include <fstream.h>
|
||||
//#include <iostream.h>
|
||||
|
||||
class MD5 {
|
||||
|
||||
public:
|
||||
// methods for controlled operation:
|
||||
MD5 (); // simple initializer
|
||||
void update (unsigned char *input, unsigned int input_length);
|
||||
void update (FILE *file);
|
||||
void finalize ();
|
||||
|
||||
// constructors for special circumstances. All these constructors finalize
|
||||
// the MD5 context.
|
||||
MD5 (unsigned char *string); // digest string, finalize
|
||||
MD5 (FILE *file); // digest file, close, finalize
|
||||
|
||||
// methods to acquire finalized result
|
||||
unsigned char *raw_digest (); // digest as a 16-byte binary array
|
||||
unsigned char *raw_digest(unsigned char buffer[16]);
|
||||
char * hex_digest (); // digest as a 33-byte ascii-hex string
|
||||
char * hex_digest (char buffer[33]); //same as above, passing buffer
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// first, some types:
|
||||
typedef unsigned int uint4; // assumes integer is 4 words long
|
||||
typedef unsigned short int uint2; // assumes short integer is 2 words long
|
||||
typedef unsigned char uint1; // assumes char is 1 word long
|
||||
|
||||
// next, the private data:
|
||||
uint4 state[4];
|
||||
uint4 count[2]; // number of *bits*, mod 2^64
|
||||
uint1 buffer[64]; // input buffer
|
||||
uint1 digest[16];
|
||||
uint1 finalized;
|
||||
|
||||
// last, the private methods, mostly static:
|
||||
void init (); // called by all constructors
|
||||
void transform (uint1 *buffer); // does the real update work. Note
|
||||
// that length is implied to be 64.
|
||||
|
||||
static void encode (uint1 *dest, uint4 *src, uint4 length);
|
||||
static void decode (uint4 *dest, uint1 *src, uint4 length);
|
||||
static void memcpy (uint1 *dest, uint1 *src, uint4 length);
|
||||
static void memset (uint1 *start, uint1 val, uint4 length);
|
||||
|
||||
static inline uint4 rotate_left (uint4 x, uint4 n);
|
||||
static inline uint4 F (uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 G (uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 H (uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 I (uint4 x, uint4 y, uint4 z);
|
||||
static inline void FF (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac);
|
||||
static inline void GG (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac);
|
||||
static inline void HH (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac);
|
||||
static inline void II (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
|
||||
uint4 s, uint4 ac);
|
||||
|
||||
};
|
||||
@@ -5,35 +5,35 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sourcemod_mm", "sourcemod_m
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CrazyDebug|Win32 = CrazyDebug|Win32
|
||||
CrazyDebug - Episode 1|Win32 = CrazyDebug - Episode 1|Win32
|
||||
CrazyDebug - Old Metamod|Win32 = CrazyDebug - Old Metamod|Win32
|
||||
CrazyDebug - Orange Box|Win32 = CrazyDebug - Orange Box|Win32
|
||||
Debug - Episode 1|Win32 = Debug - Episode 1|Win32
|
||||
Debug - Old Metamod|Win32 = Debug - Old Metamod|Win32
|
||||
Debug - Orange Box|Win32 = Debug - Orange Box|Win32
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release - Episode 1|Win32 = Release - Episode 1|Win32
|
||||
Release - Old Metamod|Win32 = Release - Old Metamod|Win32
|
||||
Release - Orange Box|Win32 = Release - Orange Box|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug|Win32.ActiveCfg = CrazyDebug|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug|Win32.Build.0 = CrazyDebug|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug - Episode 1|Win32.ActiveCfg = CrazyDebug - Episode 1|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug - Episode 1|Win32.Build.0 = CrazyDebug - Episode 1|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug - Old Metamod|Win32.ActiveCfg = CrazyDebug - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug - Old Metamod|Win32.Build.0 = CrazyDebug - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug - Orange Box|Win32.ActiveCfg = CrazyDebug - Orange Box|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.CrazyDebug - Orange Box|Win32.Build.0 = CrazyDebug - Orange Box|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug - Episode 1|Win32.ActiveCfg = Debug - Episode 1|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug - Episode 1|Win32.Build.0 = Debug - Episode 1|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug - Old Metamod|Win32.ActiveCfg = Debug - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug - Old Metamod|Win32.Build.0 = Debug - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug - Orange Box|Win32.ActiveCfg = Debug - Orange Box|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug - Orange Box|Win32.Build.0 = Debug - Orange Box|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug|Win32.ActiveCfg = CrazyDebug|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Debug|Win32.Build.0 = CrazyDebug|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release - Episode 1|Win32.ActiveCfg = Release - Episode 1|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release - Episode 1|Win32.Build.0 = Release - Episode 1|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release - Old Metamod|Win32.ActiveCfg = Release - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release - Old Metamod|Win32.Build.0 = Release - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release - Orange Box|Win32.ActiveCfg = Release - Orange Box|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release - Orange Box|Win32.Build.0 = Release - Orange Box|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release|Win32.ActiveCfg = Debug - Old Metamod|Win32
|
||||
{E39527CD-7CAB-4420-97CC-DA1B93B260BC}.Release|Win32.Build.0 = Debug - Old Metamod|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
+672
-650
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user