Compare commits
2020
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b635dace11 | ||
|
|
d990f956f9 | ||
|
|
955f1e0d3a | ||
|
|
b4cd559186 | ||
|
|
46e89891e1 | ||
|
|
080e2563c3 | ||
|
|
e1e0c33f2c | ||
|
|
0160d3cc71 | ||
|
|
81f0d82c67 | ||
|
|
b5276b435a | ||
|
|
16aecfb404 | ||
|
|
7054ef56f6 | ||
|
|
bfae78d1ec | ||
|
|
c82f2b4659 | ||
|
|
46d71790be | ||
|
|
647811f930 | ||
|
|
7ca80d1c7c | ||
|
|
8823bab3f3 | ||
|
|
b9d5b59bd1 | ||
|
|
7fc892d38b | ||
|
|
09040231a0 | ||
|
|
16541a5668 | ||
|
|
e1b3b14311 | ||
|
|
300632db86 | ||
|
|
d1776dd641 | ||
|
|
22cee6a2dd | ||
|
|
a2194df273 | ||
|
|
27e20996dd | ||
|
|
b5f16142e5 | ||
|
|
23f1f9e148 | ||
|
|
990f99af5a | ||
|
|
6ca9d86e8f | ||
|
|
fae8b4d49a | ||
|
|
7f2d9dd8eb | ||
|
|
8ae1b3e1e7 | ||
|
|
c77c853c02 | ||
|
|
2b0daba573 | ||
|
|
ba4aa4d37f | ||
|
|
e3f31af5d3 | ||
|
|
bc0bf4e270 | ||
|
|
60c5ad6324 | ||
|
|
e996a00675 | ||
|
|
0be3f0afed | ||
|
|
86bdfa2205 | ||
|
|
56c87e927f | ||
|
|
be54443918 | ||
|
|
676ea8b29c | ||
|
|
d77ff38428 | ||
|
|
d3256ef339 | ||
|
|
3d11742f91 | ||
|
|
a2aa5d1cda | ||
|
|
8860e18026 | ||
|
|
7dba540b97 | ||
|
|
0dd9a5b842 | ||
|
|
e6c3565544 | ||
|
|
8cacba922a | ||
|
|
767396d4ee | ||
|
|
07a51a0d4e | ||
|
|
9f042625d0 | ||
|
|
fc29f4249a | ||
|
|
5ca5ecee85 | ||
|
|
c79d547492 | ||
|
|
f079773195 | ||
|
|
e6ead8b5aa | ||
|
|
9eba6402eb | ||
|
|
f95be3b10c | ||
|
|
2220cc961e | ||
|
|
cfc6b2fee9 | ||
|
|
d188859fc5 | ||
|
|
96a8003448 | ||
|
|
696f702204 | ||
|
|
8b26ce73c2 | ||
|
|
ee5f488aa2 | ||
|
|
3a5cf80e2b | ||
|
|
3e4f7af96a | ||
|
|
a1a483fa27 | ||
|
|
b32f8a4803 | ||
|
|
96ee6dbf8a | ||
|
|
ac07cf95e1 | ||
|
|
8f51e33167 | ||
|
|
8366f371ad | ||
|
|
9b44dfea11 | ||
|
|
7ede8e0924 | ||
|
|
9fe2d9c1cf | ||
|
|
1836ec9d45 | ||
|
|
380d7adc09 | ||
|
|
4109d0df39 | ||
|
|
9cab1e3ab7 | ||
|
|
e9d8bfcdfc | ||
|
|
f134602991 | ||
|
|
b493532ee1 | ||
|
|
84dec75fb8 | ||
|
|
b1094f87c6 | ||
|
|
284b4bfe20 | ||
|
|
b46537ddd5 | ||
|
|
c9446c4d7d | ||
|
|
d4610ab340 | ||
|
|
0016b8ef2f | ||
|
|
72e08f7e44 | ||
|
|
b06cfa5414 | ||
|
|
a7742cae3d | ||
|
|
8a78285659 | ||
|
|
6847c8eec0 | ||
|
|
66790254ac | ||
|
|
86b8a0b16a | ||
|
|
25fced78e8 | ||
|
|
22d11160ba | ||
|
|
8d65b3e94e | ||
|
|
5518544ecd | ||
|
|
af3523bd2d | ||
|
|
8646cca538 | ||
|
|
c7cea1b40b | ||
|
|
58914f71bd | ||
|
|
3841e98c4f | ||
|
|
acd025dba2 | ||
|
|
78c2206628 | ||
|
|
5c47bf8803 | ||
|
|
8e78ee6f57 | ||
|
|
a2da4cc868 | ||
|
|
00e44ad3c3 | ||
|
|
29ba84fc5c | ||
|
|
283f1f012d | ||
|
|
fff17f8043 | ||
|
|
847eaf38f9 | ||
|
|
1d59a329eb | ||
|
|
5689888682 | ||
|
|
a01768525a | ||
|
|
e3d2ddf278 | ||
|
|
b3e48b0ad7 | ||
|
|
6d528b5c55 | ||
|
|
22daf26e3e | ||
|
|
73061969da | ||
|
|
4653530095 | ||
|
|
ef5faaaa4a | ||
|
|
f52ea98eb4 | ||
|
|
d315d4bf53 | ||
|
|
eaef2a46fb | ||
|
|
b0304a89a6 | ||
|
|
a4790f0358 | ||
|
|
d3d5cd8181 | ||
|
|
64be2bc5a0 | ||
|
|
30e476c35e | ||
|
|
88af208cdd | ||
|
|
b64751c1af | ||
|
|
2e158a72e2 | ||
|
|
c8fb05dd4b | ||
|
|
860af1e6cb | ||
|
|
5c1cadb64e | ||
|
|
bfb97a4207 | ||
|
|
7e26691b99 | ||
|
|
ca469a218a | ||
|
|
6052ddaa64 | ||
|
|
0ddc675472 | ||
|
|
9412f687cb | ||
|
|
0e865c0618 | ||
|
|
462b5213d7 | ||
|
|
f52e84730f | ||
|
|
b8873efa0d | ||
|
|
4132b9bd21 | ||
|
|
c0caa9f158 | ||
|
|
7346b0c081 | ||
|
|
6a361e3045 | ||
|
|
61d7519ef5 | ||
|
|
3e1a78703e | ||
|
|
bb195a9b2d | ||
|
|
6f095a064c | ||
|
|
eb334f5fe2 | ||
|
|
ef825d8a94 | ||
|
|
6775898712 | ||
|
|
d3dd82f190 | ||
|
|
95409f7ec7 | ||
|
|
1141a73945 | ||
|
|
176c003658 | ||
|
|
74aafaa72f | ||
|
|
0ac7867b3d | ||
|
|
c1b65f52be | ||
|
|
1d242ee161 | ||
|
|
230e4e3a32 | ||
|
|
7ff4724e28 | ||
|
|
0015d00243 | ||
|
|
5ca8967375 | ||
|
|
4e0c1f97ac | ||
|
|
191c3dabdb | ||
|
|
cd9a28864a | ||
|
|
c2ecb7363c | ||
|
|
e20e272ee1 | ||
|
|
8dc7f78b0f | ||
|
|
c4331c4795 | ||
|
|
d071ecc17c | ||
|
|
7c03276b50 | ||
|
|
ee8b180341 | ||
|
|
5258a1dc85 | ||
|
|
e74d5593a8 | ||
|
|
18285ca751 | ||
|
|
764a04a201 | ||
|
|
1e5a375203 | ||
|
|
3a2504dc18 | ||
|
|
7bc4c10660 | ||
|
|
0fcfead475 | ||
|
|
ab9c1217e4 | ||
|
|
e9f002e9c5 | ||
|
|
a9b6bcf779 | ||
|
|
52e427117c | ||
|
|
312e26a5cf | ||
|
|
f757d5f09b | ||
|
|
a66adcbc88 | ||
|
|
f4f930e8bd | ||
|
|
5200940f2f | ||
|
|
63f8262a57 | ||
|
|
bb9d5e11f1 | ||
|
|
df76b7285c | ||
|
|
e105711678 | ||
|
|
b206858c67 | ||
|
|
bc1b803093 | ||
|
|
6e54e0f6e4 | ||
|
|
e0d2287973 | ||
|
|
7f26803dee | ||
|
|
22cbe23f85 | ||
|
|
8f0c442024 | ||
|
|
02b8e3f7c0 | ||
|
|
7846ff1666 | ||
|
|
3e1e20dbe2 | ||
|
|
eaf441c226 | ||
|
|
942b1d2591 | ||
|
|
710456f871 | ||
|
|
59df217a09 | ||
|
|
ffd7603b17 | ||
|
|
329616c029 | ||
|
|
8723a69a8f | ||
|
|
edddca4857 | ||
|
|
536123ec59 | ||
|
|
db699ed2c3 | ||
|
|
bf9c58b8ed | ||
|
|
8eeec3dc48 | ||
|
|
4a1dd5f519 | ||
|
|
5256edf0e5 | ||
|
|
e9385e6eb6 | ||
|
|
80f7e3092b | ||
|
|
ab06cf4788 | ||
|
|
c2300f7b2b | ||
|
|
ba2915ce4e | ||
|
|
c0b91dd107 | ||
|
|
439986e3fe | ||
|
|
e77ad244ad | ||
|
|
2e3c5e367e | ||
|
|
eb230a45f6 | ||
|
|
5aacf886e1 | ||
|
|
0cae86e2ad | ||
|
|
e7f0a005e2 | ||
|
|
b3c506c69e | ||
|
|
99f741fb3b | ||
|
|
52aa0a5b27 | ||
|
|
b7ac61cbea | ||
|
|
2896e7bd4b | ||
|
|
8a10f4b7a2 | ||
|
|
7619d0d7ff | ||
|
|
2175357e72 | ||
|
|
bd9f126973 | ||
|
|
4260a5b3df | ||
|
|
247fabaaf0 | ||
|
|
a991d327e6 | ||
|
|
c19712dccc | ||
|
|
7d67e851c9 | ||
|
|
7492ee5d2e | ||
|
|
7ea6080689 | ||
|
|
272dbf94e0 | ||
|
|
d96f7ae4ae | ||
|
|
20d4597fa0 | ||
|
|
c5947e2dd7 | ||
|
|
544bd7d4cc | ||
|
|
d1c1cb5f7c | ||
|
|
a1165183c2 | ||
|
|
07520fb26e | ||
|
|
46393d63af | ||
|
|
ccc067a1c6 | ||
|
|
0cd954749c | ||
|
|
916f60b59b | ||
|
|
115d17de01 | ||
|
|
8dfae523a3 | ||
|
|
0532135dc3 | ||
|
|
b28c6d6e4a | ||
|
|
f703b285bb | ||
|
|
749b9dd1bb | ||
|
|
42ff151ae4 | ||
|
|
5ec6f851c9 | ||
|
|
89be7adc80 | ||
|
|
39f9702db4 | ||
|
|
021c390091 | ||
|
|
cec1d4a28b | ||
|
|
38969dde2f | ||
|
|
3061ef9d4c | ||
|
|
e55b7fa70f | ||
|
|
79d04c2d24 | ||
|
|
d11be6fcf4 | ||
|
|
bed417dc62 | ||
|
|
7625ca439e | ||
|
|
6ff5733d7b | ||
|
|
a3117ef272 | ||
|
|
2fdbedfe95 | ||
|
|
5567484a8e | ||
|
|
d79c5bd1dc | ||
|
|
34d2db6d78 | ||
|
|
eceb9008cd | ||
|
|
731245773a | ||
|
|
d4a80ab3d0 | ||
|
|
ce709298cc | ||
|
|
6ab7a6678c | ||
|
|
f62283b595 | ||
|
|
e8058912b8 | ||
|
|
4f800fbd00 | ||
|
|
e367d456e1 | ||
|
|
3025b9b5e0 | ||
|
|
b0075842d1 | ||
|
|
0a10d6022f | ||
|
|
a634da2c0a | ||
|
|
94f0fc58cc | ||
|
|
bf76be5dfa | ||
|
|
a62aeb36d8 | ||
|
|
0d795fc651 | ||
|
|
7441af67a8 | ||
|
|
9077686998 | ||
|
|
d88f07fd31 | ||
|
|
805306bdf0 | ||
|
|
da53fdb50c | ||
|
|
549e5a85cb | ||
|
|
cd75c56ac4 | ||
|
|
82883d8187 | ||
|
|
74f49ec38f | ||
|
|
cb3411481d | ||
|
|
3aad0dff2e | ||
|
|
0510723ac1 | ||
|
|
294a120f14 | ||
|
|
e6313c89bc | ||
|
|
8362b8d226 | ||
|
|
7675472b41 | ||
|
|
c07f84911c | ||
|
|
6f18a50945 | ||
|
|
d5c9ce9125 | ||
|
|
3b4ac1c64d | ||
|
|
717b4ce4fa | ||
|
|
6efc6074cc | ||
|
|
76fa100c1d | ||
|
|
981171f42a | ||
|
|
33ef2ff5c9 | ||
|
|
380d0b9623 | ||
|
|
de27cb8a2f | ||
|
|
ac6c162a13 | ||
|
|
a8021e0d79 | ||
|
|
b52f696d49 | ||
|
|
983e37a0be | ||
|
|
f1e01a3cf6 | ||
|
|
858c3f653c | ||
|
|
4618588494 | ||
|
|
cd3c3fffde | ||
|
|
148b5ea376 | ||
|
|
6f9c197400 | ||
|
|
67ae85b840 | ||
|
|
0f6e8dd311 | ||
|
|
cb86d4d967 | ||
|
|
80fbc25442 | ||
|
|
c1f9fb6c3a | ||
|
|
a46dcd45d7 | ||
|
|
99ff1179cc | ||
|
|
4871dbaaa1 | ||
|
|
832dc259af | ||
|
|
78f4640736 | ||
|
|
0b7831c6df | ||
|
|
73a701f08c | ||
|
|
080405c022 | ||
|
|
58ae7f1cab | ||
|
|
59b1bd3d96 | ||
|
|
4d4979cc98 | ||
|
|
542c515bc1 | ||
|
|
3479e452de | ||
|
|
49ad25d001 | ||
|
|
13c8336c82 | ||
|
|
601186fd6a | ||
|
|
dfadfe37f6 | ||
|
|
b3372ebba2 | ||
|
|
01de453d25 | ||
|
|
64b6c0d0eb | ||
|
|
2f684e0255 | ||
|
|
3a77fcd005 | ||
|
|
06492d18a7 | ||
|
|
0297e974d4 | ||
|
|
354279bc1e | ||
|
|
e0278071cf | ||
|
|
a9bd1ced2e | ||
|
|
8cd397e56f | ||
|
|
7423fd9c98 | ||
|
|
cd75262ad1 | ||
|
|
70f91f8345 | ||
|
|
61a28c290b | ||
|
|
40c2674d49 | ||
|
|
b3d38bd4f1 | ||
|
|
7e199b0c7c | ||
|
|
6af30e8992 | ||
|
|
e7c86713c8 | ||
|
|
7cd480a1a9 | ||
|
|
3f249c2e93 | ||
|
|
36f5200abc | ||
|
|
89325f9995 | ||
|
|
83b3c3ab8f | ||
|
|
02277225d7 | ||
|
|
6f55c3e75a | ||
|
|
56131fd63a | ||
|
|
f65de3bbbb | ||
|
|
44d9551bd6 | ||
|
|
1aab29a958 | ||
|
|
0439d08689 | ||
|
|
618eb254c0 | ||
|
|
e2340363e3 | ||
|
|
a68125a5ee | ||
|
|
3d25938dd7 | ||
|
|
70994cb4b2 | ||
|
|
0d5ef132f3 | ||
|
|
5610aeb917 | ||
|
|
02f8991fb3 | ||
|
|
f53255570d | ||
|
|
543f3440dc | ||
|
|
1a8417951f | ||
|
|
2f68781ff9 | ||
|
|
d29e546678 | ||
|
|
a39943d57d | ||
|
|
c20ac116a8 | ||
|
|
c8f5ef8afb | ||
|
|
1ebef323de | ||
|
|
3b18745bcd | ||
|
|
236579a930 | ||
|
|
9b49b2694d | ||
|
|
62336b60b2 | ||
|
|
917b6d4521 | ||
|
|
fdec003973 | ||
|
|
55b4854cd4 | ||
|
|
6aca18193a | ||
|
|
745b2f0668 | ||
|
|
2b207359f9 | ||
|
|
6121c098c8 | ||
|
|
c15a91dbcc | ||
|
|
f46c58deaa | ||
|
|
c9b7e9f9aa | ||
|
|
6a8c99eef1 | ||
|
|
7025e07e8a | ||
|
|
2ba12008c8 | ||
|
|
ac2bbf16f6 | ||
|
|
d77ebd60cf | ||
|
|
997c7ebbcf | ||
|
|
afe5425163 | ||
|
|
32eadc0ea3 | ||
|
|
e75b244cae | ||
|
|
bb448905ac | ||
|
|
6928ce9cd3 | ||
|
|
b7394ad02e | ||
|
|
eca39b1a51 | ||
|
|
f66e63c690 | ||
|
|
42c2fc61b8 | ||
|
|
24303a5365 | ||
|
|
0ecae8a844 | ||
|
|
9e45f2da9f | ||
|
|
d676886dee | ||
|
|
2d0a0b5a62 | ||
|
|
6fe32b3b49 | ||
|
|
525145f2a3 | ||
|
|
2b8038d700 | ||
|
|
2454c0baae | ||
|
|
0189c5b990 | ||
|
|
c70285dcfc | ||
|
|
f5a392e189 | ||
|
|
cd729f054c | ||
|
|
5f551fa67a | ||
|
|
1e57376cc7 | ||
|
|
4771398e1e | ||
|
|
ee49dfa505 | ||
|
|
20d1551216 | ||
|
|
a3593a5124 | ||
|
|
c7646976fb | ||
|
|
8a10cc982c | ||
|
|
74e546e145 | ||
|
|
5586f7c517 | ||
|
|
fbeeaa4c1e | ||
|
|
48738bbae9 | ||
|
|
7f74948e91 | ||
|
|
a31bb79b78 | ||
|
|
821fcd5be4 | ||
|
|
0c75229250 | ||
|
|
5f67a600fc | ||
|
|
4669c320f6 | ||
|
|
545868da38 | ||
|
|
e154f3edb7 | ||
|
|
393c54fdc2 | ||
|
|
02981cec57 | ||
|
|
6e499c8213 | ||
|
|
9ca1ced6a2 | ||
|
|
6470222a06 | ||
|
|
eedf8b845c | ||
|
|
01c94596a4 | ||
|
|
978d7c0fca | ||
|
|
3bd53b4f61 | ||
|
|
8d9c325000 | ||
|
|
dfe8ae4fd1 | ||
|
|
069d67b24b | ||
|
|
0c926b84bc | ||
|
|
11bdd68d73 | ||
|
|
1beeaf3d4f | ||
|
|
8cc850de97 | ||
|
|
0931794f10 | ||
|
|
3b12883a1b | ||
|
|
e18faf085f | ||
|
|
a98edd42d1 | ||
|
|
c1aa49ef3a | ||
|
|
49a860bc9e | ||
|
|
1b94a30c9f | ||
|
|
5a52fc3657 | ||
|
|
df7680aa73 | ||
|
|
f42a16643c | ||
|
|
96e5dc3fc6 | ||
|
|
6c0eca0eca | ||
|
|
fefff70645 | ||
|
|
18fa18f612 | ||
|
|
b2311e2ea5 | ||
|
|
ee42f09b8d | ||
|
|
e7f5f4a6af | ||
|
|
4d07acd384 | ||
|
|
2c06bb46ea | ||
|
|
3c3bfff0cf | ||
|
|
a86f6d0e64 | ||
|
|
4d54bfa6b4 | ||
|
|
28d1dab18a | ||
|
|
f3d19a860a | ||
|
|
5732e34f50 | ||
|
|
ca94a61acf | ||
|
|
a875c61b5f | ||
|
|
5ec70c9e0d | ||
|
|
4b0373408d | ||
|
|
7f8c4eff39 | ||
|
|
00f152910b | ||
|
|
95fdeb03c3 | ||
|
|
66e9ef9cf6 | ||
|
|
6b3221f1da | ||
|
|
25ad7bcf5e | ||
|
|
9a04a6bdb1 | ||
|
|
1b9fb906e2 | ||
|
|
e23d7ca51b | ||
|
|
92773c2e1b | ||
|
|
776889cfbb | ||
|
|
67163e14e6 | ||
|
|
45f68840ed | ||
|
|
325ae5e977 | ||
|
|
14919c65d9 | ||
|
|
8888e88dc4 | ||
|
|
0533664f90 | ||
|
|
64b824f457 | ||
|
|
b6592d799f | ||
|
|
c89711a863 | ||
|
|
91a1292b12 | ||
|
|
b2d469cb84 | ||
|
|
4f41da34c6 | ||
|
|
f136f2dcaf | ||
|
|
e6df54537a | ||
|
|
e62278859e | ||
|
|
51b91bce6d | ||
|
|
d96a23d4f2 | ||
|
|
98e049b336 | ||
|
|
3c297f5d1d | ||
|
|
d64d196409 | ||
|
|
b1638e79c0 | ||
|
|
13753757d4 | ||
|
|
739e341218 | ||
|
|
fda282604d | ||
|
|
2cd7fa68d6 | ||
|
|
d78a0c87b8 | ||
|
|
88d4abeaf8 | ||
|
|
1c0abbfce6 | ||
|
|
1492e12ca2 | ||
|
|
2b9a39e2eb | ||
|
|
301ae447b4 | ||
|
|
3d47010cbd | ||
|
|
dd0ff999e4 | ||
|
|
05e5c93e91 | ||
|
|
1bd97730ce | ||
|
|
458378be66 | ||
|
|
c01101dbd0 | ||
|
|
f7364111f2 | ||
|
|
f3b84b8670 | ||
|
|
ec11a31d9d | ||
|
|
2271469d1b | ||
|
|
7fe92d87c2 | ||
|
|
6046b8fb79 | ||
|
|
a65239a8af | ||
|
|
746cd5f49c | ||
|
|
75c315ad8a | ||
|
|
c1926c6e25 | ||
|
|
3f8ba353b7 | ||
|
|
39a2152a46 | ||
|
|
ddd967534b | ||
|
|
4d52fe0490 | ||
|
|
264ffa80ce | ||
|
|
258a9c636a | ||
|
|
8015d1827c | ||
|
|
ae10bc6601 | ||
|
|
51c27afcd2 | ||
|
|
e09d4f2cf2 | ||
|
|
7e87f56699 | ||
|
|
ca9150a731 | ||
|
|
5250d819d0 | ||
|
|
d93413a4ae | ||
|
|
bb7f7eff51 | ||
|
|
838e8c7b35 | ||
|
|
bb48a16466 | ||
|
|
a02ff01d84 | ||
|
|
66d27d6ac5 | ||
|
|
5ba82ef0fc | ||
|
|
053b522aff | ||
|
|
4521f80e5a | ||
|
|
f24efc17c1 | ||
|
|
f32d3849e5 | ||
|
|
f2fb064ea6 | ||
|
|
ce5093f91f | ||
|
|
75121588c4 | ||
|
|
1ff0f478d4 | ||
|
|
6c68082359 | ||
|
|
a752d220cc | ||
|
|
ee1bbd5994 | ||
|
|
91368e5656 | ||
|
|
c4c554b420 | ||
|
|
52ec8bf049 | ||
|
|
5c40e02ee6 | ||
|
|
d2a89c5856 | ||
|
|
9ec3f1b89d | ||
|
|
3ab81c764d | ||
|
|
c072ce8f0c | ||
|
|
e44dbd0e77 | ||
|
|
ec12022550 | ||
|
|
e0f670499c | ||
|
|
177cc87985 | ||
|
|
3e387f35e9 | ||
|
|
7037723993 | ||
|
|
b1098d6287 | ||
|
|
be222a16ce | ||
|
|
17f9a3eba6 | ||
|
|
0ee77c0e7d | ||
|
|
b92fa45da7 | ||
|
|
e64c2fc110 | ||
|
|
49a6508888 | ||
|
|
859678536f | ||
|
|
9a5f788807 | ||
|
|
84b3b1d29c | ||
|
|
80eb18a425 | ||
|
|
3e1ab53abd | ||
|
|
18c119b4d5 | ||
|
|
e67a65c0db | ||
|
|
4c878c4963 | ||
|
|
e8fbe0f36c | ||
|
|
243b7e25f8 | ||
|
|
f1a4a08c7f | ||
|
|
c0fa36b9a1 | ||
|
|
835b2d7ced | ||
|
|
13c2381ba7 | ||
|
|
fbc8e899dd | ||
|
|
5ee8c8ce91 | ||
|
|
971793d6a1 | ||
|
|
9d7a905fb1 | ||
|
|
731f002175 | ||
|
|
7e6f3bfd83 | ||
|
|
3e14739b29 | ||
|
|
d7fb6b2892 | ||
|
|
7527f441ae | ||
|
|
5228ee1d91 | ||
|
|
297a98e065 | ||
|
|
727d8afd94 | ||
|
|
c292fba3df | ||
|
|
9954ff55f5 | ||
|
|
fefd84d431 | ||
|
|
b4a7d21b9e | ||
|
|
d03e051611 | ||
|
|
e8c141d775 | ||
|
|
5b45e29533 | ||
|
|
024d094459 | ||
|
|
df977577e2 | ||
|
|
b63b94bc81 | ||
|
|
7e514f5d34 | ||
|
|
cb2de2e5c4 | ||
|
|
f2fedbc3e6 | ||
|
|
8ef686fd21 | ||
|
|
4c96e9a17d | ||
|
|
939bc00b2b | ||
|
|
0b06d3412e | ||
|
|
94f6f60105 | ||
|
|
4bd6bc9683 | ||
|
|
3c59621425 | ||
|
|
a37e2ab26a | ||
|
|
d099febf7b | ||
|
|
b9f82332c8 | ||
|
|
c02c4c6d6a | ||
|
|
17476ec137 | ||
|
|
ee51a68c6f | ||
|
|
0120ce5d7c | ||
|
|
42c6e640fc | ||
|
|
bc571316b9 | ||
|
|
3cc1af9618 | ||
|
|
6957bf504b | ||
|
|
d47dd70141 | ||
|
|
86eb2360db | ||
|
|
c55e350cb2 | ||
|
|
b0fe032b8d | ||
|
|
aa25870fb8 | ||
|
|
a8118ea8f4 | ||
|
|
1a344c1441 | ||
|
|
86a1641ac1 | ||
|
|
10129fa568 | ||
|
|
935a8d36da | ||
|
|
2516a3af8a | ||
|
|
120a265fc3 | ||
|
|
33aebeb727 | ||
|
|
7e06cfb471 | ||
|
|
f2bcff69a9 | ||
|
|
39b7d175b9 | ||
|
|
b9cebe8d87 | ||
|
|
6814cfbcd7 | ||
|
|
2884696024 | ||
|
|
6930046bc6 | ||
|
|
174cbfe3b9 | ||
|
|
611c7633cf | ||
|
|
822d4269c4 | ||
|
|
8fd16efc33 | ||
|
|
ef082d855c | ||
|
|
a5c4739804 | ||
|
|
d1f1a88ffd | ||
|
|
c05f6b7bf3 | ||
|
|
4b5fa26cd6 | ||
|
|
0162d18343 | ||
|
|
b6415818f6 | ||
|
|
e16efbf58b | ||
|
|
46804d0faf | ||
|
|
a81567e2d6 | ||
|
|
217670b54a | ||
|
|
f2e19c0387 | ||
|
|
9799970042 | ||
|
|
ca75d0d765 | ||
|
|
0824e49000 | ||
|
|
c3a98db0ea | ||
|
|
f27685717b | ||
|
|
55034bfa6f | ||
|
|
6f8b420d0d | ||
|
|
2ed7e14a99 | ||
|
|
ee3bcef8ab | ||
|
|
adbcb97515 | ||
|
|
c667723958 | ||
|
|
d94634398e | ||
|
|
f348e58508 | ||
|
|
60f16970ac | ||
|
|
39c5eafafc | ||
|
|
b7f6c223d8 | ||
|
|
bf9a65338b | ||
|
|
5b3ae5eff9 | ||
|
|
f80a8d306b | ||
|
|
9ed9060940 | ||
|
|
5453e60099 | ||
|
|
3de61b69ad | ||
|
|
322a4ed05d | ||
|
|
8f3b4afcf7 | ||
|
|
ebdc6b94fc | ||
|
|
a7218d2e59 | ||
|
|
6d93beac8e | ||
|
|
1fb1309e77 | ||
|
|
5916f40b7a | ||
|
|
5226714bbd | ||
|
|
dabf486a9f | ||
|
|
c78f4407ea | ||
|
|
fae4127ddc | ||
|
|
9cc1497e9e | ||
|
|
cdd64d52eb | ||
|
|
4d319c12f8 | ||
|
|
8fc3e4ab12 | ||
|
|
ed7d68d6a7 | ||
|
|
59820519ce | ||
|
|
767c807a40 | ||
|
|
d25adc1b10 | ||
|
|
35f0067fe5 | ||
|
|
f1b01dd086 | ||
|
|
3df08d64e2 | ||
|
|
f56cc43331 | ||
|
|
b4b37daaf6 | ||
|
|
1f187d24c8 | ||
|
|
5b806a467b | ||
|
|
20d14d5a10 | ||
|
|
043b2df345 | ||
|
|
9ec7feb9ab | ||
|
|
57cf6db4e0 | ||
|
|
61b677c073 | ||
|
|
264e42a4c5 | ||
|
|
251fd660f9 | ||
|
|
6459f53263 | ||
|
|
55c8d93862 | ||
|
|
c6f83f8c14 | ||
|
|
c9eaca0e56 | ||
|
|
6267c17c6b | ||
|
|
616113d384 | ||
|
|
ac738aff10 | ||
|
|
7627bf80b9 | ||
|
|
172abb2710 | ||
|
|
a643c6ef1e | ||
|
|
64bfb0961e | ||
|
|
68d822f50a | ||
|
|
56e3bab02a | ||
|
|
9dd5ab4ebd | ||
|
|
b1ef86de75 | ||
|
|
b4a0d7a5b7 | ||
|
|
e6a93a799a | ||
|
|
4e175f9cd6 | ||
|
|
62e3fe1414 | ||
|
|
eeb7285528 | ||
|
|
0340b62b7c | ||
|
|
5488f60260 | ||
|
|
be7ef860d5 | ||
|
|
9aba700d8c | ||
|
|
7972acf5bf | ||
|
|
430c001d58 | ||
|
|
943777e5d0 | ||
|
|
c086c3b03b | ||
|
|
e517eceb24 | ||
|
|
7fb57a4064 | ||
|
|
888bca13c0 | ||
|
|
8b39e0631d | ||
|
|
d0d0148a58 | ||
|
|
a73b62c5bf | ||
|
|
bee0afd301 | ||
|
|
8f37940f4c | ||
|
|
0fa8d8cb51 | ||
|
|
1f589d0d5d | ||
|
|
ad36745a7c | ||
|
|
99b9860ea5 | ||
|
|
dc5f82cce2 | ||
|
|
dc3050537b | ||
|
|
5acd0dd2d1 | ||
|
|
0d933a1901 | ||
|
|
9f21865caf | ||
|
|
2ba81d3fef | ||
|
|
bcc1c2e658 | ||
|
|
5fa8972ae6 | ||
|
|
96363a0ce3 | ||
|
|
817fa9d9be | ||
|
|
89334bb459 | ||
|
|
0ae2d99599 | ||
|
|
e1199a02ee | ||
|
|
9408a61eb1 | ||
|
|
78d7e1bdfe | ||
|
|
dd44a0aaea | ||
|
|
b3144dd19a | ||
|
|
2722e96fac | ||
|
|
488de0014e | ||
|
|
9c2e0ebd4c | ||
|
|
28cc96cfd0 | ||
|
|
4ab3b15efd | ||
|
|
ff363e3893 | ||
|
|
cd2c10b6dc | ||
|
|
563e981902 | ||
|
|
c3e20d5d12 | ||
|
|
2802486671 | ||
|
|
1507d03c21 | ||
|
|
fbbf193345 | ||
|
|
78e51e6b11 | ||
|
|
be2bbec526 | ||
|
|
a366096ef4 | ||
|
|
c72222f718 | ||
|
|
fba0ec93bf | ||
|
|
86f767e1aa | ||
|
|
7e54192713 | ||
|
|
e76a73e276 | ||
|
|
ccf0490624 | ||
|
|
fe2721e04e | ||
|
|
fdd1a9afef | ||
|
|
abf7aed880 | ||
|
|
d986c7cdc0 | ||
|
|
9d5e994c01 | ||
|
|
6f16fc77b8 | ||
|
|
651dfb796c | ||
|
|
4f2fc17a8f | ||
|
|
7bc019547f | ||
|
|
f8c2629a3e | ||
|
|
b5b4bff2fc | ||
|
|
7054b92a14 | ||
|
|
5856f9a45f | ||
|
|
cec10060c6 | ||
|
|
74a479ab41 | ||
|
|
e51ab09bb1 | ||
|
|
0cd98bc353 | ||
|
|
158f9b0dc7 | ||
|
|
95fe6eaf86 | ||
|
|
40b4859b16 | ||
|
|
e4832f0d08 | ||
|
|
5d5400a9ac | ||
|
|
f439cad46c | ||
|
|
9fe2e8e31a | ||
|
|
92d3fc3d8c | ||
|
|
5d89599799 | ||
|
|
2eb5b5eb67 | ||
|
|
45549a8173 | ||
|
|
d7ebf2edc1 | ||
|
|
a9aed2e557 | ||
|
|
d691a0cf24 | ||
|
|
cbaa959521 | ||
|
|
2f128113b6 | ||
|
|
70251a8b2e | ||
|
|
e332f4e12b | ||
|
|
9a140ff93f | ||
|
|
97ab5dd1b5 | ||
|
|
075b4e92a9 | ||
|
|
f22dcfe03c | ||
|
|
124086419e | ||
|
|
0712db0d29 | ||
|
|
895f7edd12 | ||
|
|
a3c5c0c23a | ||
|
|
f7a3a6c17b | ||
|
|
98bec2580e | ||
|
|
5ca2d469a8 | ||
|
|
b413405876 | ||
|
|
330ff93e3e | ||
|
|
fe08104d18 | ||
|
|
e518605d69 | ||
|
|
9a35085ac3 | ||
|
|
b0cf41de08 | ||
|
|
00c3dc73f3 | ||
|
|
a73cc93d21 | ||
|
|
5a10299074 | ||
|
|
77d243f87f | ||
|
|
fb4f6406c9 | ||
|
|
3133b9b010 | ||
|
|
12723167fc | ||
|
|
2cc22778b5 | ||
|
|
790d3f12a6 | ||
|
|
beb1ab81e0 | ||
|
|
e5126b4c65 | ||
|
|
a2a4df5d06 | ||
|
|
ac0bd9714b | ||
|
|
60226d9195 | ||
|
|
64455b9852 | ||
|
|
96f6cdf677 | ||
|
|
c188491289 | ||
|
|
e9e4d566a5 | ||
|
|
85bedca236 | ||
|
|
d80191df3d | ||
|
|
9137e92c09 | ||
|
|
721dae3892 | ||
|
|
1cdacf69be | ||
|
|
b5b002aa4b | ||
|
|
78f5b513c0 | ||
|
|
0032fcaa66 | ||
|
|
0fba0923c8 | ||
|
|
e0169f6696 | ||
|
|
28217f10cb | ||
|
|
fb28f4bcd0 | ||
|
|
8852256ab6 | ||
|
|
95de453677 | ||
|
|
5ef40e15c4 | ||
|
|
31f223bff5 | ||
|
|
9fce2b1d8e | ||
|
|
a6ceb337b2 | ||
|
|
f4e22cb44c | ||
|
|
ab9750f8b2 | ||
|
|
fe8e0b0e0a | ||
|
|
c2565cf3b7 | ||
|
|
af82971bf5 | ||
|
|
271b52158e | ||
|
|
26c404adee | ||
|
|
f06af54165 | ||
|
|
2a77dfbcd2 | ||
|
|
738fcb6563 | ||
|
|
3d4754d4ad | ||
|
|
b9ea1d1be4 | ||
|
|
b1b0484dae | ||
|
|
20b79784bf | ||
|
|
4baa3358df | ||
|
|
8fe7f8b8d8 | ||
|
|
6996a0db2b | ||
|
|
b89a899c82 | ||
|
|
bbbbb660b3 | ||
|
|
6ba29219e5 | ||
|
|
dd97bdcc2c | ||
|
|
b63e0f08bf | ||
|
|
c5ae9d45ad | ||
|
|
e906a0da8c | ||
|
|
2edfb0aaac | ||
|
|
dc116858a9 | ||
|
|
1a938f8711 | ||
|
|
fc88cd3cb1 | ||
|
|
55205e631b | ||
|
|
a36fa76d21 | ||
|
|
b8d512f5e1 | ||
|
|
d4263b59c6 | ||
|
|
e5e1507dff | ||
|
|
2edf63c5fd | ||
|
|
5ec4b3441e | ||
|
|
dd1757b3c3 | ||
|
|
dda26545e5 | ||
|
|
410ef8ce96 | ||
|
|
ce7cb9cf64 | ||
|
|
31a16375ab | ||
|
|
ec7b47da22 | ||
|
|
0124020ba4 | ||
|
|
28f71d18bd | ||
|
|
fe226c1c8d | ||
|
|
18e20de4d6 | ||
|
|
956d345e17 | ||
|
|
ddfb958647 | ||
|
|
145d0ef37d | ||
|
|
019e3956f7 | ||
|
|
a72daff4ac | ||
|
|
58ce9cd37f | ||
|
|
687bdaff8f | ||
|
|
2143a66ad6 | ||
|
|
74892f1562 | ||
|
|
4a59ac011f | ||
|
|
e0fd2e8f27 | ||
|
|
ba76506773 | ||
|
|
d224827544 | ||
|
|
8d35b5bd11 | ||
|
|
9df28c25d7 | ||
|
|
5f9b2a91fd | ||
|
|
46a46f5e49 | ||
|
|
4bdc495d01 | ||
|
|
e60d5e6aeb | ||
|
|
7c3387755d | ||
|
|
6f04dad428 | ||
|
|
6ed4720df3 | ||
|
|
ac7b454039 | ||
|
|
0af39de346 | ||
|
|
d484979fe8 | ||
|
|
6e87e5c05f | ||
|
|
7633c8e76e | ||
|
|
c78e89c3c1 | ||
|
|
1852aaf332 | ||
|
|
8b4c8f63c0 | ||
|
|
d7b64c18c2 | ||
|
|
09668c972e | ||
|
|
68a0d10443 | ||
|
|
0708e7f8f6 | ||
|
|
1235e989d4 | ||
|
|
3a6808e4d8 | ||
|
|
dbfb034548 | ||
|
|
94d01e9e5a | ||
|
|
5e48b49b7e | ||
|
|
3b0785cae0 | ||
|
|
bd3b46d624 | ||
|
|
1cbe996831 | ||
|
|
18865c44c8 | ||
|
|
ead6ca73e5 | ||
|
|
deb3f6d9c4 | ||
|
|
b1b98c5256 | ||
|
|
4dc2227f23 | ||
|
|
a76f9e11fb | ||
|
|
abeb91a5e4 | ||
|
|
6d5e7cbe08 | ||
|
|
c468c26ad6 | ||
|
|
a0e940c5a9 | ||
|
|
2f1de22cae | ||
|
|
4631282709 | ||
|
|
306ac5243a | ||
|
|
956fe42a6c | ||
|
|
1824bdfe7e | ||
|
|
5f53284cbd | ||
|
|
7a84b71eb2 | ||
|
|
85382cd6c2 | ||
|
|
02a99f1e51 | ||
|
|
fe405df704 | ||
|
|
ac5ee90c9b | ||
|
|
fb6b34e155 | ||
|
|
caa8932c9a | ||
|
|
75611f3bca | ||
|
|
f0f14d8a22 | ||
|
|
98ad6cd23b | ||
|
|
bd80d1cd76 | ||
|
|
5a4670ec2f | ||
|
|
6fd039925a | ||
|
|
cd602ab5e3 | ||
|
|
f59ead54d3 | ||
|
|
4030f1e40d | ||
|
|
b7ac7452f7 | ||
|
|
5dd6867408 | ||
|
|
9d410df287 | ||
|
|
fe8dc36074 | ||
|
|
0cef3fbf27 | ||
|
|
b5d9b18da4 | ||
|
|
dc0ea197cd | ||
|
|
5bf17fc5ae | ||
|
|
33ca5943fa | ||
|
|
edc6591041 | ||
|
|
113ec33743 | ||
|
|
8c297832f6 | ||
|
|
e767b2ff94 | ||
|
|
a1ff408c13 | ||
|
|
440184e83c | ||
|
|
8ee6cad7ea | ||
|
|
edb17b76f0 | ||
|
|
31dc5f335d | ||
|
|
eb68e4c627 | ||
|
|
98e97920ae | ||
|
|
533723cd8b | ||
|
|
9e69afbbd6 | ||
|
|
2dea76dfa1 | ||
|
|
8a8bafb199 | ||
|
|
5a21d8c24d | ||
|
|
5111b4799c | ||
|
|
528bbe0116 | ||
|
|
3030ab8664 | ||
|
|
2698ff1a04 | ||
|
|
084dd1c8dd | ||
|
|
a8392889de | ||
|
|
3bf5edc2b3 | ||
|
|
97be0ff22a | ||
|
|
b43c8c018b | ||
|
|
38a5a4b97b | ||
|
|
73d70b6953 | ||
|
|
6b06733192 | ||
|
|
359146f60b | ||
|
|
0931c6a7e1 | ||
|
|
f2049c5910 | ||
|
|
de76827dd8 | ||
|
|
0cae3ac5a1 | ||
|
|
4fc378d3e2 | ||
|
|
e3e11d233c | ||
|
|
fcfd5c7419 | ||
|
|
be8c498aea | ||
|
|
5528b9ba09 | ||
|
|
c60877b6f2 | ||
|
|
07901946d0 | ||
|
|
705ea18b2a | ||
|
|
3277cc3675 | ||
|
|
c09b7bed34 | ||
|
|
83e633534d | ||
|
|
8a2c299653 | ||
|
|
74dc2ed1f9 | ||
|
|
dc0d6a9b4a | ||
|
|
3f264097a7 | ||
|
|
e0c7b17bd5 | ||
|
|
d43b027c25 | ||
|
|
85963cafe7 | ||
|
|
d4deeb4edd | ||
|
|
c72bfe3685 | ||
|
|
90137f2263 | ||
|
|
d8474cfafa | ||
|
|
493a756aaa | ||
|
|
95d30ba4ec | ||
|
|
dbcb3e6192 | ||
|
|
4228642b53 | ||
|
|
acba87ae46 | ||
|
|
533f17b3b0 | ||
|
|
77de71d79d | ||
|
|
caadb7fa27 | ||
|
|
1dd862f83d | ||
|
|
70bb4930f6 | ||
|
|
852eb5c524 | ||
|
|
3cfc45c4e8 | ||
|
|
db97c2a5b1 | ||
|
|
70993256b9 | ||
|
|
a439c3be3c | ||
|
|
0a060982e3 | ||
|
|
7ffcc176cd | ||
|
|
4a9650df80 | ||
|
|
f1c6f09f98 | ||
|
|
f039c0636e | ||
|
|
a620e1490c | ||
|
|
d682361cfc | ||
|
|
d3f0a14867 | ||
|
|
83393f299a | ||
|
|
bf1285567e | ||
|
|
e315726001 | ||
|
|
2f3e172162 | ||
|
|
d6cf9bd8ae | ||
|
|
5710a35388 | ||
|
|
1156d00538 | ||
|
|
5707354a18 | ||
|
|
155cc4573c | ||
|
|
3288592d30 | ||
|
|
886b683739 | ||
|
|
95cffca5f1 | ||
|
|
85cb592a7e | ||
|
|
13b9deb5ef | ||
|
|
c307c692a0 | ||
|
|
008e98d980 | ||
|
|
b11f597521 | ||
|
|
944c523a49 | ||
|
|
3c365259cc | ||
|
|
98274d4b17 | ||
|
|
12a1cb9e97 | ||
|
|
d273750849 | ||
|
|
75c54c6738 | ||
|
|
ffd72fbb4d | ||
|
|
71dc3d4826 | ||
|
|
b7757d71bf | ||
|
|
55338e731b | ||
|
|
097aa3fa16 | ||
|
|
935d6a7cf5 | ||
|
|
c69d1c7fb8 | ||
|
|
b5152c0c48 | ||
|
|
ed02df113f | ||
|
|
2afdcf54ab | ||
|
|
764fbe7fac | ||
|
|
0c9160ec8b | ||
|
|
33bed487ac | ||
|
|
3e36382b58 | ||
|
|
7ec656db09 | ||
|
|
cf61779b08 | ||
|
|
71600a4f37 | ||
|
|
14320f2155 | ||
|
|
1923368353 | ||
|
|
752bd78de5 | ||
|
|
c4b17855e5 | ||
|
|
a1543f79cb | ||
|
|
d4798ccaa5 | ||
|
|
c2c4ed1fe5 | ||
|
|
614188c82b | ||
|
|
53e98c114a | ||
|
|
73c8246204 | ||
|
|
58d98f8454 | ||
|
|
7605396e84 | ||
|
|
cec339552e | ||
|
|
fc003db139 | ||
|
|
caf434aef2 | ||
|
|
5261873f39 | ||
|
|
421b58f68e | ||
|
|
850dbd62c6 | ||
|
|
2af45da0a8 | ||
|
|
685e8bac22 | ||
|
|
e2a6ae9ecc | ||
|
|
eb64e66e9f | ||
|
|
6a24b049cb | ||
|
|
1112dfffb3 | ||
|
|
3304bc2f3a | ||
|
|
4d2bee192f | ||
|
|
2d4fb8a463 | ||
|
|
56c5012bef | ||
|
|
47002f970d | ||
|
|
f6fd395485 | ||
|
|
4f426dafef | ||
|
|
7b6f2863a9 | ||
|
|
834a9bc84d | ||
|
|
7710a1fdb0 | ||
|
|
bd97bdd378 | ||
|
|
211c5dcfcd | ||
|
|
2cdf1897b9 | ||
|
|
bf8c57c669 | ||
|
|
7fd6b308f8 | ||
|
|
6908c0f1d0 | ||
|
|
f74380b3e9 | ||
|
|
4abdc29d9e | ||
|
|
5096aef6e7 | ||
|
|
d9f5801a68 | ||
|
|
462e03d150 | ||
|
|
6aded88e14 | ||
|
|
74a25097b2 | ||
|
|
2c190f502f | ||
|
|
0122686541 | ||
|
|
187c0a9bf7 | ||
|
|
a4295d1e93 | ||
|
|
9def5e57de | ||
|
|
3d573c08a1 | ||
|
|
c9ff6be881 | ||
|
|
40a8892cb7 | ||
|
|
e1bb10d859 | ||
|
|
569f4646a0 | ||
|
|
16756e550f | ||
|
|
933b77e429 | ||
|
|
3ac9ecb4b7 | ||
|
|
ccc4386285 | ||
|
|
4364ba46e2 | ||
|
|
d7917a6a9a | ||
|
|
81e30e75c4 | ||
|
|
7a94343dec | ||
|
|
3ee6bae4ba | ||
|
|
9a77e6b3cc | ||
|
|
a1727cc047 | ||
|
|
5b012b6509 | ||
|
|
c23ffa2ce5 | ||
|
|
ff68383732 | ||
|
|
bce2b2adb6 | ||
|
|
fa8c9a8418 | ||
|
|
2e176b8b8d | ||
|
|
f6bb6037f3 | ||
|
|
7fac7c8713 | ||
|
|
bdaef0b0dc | ||
|
|
5b21fc89fc | ||
|
|
bc7b90a1b4 | ||
|
|
134cb68396 | ||
|
|
c0ee2ce345 | ||
|
|
a299533508 | ||
|
|
d4bcbc3771 | ||
|
|
2c7555366f | ||
|
|
d8264fada7 | ||
|
|
72da49415e | ||
|
|
8e744ec5f7 | ||
|
|
7372b66680 | ||
|
|
8dfbcf5a9f | ||
|
|
01ff2cca0c | ||
|
|
e981c2b43f | ||
|
|
1f636bf7a9 | ||
|
|
68bc33ef4d | ||
|
|
a7e447a3f5 | ||
|
|
096a04b3e4 | ||
|
|
86e600000d | ||
|
|
a0128d9b7c | ||
|
|
65996254c6 | ||
|
|
a85031be53 | ||
|
|
8509f0857a | ||
|
|
b24c75b400 | ||
|
|
d372e789a4 | ||
|
|
d9f7e4c9e0 | ||
|
|
e6ea726b69 | ||
|
|
98c1a18e57 | ||
|
|
e04d2a4a10 | ||
|
|
96a3671bb6 | ||
|
|
0c028ca9d0 | ||
|
|
64124447d5 | ||
|
|
037ea592ab | ||
|
|
6ebbb48f9f | ||
|
|
2e8a53ff34 | ||
|
|
f104438802 | ||
|
|
eb25650e26 | ||
|
|
c4cba5254c | ||
|
|
c90dda908a | ||
|
|
6aca0a8bfc | ||
|
|
864376e7ba | ||
|
|
71794fe511 | ||
|
|
c69989c56f | ||
|
|
cc91beece7 | ||
|
|
0d6c6bdb58 | ||
|
|
e234b1537c | ||
|
|
407e58604f | ||
|
|
2c3bf7dd23 | ||
|
|
5e6417eac0 | ||
|
|
a4db34a419 | ||
|
|
8c493576cc | ||
|
|
110a0d98fa | ||
|
|
449b52e5a4 | ||
|
|
d0fda1f919 | ||
|
|
79ea33beda | ||
|
|
fef5bd321c | ||
|
|
6c7a763b76 | ||
|
|
78fa1c9995 | ||
|
|
3623ee3ce8 | ||
|
|
ba28da5fdc | ||
|
|
c2b7bd10ec | ||
|
|
35ab37c76c | ||
|
|
c968dfa113 | ||
|
|
09b24e45f9 | ||
|
|
8541040bb9 | ||
|
|
8ae003046c | ||
|
|
fc7f9ac6e9 | ||
|
|
7dcc7ea99c | ||
|
|
4590015ed6 | ||
|
|
79f9dc61a4 | ||
|
|
3fac7d027a | ||
|
|
10ba5809d2 | ||
|
|
792204bd06 | ||
|
|
f19cb010a0 | ||
|
|
ca3df3bd50 | ||
|
|
db43487b5a | ||
|
|
38c37b8160 | ||
|
|
44a04e6167 | ||
|
|
9d6a9eb615 | ||
|
|
27070af1b9 | ||
|
|
32d2d4107d | ||
|
|
75ebac822d | ||
|
|
bd9fab6cf5 | ||
|
|
d75f8f11e1 | ||
|
|
47900db414 | ||
|
|
aec3469c03 | ||
|
|
b61542242c | ||
|
|
13c1fd09c4 | ||
|
|
fddb69e49e | ||
|
|
ed51d5cf84 | ||
|
|
3d7b0db114 | ||
|
|
9e445a5adf | ||
|
|
97e25c37de | ||
|
|
16033c1307 | ||
|
|
15d64b8486 | ||
|
|
5d06aa3c8c | ||
|
|
e276223b61 | ||
|
|
71b48fad0f | ||
|
|
a3fade1c1d | ||
|
|
6530f47b2d | ||
|
|
3ab1ef139f | ||
|
|
36bd6423c2 | ||
|
|
ffd8ff099a | ||
|
|
178347f9f1 | ||
|
|
e194f89b25 | ||
|
|
3bfc70aa3b | ||
|
|
93a6a0f211 | ||
|
|
cef6a2e389 | ||
|
|
4f5764e4a5 | ||
|
|
21770ff10f | ||
|
|
2b97461f54 | ||
|
|
0cf5f4ae2a | ||
|
|
7b6dcfce87 | ||
|
|
f9d472847c | ||
|
|
d69d97402b | ||
|
|
643c39690f | ||
|
|
6048144310 | ||
|
|
94303ea9a0 | ||
|
|
a017e4820a | ||
|
|
50e1c5ba1f | ||
|
|
c5ec369388 | ||
|
|
7d3ebce7d1 | ||
|
|
52826342fc | ||
|
|
29b357a2f6 | ||
|
|
747ed1e59a | ||
|
|
992c05b6aa | ||
|
|
f4a5457941 | ||
|
|
7167a807bf | ||
|
|
22675ba2e7 | ||
|
|
80602b011d | ||
|
|
abea8e2195 | ||
|
|
9075aecb18 | ||
|
|
6e9ac875d7 | ||
|
|
100ecb12e9 | ||
|
|
57b4701e57 | ||
|
|
fffc211989 | ||
|
|
5a0528de26 | ||
|
|
fb8f46ea45 | ||
|
|
a8e1a4f2fd | ||
|
|
157f050f89 | ||
|
|
3653f56331 | ||
|
|
e31cbbfe21 | ||
|
|
bc3491c5bd | ||
|
|
9a7c25047d | ||
|
|
7cef8b7363 | ||
|
|
e449b8384c | ||
|
|
9514c12982 | ||
|
|
489d6c5a65 | ||
|
|
ccc59ecdaf | ||
|
|
d2ce50f989 | ||
|
|
14e409adb4 | ||
|
|
4a0f639e89 | ||
|
|
32c5925652 | ||
|
|
4c91dd8621 | ||
|
|
f641aa92f5 | ||
|
|
3bdc8583e5 | ||
|
|
4e37900d93 | ||
|
|
c676ecc026 | ||
|
|
db760dc29b | ||
|
|
0fbb87e3b2 | ||
|
|
29996d0133 | ||
|
|
7807f3e31a | ||
|
|
e246d14a6b | ||
|
|
a34a27be65 | ||
|
|
e1d2b88c23 | ||
|
|
f96ca17f17 | ||
|
|
50580498c4 | ||
|
|
a21e688c96 | ||
|
|
4b1deee7e1 | ||
|
|
bf5fefe84f | ||
|
|
5c92b0d154 | ||
|
|
2b7ccf6625 | ||
|
|
004d450844 | ||
|
|
7705e88b57 | ||
|
|
3f250ba42d | ||
|
|
1b8bb4e049 | ||
|
|
1577fab93a | ||
|
|
181fe74b09 | ||
|
|
34b8d00548 | ||
|
|
0a6cbadcd8 | ||
|
|
701fef1ba4 | ||
|
|
cdd78b2ec3 | ||
|
|
ba04132142 | ||
|
|
ddc42bedf5 | ||
|
|
ea84302e28 | ||
|
|
a7a08a7d4e | ||
|
|
0a33a25a7d | ||
|
|
2c9622ea52 | ||
|
|
08e2fc8deb | ||
|
|
ebed45a0f6 | ||
|
|
d3c279fd05 | ||
|
|
e69ed4b0da | ||
|
|
4daca3c5ba | ||
|
|
cb41fa6de4 | ||
|
|
dc758ead10 | ||
|
|
1fe38c7473 | ||
|
|
5564c38a2f | ||
|
|
2a853a23d7 | ||
|
|
37da98c9bb | ||
|
|
5a5172be57 | ||
|
|
58ec9a4f38 | ||
|
|
b7477fc321 | ||
|
|
88afac51f0 | ||
|
|
2bb3e5fd6b | ||
|
|
dd338d40f3 | ||
|
|
1cc8440900 | ||
|
|
47cf8f4233 | ||
|
|
eedfd2d70d | ||
|
|
4e88626d65 | ||
|
|
a1b91ac136 | ||
|
|
4bbd74b702 | ||
|
|
1d07d24054 | ||
|
|
0a0fd0c64a | ||
|
|
a7c6fc12d8 | ||
|
|
48f0a49f9b | ||
|
|
b63d714a06 | ||
|
|
7bdcea5814 | ||
|
|
f418f38589 | ||
|
|
7d3e32b65f | ||
|
|
52377b509b | ||
|
|
14152bb7ba | ||
|
|
d51aaec97d | ||
|
|
ea3fe754f4 | ||
|
|
04354a809c | ||
|
|
3cf30f5e62 | ||
|
|
7ff0129f36 | ||
|
|
b684d3aad7 | ||
|
|
f164419baa | ||
|
|
f20603ad06 | ||
|
|
bac975331d | ||
|
|
dcccfbd26a | ||
|
|
4baf847062 | ||
|
|
90a44ea6c8 | ||
|
|
fef83838f9 | ||
|
|
1422a9abe3 | ||
|
|
2fc0520895 | ||
|
|
7b1adfe00b | ||
|
|
28e1568eb7 | ||
|
|
0a6eac7c27 | ||
|
|
ecaced40f2 | ||
|
|
984a2d26f4 | ||
|
|
f85bb7e490 | ||
|
|
321443450a | ||
|
|
25a0a192a2 | ||
|
|
843ff25de4 | ||
|
|
4563c00deb | ||
|
|
7a38e5584c | ||
|
|
e26ce2b457 | ||
|
|
9c1e45d97c | ||
|
|
c2756c731f | ||
|
|
d6fc82f8fa | ||
|
|
2acf1b08d5 | ||
|
|
6ffd39ac77 | ||
|
|
9ae456b9d1 | ||
|
|
5bbeddc134 | ||
|
|
373fbb6ca3 | ||
|
|
d1405f2ab3 | ||
|
|
2ff9b0aada | ||
|
|
43f5d71724 | ||
|
|
41b61ed36f | ||
|
|
31e30faace | ||
|
|
ff7a2c6b73 | ||
|
|
acea705df8 | ||
|
|
7e3f9ada31 | ||
|
|
0a956115eb | ||
|
|
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,28 @@
|
||||
# Binaries
|
||||
\.dll$
|
||||
\.dylib$
|
||||
\.exe$
|
||||
\.so$
|
||||
|
||||
# Files generated by Visual Studio
|
||||
\.aps$
|
||||
\.ipch$
|
||||
\.ncb$
|
||||
\.opensdf$
|
||||
\.sdf$
|
||||
\.suo$
|
||||
\.user$
|
||||
|
||||
# Build directories
|
||||
/CrazyDebug.*
|
||||
/Debug.*
|
||||
/Release.*
|
||||
|
||||
# Files generated by Mac OS X Finder
|
||||
(^|/)\.DS_Store$
|
||||
|
||||
# Files generated by Windows Explorer
|
||||
(^|/)[dD]esktop\.ini$
|
||||
(^|/)[tT]humbs\.db$
|
||||
syntax: glob
|
||||
build/*
|
||||
@@ -0,0 +1,7 @@
|
||||
54539fa4e51f98d7841c853c1370dff6ccd3cdf2 sourcemod-1.0.0
|
||||
e6ef5ecdf8d75740ca2685a709bf321f8873bc3b sourcemod-1.1.0
|
||||
e877885fac80be71822641f7a9122cebc9812521 sourcemod-1.1.1
|
||||
b3ffa8a4511c4eadaf533fc790aa6b14f7f0c6ea sourcemod-1.1.2
|
||||
3a73bbf60f34befa9b66be03fa5974b394bb3411 sourcemod-1.2.0
|
||||
78a1f1b1c6fa86fd7691c70ebf48a9fb3dfb3c11 sourcemod-1.5.0
|
||||
5574bfe07731b7dba171c1300f6022319d2dbc89 sourcemod-1.5.1
|
||||
+499
@@ -0,0 +1,499 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
import sys
|
||||
from ambuild.command import Command
|
||||
from ambuild.command import ShellCommand
|
||||
from ambuild.command import SymlinkCommand
|
||||
|
||||
class ExtractDebugInfoCommand(Command):
|
||||
def __init__(self, binary, outfile):
|
||||
Command.__init__(self)
|
||||
self.binary = binary
|
||||
self.outfile = outfile
|
||||
|
||||
def run(self, runner, job):
|
||||
if AMBuild.cache['debug']:
|
||||
return
|
||||
|
||||
if not self.binary.NeedsRelink(self.outfile):
|
||||
return
|
||||
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
job.AddCommand(ShellCommand('objcopy --only-keep-debug ' + self.outfile + ' ' + self.outfile + '.dbg'))
|
||||
job.AddCommand(ShellCommand('objcopy --strip-debug ' + self.outfile))
|
||||
job.AddCommand(ShellCommand('objcopy --add-gnu-debuglink=' + os.path.basename(self.outfile) + '.dbg ' + self.outfile))
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
job.AddCommand(ShellCommand('dsymutil ' + self.outfile))
|
||||
job.AddCommand(ShellCommand('strip -S ' + self.outfile))
|
||||
|
||||
class SM:
|
||||
def __init__(self):
|
||||
self.compiler = Cpp.Compiler()
|
||||
|
||||
#Build SDK info
|
||||
self.possibleSdks = { }
|
||||
self.possibleSdks['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
|
||||
'name': 'EPISODEONE', 'platform': ['windows', 'linux'],
|
||||
'dir': 'hl2sdk'}
|
||||
self.possibleSdks['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
|
||||
'name': 'ORANGEBOX', 'platform': ['windows', 'linux'],
|
||||
'dir': 'hl2sdk-ob'}
|
||||
self.possibleSdks['css'] = {'sdk': 'HL2SDKCSS', 'ext': '2.css', 'def': '6',
|
||||
'name': 'CSS', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-css'}
|
||||
self.possibleSdks['hl2dm'] = {'sdk': 'HL2SDKHL2DM', 'ext': '2.hl2dm', 'def': '7',
|
||||
'name': 'HL2DM', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-hl2dm'}
|
||||
self.possibleSdks['dods'] = {'sdk': 'HL2SDKDODS', 'ext': '2.dods', 'def': '8',
|
||||
'name': 'DODS', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-dods'}
|
||||
self.possibleSdks['tf2'] = {'sdk': 'HL2SDKTF2', 'ext': '2.tf2', 'def': '9',
|
||||
'name': 'TF2', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-tf2'}
|
||||
self.possibleSdks['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '10',
|
||||
'name': 'LEFT4DEAD', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-l4d'}
|
||||
self.possibleSdks['nd'] = {'sdk': 'HL2SDKND', 'ext': '2.nd', 'def': '11',
|
||||
'name': 'NUCLEARDAWN', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-nd'}
|
||||
self.possibleSdks['l4d2'] = {'sdk': 'HL2SDKL4D2', 'ext': '2.l4d2', 'def': '12',
|
||||
'name': 'LEFT4DEAD2', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-l4d2'}
|
||||
self.possibleSdks['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
|
||||
'name': 'DARKMESSIAH', 'platform': ['windows'],
|
||||
'dir': 'hl2sdk-darkm'}
|
||||
self.possibleSdks['swarm'] = {'sdk': 'HL2SDK-SWARM', 'ext': '2.swarm', 'def': '13',
|
||||
'name': 'ALIENSWARM', 'platform': ['windows'],
|
||||
'dir': 'hl2sdk-swarm'}
|
||||
self.possibleSdks['bgt'] = {'sdk': 'HL2SDK-BGT', 'ext': '2.bgt', 'def': '4',
|
||||
'name': 'BLOODYGOODTIME', 'platform': ['windows'],
|
||||
'dir': 'hl2sdk-bgt'}
|
||||
self.possibleSdks['eye'] = {'sdk': 'HL2SDK-EYE', 'ext': '2.eye', 'def': '5',
|
||||
'name': 'EYE', 'platform': ['windows'],
|
||||
'dir': 'hl2sdk-eye'}
|
||||
self.possibleSdks['csgo'] = {'sdk': 'HL2SDKCSGO', 'ext': '2.csgo', 'def': '15',
|
||||
'name': 'CSGO', 'platform': ['windows', 'linux', 'darwin'],
|
||||
'dir': 'hl2sdk-csgo'}
|
||||
# self.possibleSdks['portal2'] = {'sdk': 'HL2SDK-PORTAL2', 'ext': '2.portal2', 'def': '14',
|
||||
# 'name': 'PORTAL2', 'platform': ['windows'],
|
||||
# 'dir': 'hl2sdk-portal'}
|
||||
|
||||
self.sdkInfo = { }
|
||||
|
||||
if AMBuild.mode == 'config':
|
||||
#Detect compilers
|
||||
self.compiler.DetectAll(AMBuild)
|
||||
|
||||
self.hasMySql = AMBuild.options.hasMySql
|
||||
AMBuild.cache.CacheVariable('hasMySql', self.hasMySql)
|
||||
|
||||
AMBuild.cache.CacheVariable('debug', AMBuild.options.debug)
|
||||
|
||||
#Environment variable paths to external headers
|
||||
envvars = { 'MMSOURCE110': 'mmsource-1.10', 'MYSQL5': 'mysql-5.0' }
|
||||
|
||||
#Look for Metamod:Source and MySQL if not disabled
|
||||
for env in envvars:
|
||||
if not self.hasMySql and env == 'MYSQL5':
|
||||
continue
|
||||
path = self.ResolveEnvPath(env, envvars[env])
|
||||
if path == None:
|
||||
raise Exception('Could not find a valid path for {0}'.format(env))
|
||||
AMBuild.cache.CacheVariable(env, path)
|
||||
|
||||
#Look for SDK directories
|
||||
for sdk in self.possibleSdks:
|
||||
#Get list of SDKs to build against or 'all' or 'present'
|
||||
sdkList = AMBuild.options.sdks.split(',')
|
||||
#Build against all supported SDKs?
|
||||
useAll = sdkList[0] == 'all'
|
||||
#Build against supported SDKs that exist?
|
||||
usePresent = sdkList[0] == 'present'
|
||||
|
||||
info = self.possibleSdks[sdk]
|
||||
if AMBuild.target['platform'] in info['platform']:
|
||||
env = info['sdk']
|
||||
dir = info['dir']
|
||||
sdkPath = self.ResolveEnvPath(env, dir)
|
||||
if sdkPath == None:
|
||||
if useAll or sdk in sdkList:
|
||||
raise Exception('Could not find a valid path for {0}'.format(env))
|
||||
else:
|
||||
continue
|
||||
if useAll or usePresent or sdk in sdkList:
|
||||
self.sdkInfo[sdk] = info
|
||||
AMBuild.cache.CacheVariable(env, sdkPath)
|
||||
|
||||
if len(self.sdkInfo) < 1:
|
||||
raise Exception('At least one SDK must be available.')
|
||||
|
||||
AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
|
||||
|
||||
#Set up defines
|
||||
cxx = self.compiler.cxx
|
||||
if isinstance(cxx, Cpp.CompatGCC):
|
||||
if isinstance(cxx, Cpp.GCC):
|
||||
self.vendor = 'gcc'
|
||||
elif isinstance(cxx, Cpp.Clang):
|
||||
self.vendor = 'clang'
|
||||
self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
|
||||
self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
|
||||
self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
|
||||
self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
|
||||
self.compiler.AddToListVar('CFLAGS', '-pipe')
|
||||
self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
|
||||
if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
|
||||
self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wall')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Werror')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
|
||||
self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
|
||||
self.compiler.AddToListVar('CFLAGS', '-msse')
|
||||
self.compiler.AddToListVar('CFLAGS', '-g3')
|
||||
self.compiler.AddToListVar('CFLAGS', '-m32')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
|
||||
if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
|
||||
(self.vendor == 'clang' and cxx.majorVersion >= 3):
|
||||
self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
|
||||
self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
|
||||
self.compiler.AddToListVar('CDEFINES', 'GNUC')
|
||||
if self.vendor == 'gcc':
|
||||
self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
|
||||
elif isinstance(cxx, Cpp.MSVC):
|
||||
self.vendor = 'msvc'
|
||||
if AMBuild.options.debug == '1':
|
||||
self.compiler.AddToListVar('CFLAGS', '/MTd')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
|
||||
else:
|
||||
self.compiler.AddToListVar('CFLAGS', '/MT')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
|
||||
self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/GR-')
|
||||
self.compiler.AddToListVar('CFLAGS', '/W3')
|
||||
self.compiler.AddToListVar('CFLAGS', '/nologo')
|
||||
self.compiler.AddToListVar('CFLAGS', '/Zi')
|
||||
self.compiler.AddToListVar('CXXFLAGS', '/TP')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
|
||||
|
||||
#Optimization
|
||||
if AMBuild.options.opt == '1':
|
||||
self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
|
||||
if self.vendor == 'gcc' or self.vendor == 'clang':
|
||||
self.compiler.AddToListVar('CFLAGS', '-O3')
|
||||
elif self.vendor == 'msvc':
|
||||
self.compiler.AddToListVar('CFLAGS', '/Ox')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
|
||||
|
||||
#Debugging
|
||||
if AMBuild.options.debug == '1':
|
||||
self.compiler.AddToListVar('CDEFINES', 'DEBUG')
|
||||
self.compiler.AddToListVar('CDEFINES', '_DEBUG')
|
||||
if self.vendor == 'msvc':
|
||||
self.compiler.AddToListVar('CFLAGS', '/Od')
|
||||
self.compiler.AddToListVar('CFLAGS', '/RTC1')
|
||||
|
||||
#This needs to be after our optimization flags which could otherwise disable it.
|
||||
if self.vendor == 'msvc':
|
||||
# Don't omit frame pointer
|
||||
self.compiler.AddToListVar('CFLAGS', '/Oy-')
|
||||
|
||||
#Platform-specifics
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
self.compiler.AddToListVar('CDEFINES', '_LINUX')
|
||||
self.compiler.AddToListVar('CDEFINES', 'POSIX')
|
||||
if self.vendor == 'gcc':
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
|
||||
if self.vendor == 'clang':
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
self.compiler.AddToListVar('CDEFINES', 'OSX')
|
||||
self.compiler.AddToListVar('CDEFINES', '_OSX')
|
||||
self.compiler.AddToListVar('CDEFINES', 'POSIX')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
|
||||
self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
|
||||
|
||||
# For OS X dylib versioning
|
||||
import re
|
||||
productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
|
||||
productContents = productFile.read()
|
||||
productFile.close()
|
||||
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||
if m == None:
|
||||
self.version = '1.0.0'
|
||||
else:
|
||||
major, minor, release = m.groups()
|
||||
self.version = '{0}.{1}.{2}'.format(major, minor, release)
|
||||
AMBuild.cache.CacheVariable('version', self.version)
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
self.compiler.AddToListVar('CDEFINES', 'WIN32')
|
||||
self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
|
||||
|
||||
#Finish up
|
||||
self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
|
||||
self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
|
||||
self.compiler.AddToListVar('CINCLUDES',
|
||||
os.path.join(AMBuild.outputFolder, 'includes'))
|
||||
self.compiler.ToConfig(AMBuild, 'compiler')
|
||||
AMBuild.cache.CacheVariable('vendor', self.vendor)
|
||||
self.targetMap = { }
|
||||
AMBuild.cache.CacheVariable('targetMap', self.targetMap)
|
||||
else:
|
||||
self.sdkInfo = AMBuild.cache['sdkInfo']
|
||||
self.compiler.FromConfig(AMBuild, 'compiler')
|
||||
self.targetMap = AMBuild.cache['targetMap']
|
||||
self.hasMySql = AMBuild.cache['hasMySql']
|
||||
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
|
||||
self.compiler.AddToListVar('RCINCLUDES',
|
||||
os.path.join(AMBuild.outputFolder, 'includes'))
|
||||
self.mmsPath = AMBuild.cache['MMSOURCE110']
|
||||
|
||||
def DefaultCompiler(self):
|
||||
return self.compiler.Clone()
|
||||
|
||||
def JobMatters(self, jobname):
|
||||
file = sys._getframe().f_code.co_filename
|
||||
if AMBuild.mode == 'config':
|
||||
self.targetMap[jobname] = file
|
||||
return True
|
||||
if len(AMBuild.args) == 0:
|
||||
return True
|
||||
if not jobname in AMBuild.args:
|
||||
return False
|
||||
|
||||
def DefaultExtCompiler(self, path):
|
||||
compiler = self.DefaultCompiler()
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
|
||||
return compiler
|
||||
|
||||
def AutoVersion(self, folder, binary):
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
|
||||
binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
|
||||
elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
|
||||
binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
|
||||
binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
|
||||
else:
|
||||
return
|
||||
|
||||
def ExtractDebugInfo(self, job, binary):
|
||||
src = os.path.join('..', AMBuild.outputFolder, job.workFolder, binary.binaryFile)
|
||||
job.AddCommand(ExtractDebugInfoCommand(binary, src))
|
||||
|
||||
def PreSetupHL2Job(self, job, builder, sdk):
|
||||
info = self.sdkInfo[sdk]
|
||||
sdkPath = AMBuild.cache[info['sdk']]
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
if sdk == 'ep1':
|
||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
||||
else:
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
||||
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
|
||||
if sdk in ['css', 'hl2dm', 'dods', 'tf2', 'l4d2']:
|
||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib_srv.so', 'libtier0_srv.so']
|
||||
for lib in libs:
|
||||
link = os.path.join(workFolder, lib)
|
||||
target = os.path.join(staticLibs, lib)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
elif sdk in ['l4d', 'nd', 'csgo']:
|
||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']
|
||||
if sdk == 'csgo':
|
||||
libs.append('interfaces_i486.a')
|
||||
for lib in libs:
|
||||
link = os.path.join(workFolder, lib)
|
||||
target = os.path.join(staticLibs, lib)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
else:
|
||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']
|
||||
for lib in libs:
|
||||
link = os.path.join(workFolder, lib)
|
||||
target = os.path.join(staticLibs, lib)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'mac')
|
||||
workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
|
||||
libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']
|
||||
if sdk == 'csgo':
|
||||
libs.append('interfaces_i486.a')
|
||||
for lib in libs:
|
||||
link = os.path.join(workFolder, lib)
|
||||
target = os.path.join(staticLibs, lib)
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
job.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||
if sdk in ['swarm', 'csgo']:
|
||||
libs.append('interfaces')
|
||||
for lib in libs:
|
||||
libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
|
||||
builder.RebuildIfNewer(libPath)
|
||||
builder['POSTLINKFLAGS'].append(libPath)
|
||||
|
||||
def PostSetupHL2Job(self, job, builder, sdk):
|
||||
if AMBuild.target['platform'] in ['linux', 'darwin']:
|
||||
builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
|
||||
if sdk == 'csgo':
|
||||
builder.AddObjectFiles(['interfaces_i486.a'])
|
||||
|
||||
def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
|
||||
compiler = self.DefaultExtCompiler(path)
|
||||
|
||||
mms = 'core'
|
||||
if sdk == 'ep1':
|
||||
mms += oldMms
|
||||
|
||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
|
||||
|
||||
info = self.possibleSdks
|
||||
compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
|
||||
|
||||
# We don't build for Portal 2 (yet?, ever?), but using this define in code as
|
||||
# it saves trouble if we ever need to
|
||||
compiler['CDEFINES'].append('SE_PORTAL2=14')
|
||||
|
||||
paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
|
||||
['public', 'tier0'], ['public', 'tier1']]
|
||||
if sdk == 'ep1' or sdk == 'darkm':
|
||||
paths.append(['public', 'dlls'])
|
||||
paths.append(['game_shared'])
|
||||
else:
|
||||
paths.append(['public', 'game', 'server'])
|
||||
paths.append(['public', 'toolframework'])
|
||||
paths.append(['game', 'shared'])
|
||||
paths.append(['common'])
|
||||
|
||||
info = self.sdkInfo[sdk]
|
||||
sdkPath = AMBuild.cache[info['sdk']]
|
||||
|
||||
compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
|
||||
|
||||
if sdk in ['swarm','csgo']:
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
|
||||
else:
|
||||
compiler['CDEFINES'].extend(['COMPILER_GCC'])
|
||||
|
||||
if sdk == 'ep1':
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
staticLibs = os.path.join(sdkPath, 'linux_sdk')
|
||||
else:
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'linux')
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
staticLibs = os.path.join(sdkPath, 'lib', 'mac')
|
||||
|
||||
for i in paths:
|
||||
compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
|
||||
|
||||
if not noLink:
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['-lm']
|
||||
if sdk in ['css', 'hl2dm', 'dods', 'tf2', 'l4d2']:
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0_srv.so']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib_srv.so']
|
||||
elif sdk in ['l4d', 'nd', 'csgo']:
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
|
||||
else:
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
|
||||
compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
|
||||
|
||||
return compiler
|
||||
|
||||
def ResolveEnvPath(self, env, defaultDir):
|
||||
if env in os.environ:
|
||||
path = os.environ[env]
|
||||
if os.path.isdir(path):
|
||||
return path
|
||||
else:
|
||||
head = os.getcwd()
|
||||
oldhead = None
|
||||
while head != None and head != oldhead:
|
||||
path = os.path.join(head, defaultDir)
|
||||
if os.path.isdir(path):
|
||||
return path
|
||||
oldhead = head
|
||||
head, tail = os.path.split(head)
|
||||
return None
|
||||
|
||||
sm = SM()
|
||||
globals = {
|
||||
'SM': sm
|
||||
}
|
||||
|
||||
AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
|
||||
|
||||
FileList = [
|
||||
['loader', 'AMBuilder'],
|
||||
['core', 'AMBuilder'],
|
||||
['core', 'logic', 'AMBuilder'],
|
||||
['extensions', 'bintools', 'AMBuilder'],
|
||||
['extensions', 'clientprefs', 'AMBuilder'],
|
||||
['extensions', 'cstrike', 'AMBuilder'],
|
||||
['extensions', 'curl', 'AMBuilder'],
|
||||
['extensions', 'geoip', 'AMBuilder'],
|
||||
['extensions', 'mysql', 'AMBuilder'],
|
||||
['extensions', 'sdkhooks', 'AMBuilder'],
|
||||
['extensions', 'sdktools', 'AMBuilder'],
|
||||
['extensions', 'topmenus', 'AMBuilder'],
|
||||
['extensions', 'updater', 'AMBuilder'],
|
||||
['extensions', 'sqlite', 'AMBuilder'],
|
||||
['extensions', 'regex', 'AMBuilder'],
|
||||
['extensions', 'tf2', 'AMBuilder'],
|
||||
['sourcepawn', 'jit', 'AMBuilder'],
|
||||
['sourcepawn', 'compiler', 'AMBuilder'],
|
||||
['plugins', 'AMBuilder'],
|
||||
['tools', 'buildbot', 'PackageScript'],
|
||||
['tools', 'buildbot', 'BreakpadSymbols']
|
||||
]
|
||||
|
||||
if not sm.hasMySql:
|
||||
FileList.remove(['extensions', 'mysql', 'AMBuilder'])
|
||||
|
||||
for parts in FileList:
|
||||
AMBuild.Include(os.path.join(*parts), globals)
|
||||
|
||||
+3
-19
@@ -1,21 +1,5 @@
|
||||
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.
|
||||
|
||||
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
|
||||
http://wiki.alliedmods.net/Mercurial_Tutorial#Identity
|
||||
|
||||
+882
@@ -0,0 +1,882 @@
|
||||
SourceMod Changelog
|
||||
|
||||
SourceMod 1.5.2 [2013-10-29]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated gamedata support for TF2, CS:S, CS:GO, and HL2:DM.
|
||||
- Fixed crash from regression in SDKTools SetClientListening hook refcounting (bug 5956) (KyleS).
|
||||
- Fixed potential crash when having maps with format characters in name.
|
||||
- Fixed some nextmap issues with long map names.
|
||||
- SDKTools no longer requires gamedata for sm_dump_datamaps on TF2, CS:S, HL2:DM, and DoD:S (bug 5968).
|
||||
|
||||
Developer Changes:
|
||||
- Updated TFCond and TF custom dmg enums.
|
||||
- Updated TF2 critical hit detection logic in TF2_OnCalcIsAttackCritical to handle more cases, including when criticals are disabled (bug 5894).
|
||||
- Fixed GetEngineVersion native returning a bad value when running on MM:S 1.9.x or earlier (bug 5697).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.5.1 [2013-09-10]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated gamedata support for TF2.
|
||||
- Added missing DispatchKeyValue gamedata for HL2 CTF (bug 5114) (peace-maker).
|
||||
- Fixed translations not being loaded if identifier was not two or three characters (fixes Portuguese) (bug 5888).
|
||||
- Fixed runoff voting occurring when receiving the exact number of required votes (bug 5890).
|
||||
- Fixed reserve slot plugin hiding too many slots on Orangebox gamesif SourceTV and/or Replay are present (bug 5499).
|
||||
- Fixed some crashes in TF2 and unexpected behavior in all games with SDKHook_TakeDamage due to uninitialized var.
|
||||
- Fixed attempted triggers from gagged users displaying in chat (bug 5918).
|
||||
- Fixed errors in Italian translation (Oktober).
|
||||
- Added Norwegian translation (checkster).
|
||||
|
||||
Developer Changes:
|
||||
- Added CS_UpdateClientModel native to CStrike extension for CS:S and CS:GO (bug 5905) (Drifter).
|
||||
- Fixed setting weapon param in SDKHook_TakeDamage overwriting attacker instead of setting weapon (bug 5911) (KyleS)
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.5.0 [2013-08-25]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.5.0_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added support for Counter-Strike: Global Offensive (bug 5299, bug 5579).
|
||||
- Split CS:S, TF2, DoD:S, HL2:DM, and ND to separate binaries (bug 5370, bug 5813).
|
||||
- Added support for runoff voting in mapchooser (bug 4218).
|
||||
- Added option to require Steam validation before granting admin access (bug 4837) (VoiDeD).
|
||||
- Added localization support for many more core and base plugin messages (bug 5120, bug 5146).
|
||||
- Added the ability to override RegConsoleCommand-created commands (bug 5199).
|
||||
- Added support for "fuzzy" (partial) map names in map-related natives and cmds for L4D and later (bug 5599).
|
||||
- Updated Reserved Slots to use max humans as max count (bug 5444).
|
||||
- Added support for custom maxitems on radio menus (bug 5371).
|
||||
- Improved console config editing (bug 5470).
|
||||
- Increased map name buffer sizes in mapchooser to better account for nested maps (bug 5609) (Peace-Maker).
|
||||
- Fixed JIT conflicts with SELinux (bug 5581).
|
||||
- Added logged error when PlayerRunCommand offset lookup fails (bug 5535) (GoD-Tony).
|
||||
- Fixed double print when sending psay to self (bug 5649) (Peace-Maker).
|
||||
- Fixed check against uninitialized string in extension loader (bug 5546) (KyleS).
|
||||
- Fixed possible runtime errors in basetriggers for not-ingame clients (bug 5191) (Peace-Maker).
|
||||
- Check all possible mapcycle paths on newer orangebox games (bug 5719).
|
||||
- Fixed ReadMapList not seeing maps in all valve search paths (bug 5715) (VoiDeD).
|
||||
- Fixed typo in too-many-params native error message (Peace-Maker).
|
||||
- Fixed various issues in clientprefs (bug 5538) (KyleS).
|
||||
- Removed debug printout from PerformGravity (bug 5679) (KyleS).
|
||||
- Fixed broken translating in some plugins and natives (bug 5612) (KyleS).
|
||||
- Fixed issues with COMMAND_FILTER_NO_BOTS and @bots multi-target.
|
||||
- Fixed crash in SDKHooks when throwing bad ent type error on logical ent (KyleS).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added support for CS:GO to the CStrike extension (bug 5299) (Drifter).
|
||||
- Added support for new protobuf usermessages used in newer games (bug 5579, bug 5588, bug 5590, bug 5633).
|
||||
- Added latest SDKHooks version as first-party extension.
|
||||
- Updated SQLite to version 3.7.15.1 (bug 5235).
|
||||
- Added natives for changing team score and mvp stars on CSS/CSGO (bug 5295) (Drifter).
|
||||
- Added global pre and post forwards for client chat (bug 5394) (KyleS).
|
||||
- Added TF2_CanPlayerTeleport forward to the TF2 game extension (bug 5283) (VoiDeD).
|
||||
- Added GetEntityAddress native (bug 5269) (ProdigySim).
|
||||
- Added more parameters to PlayerRunCommand forward (bug 5346) (GoD-Tony).
|
||||
- Added forwards to basecomm plugin (bug 5466) (Drifter).
|
||||
- Added symbol lookup support to gamedata on Windows (bug 5511) (GoD-Tony).
|
||||
- Exposed GetLanguageInfo in ITranslator interface (bug 5249) (VoiDeD).
|
||||
- Increase maximum .sp line length to 4095 characters. (bug 5347) (theY4Kman).
|
||||
- Improved netprop dump output (bug 5471).
|
||||
- Added int64 typename to netprop dumps (bug 5655).
|
||||
- Added GetMaxHumanPlayers native exposing IServerGameClients func (bug 5551).
|
||||
- Added WeaponIDToAlias native to CStrike extension (bug 5460) (KyleS).
|
||||
- Fixed OnLibraryAdded/Removed not being called in all plugins (bug 5431).
|
||||
- Made thread worker processing limits configurable at runtime (bug 5326).
|
||||
- Added support in TF2 ext for detection of player conds >= 64 (bug 5565).
|
||||
- Updated button defines in entity_prop_stocks (bug 5564).
|
||||
- Added GetPlayerResourceEntity to SDKTools to replace old, semi-broken TF2-only version (bug 5491).
|
||||
- Exposed third parameter of TF2's AddCond in TF2_AddCondition (bug 5641) (FlaminSarge).
|
||||
- Added GetSteamAccountID function to IPlayerHelpers and native for sp (bug 5548) (KyleS).
|
||||
- Added ISDKHooks interface with entity listeners (bug 5602) (GoD-Tony).
|
||||
- Added file upload support to webternet extension.
|
||||
- Added more alternative names for TFClass_Heavy (bug 5338) (Afronanny).
|
||||
- Throw error instead of crash when calling SetTeamScore between maps (bug 5718) (KyleS).
|
||||
- Fixed clients not being marked as in kick queue in some cases (bug 5746) (SystematicMania).
|
||||
- Made compile.sh set working dir to own dir (bug 5710) (KyleS).
|
||||
- Added CS_IsValidWeaponID native and validity checks to other natives (bug 5566) (Drifter).
|
||||
- Numerous code documentation fixups (bug 5720) (Tsunami).
|
||||
- Fixed cmd listener callback return behavior to match func doc (bug 5882).
|
||||
|
||||
Internal Changes:
|
||||
|
||||
- Fixed handle misuse in clientprefs plugin (bug 5805) (KyleS).
|
||||
- Removed call to getchar() in debug build of compiler (bug 5626) (KyleS).
|
||||
- Fixed instability issues with cloned handles (bug 5245, bug 5240) (KyleS).
|
||||
- Changed extension unload order to avoid exposing finalization window (bug 5556) (KyleS).
|
||||
- Call OnPluginEnd before finalizer hooks have run (bug 4519).
|
||||
- Fixed potential for reading out of library bounds in MemoryUtils::FindPattern.
|
||||
- Fixed typo in TF2 ext asm.c causing accidental assignment instead of compare.
|
||||
- Overhauled versioning information (bug 5453).
|
||||
- Changed from RemoveEdict to using the Kill input for TF2_RemoveWeapon.
|
||||
- Fixed accidental assignment in each of SDKTools and sp compiler (bug 5745) (KyleS).
|
||||
- Fixed potential deadlock in HandleSystem::TryAndFreeSomeHandles (bug 5665) (KyleS).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.4.7 [2013-02-06]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.7_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM).
|
||||
- Updated gamedata for Left 4 Dead 2, Nuclear Dawn, No More Room in Hell, Zombie Panic Source, CSPromod, GoldenEye Source, Synergy, The Hidden, and PVKII.
|
||||
- Added system to block malware or illegal plugins (bug 5289).
|
||||
- Fixed a potential crash when a bad entity index is passed to certain functions (bug 5539) (KyleS).
|
||||
- Added an error message for when auto plugin configs fail to be created due to write error (bug 5465) (Drifter).
|
||||
- Fixed an issue where a malformed plugin could cause crashes (bug 5478).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new values to the TFCond TF2 conditions enum (bug 5537) (FlaminSarge).
|
||||
- Updated TFHoliday TF2 holidays enum (bug 5526) (Powerlord).
|
||||
- Fixed regression in SourceMod 1.3.0 causing GetEntPropEnt, GetEntDataEnt2, and GameRules_GetPropEnt to possibly return stale (incorrect) entity indexes in place of -1.
|
||||
- Added support for < 32-bit unsigned sign extension to GameRules_GetProp lookup (already in GetEntProp since SM 1.4.0).
|
||||
- Fixed < 32-bit unsigned sign extension in GetEntProp not being applied for array prop elements (bug 5591).
|
||||
- Fixed value size auto-detection in GetEntProp and GameRules_GetProp for ep2v's new SPROP_VARINT sendprops.
|
||||
- Fixed Sort_Random sort type not including first value in array sorting functions (bug 4292) (Peace-Maker).
|
||||
- Fixed GameRules_SetPropVector writing data to unexpected addresses instead of to the gamerules proxy entity (bug 5592) (ProdigySim).
|
||||
- Fixed VoteMenuToAll stock adding bots to list (bug 5253 (VoiDeD).
|
||||
|
||||
----------------------------------------------------------
|
||||
SourceMod 1.4.6 [2012-09-04]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.6_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Fixed extraneous errors resulting from a bug in 1.4.5.
|
||||
|
||||
----------------------------------------------------------
|
||||
|
||||
SourceMod 1.4.5 [2012-09-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.5_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated Nuclear Dawn, Dino D-Day, and Zombie Panic gamedata.
|
||||
- Added compatibility for running on Metamod:Source 1.9.0.
|
||||
- Fixed very minor memory leaks in CStrike extension (bug 5456) (KyleS).
|
||||
- Fixed crash from plugins accessing netprops too early (bug 5297) (KyleS).
|
||||
- Fixed crash from plugins trying to access nested datadesc members (bug 5446).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new TF2 weapon and custom dmg defines.
|
||||
- Added new TF2 TFHoliday value (bug 5436) (Powerlord).
|
||||
- Fixed IClientListener::InterceptClientConnect not being able to properly block connections (bug 5461) (PimpinJuice).
|
||||
- Fixed PrepSDKCall_SetSignature native not working with symbol names on L4D2 linux (bug 5440).
|
||||
- Fixed resolution of GetProfilerTime native on non-Windows platforms.
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.4 [2012-07-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.4_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated Nuclear Dawn gamedata.
|
||||
- Fixed a crash that could occur when selecting an option on a clientprefs prefab menu (bug 5374).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new TF2 weapon and custom dmg defines.
|
||||
- Added new TF2 TFHoliday value (bug 5364) (Powerlord).
|
||||
- Updated sample extension to properly fill ninvoke with INativeInvoker ptr (bug 5340) (Afronanny).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.3 [2012-06-09]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.3_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Made clientprefs attempt to reconnect to the database on map change (bug 4745).
|
||||
- Log functions now respect sv_logecho (bug 5135).
|
||||
- Fixed client console vote output (bug 5290, bug 5205) (FlaminSarge).
|
||||
- Fixed error when reloading dependant plugins using aliased natives (bug 5302).
|
||||
- Fixed intermittent crash when looking for an invalid signature (bug 5301).
|
||||
- Fixed possible crash when reloading a plugin with an invalid binary (bug 5288).
|
||||
- Exposed extensions list to clients (bug 5221) (VoiDeD).
|
||||
- Fixed intermittent crashes in clientprefs (bug 4660).
|
||||
- Fixed crash when passing an invalid entity reference to ReferenceToEntity (bug 5330).
|
||||
- Fixed cstrike extension crash on shutdown (bug 5328).
|
||||
- Lowered threading API think time to 20ms, making threaded MySQL queries complete faster (bug 4733).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Fixed client serials not being unique on Windows (bug 5285).
|
||||
- Fixed broken SourceTV detection on L4D1 (bug 5216).
|
||||
- Fixed Float negation operator (bug 5292).
|
||||
- Updated TF2 condition defines (bug 5259) (FlaminSarge).
|
||||
- Adding missing SetMenuNoVoteButton native declaration (bug 4522) (GoD-Tony).
|
||||
- Fixed erroneous const-qualification of name param of GetAdminUsername (bug 5267).
|
||||
- Added GetGameTickCount native (bug 5209) (GoD-Tony).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.2 [2011-04-13]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Fixed regression in SourceMod 1.4.0 causing SM to cause load errors on The Ship (bug 5216).
|
||||
- Fixed toggling and player lag issues with sm_drug command (bugs 5217, 5218) (FlaminSarge).
|
||||
|
||||
Developer Changes:
|
||||
- Updated TF2-specific defines and enums (bug 5194).
|
||||
- Fixed StoreToAddress always writing 32 bits and throwing an error (bug 5248) (ProdigySim).
|
||||
- Fixed crash with StoreToAddress if memory wasn't writable (bug 5252) (Dr!fter).
|
||||
- Fixed return value of VoteMenuToAll (bug 5254) (VoiDeD).
|
||||
- Fixed bug in command lower-casing API guarantee
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.1 [2011-12-07]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Added gamedata for Adrenaline Gamer 2 and No More Room in Hell.
|
||||
- Fixed "not connected" error in reserve slots plugin (bug 5158) (ostrel).
|
||||
- Fixed ff trigger output printing to all in triggerer's language (rather than viewer's language) (bug 5161).
|
||||
- Fixed typo in one of basebans ban reasons (bug 5188).
|
||||
- Fixed formatting error in Swedish "Vote Count" phrase (bug 5174).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Fixed sp MaxClients not being updated on map changes after load (bug 5160).
|
||||
- Removed GLIBC_2.7 dependency from spcomp.
|
||||
- Increased buffer for sm_rcon command to fit larger responses (bug 5169).
|
||||
- BaseComm now properly registers a library allowing it to be required by other plugins (bug 5156).
|
||||
- Fixed TFHoliday enum values (bug 5155).
|
||||
- Updated TF2_OnIsHolidayActive ret behavior to match doc (bug 5155).
|
||||
- Added new TF2 deathflag and dmg custom defines (bug 5157).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.4.0 [2011-10-28]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.4.0_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added support for Max OS X (bug 4392).
|
||||
- Added support for Bloody Good Time (bug 4780).
|
||||
- Added support for E.Y.E Divine Cybermancy (bug 5035).
|
||||
- Added gamedata for Nuclear Dawn.
|
||||
- Added gamedata for International Online Soccer: Source (bug 5019).
|
||||
- Added gamedata for Half-Life 2 Capture the Flag (bug 5114).
|
||||
- Updated mapchooser and other base plugins with Nuclear Dawn specific fixes (bug 5117).
|
||||
- Fixed ServerLang value not being read properly on startup (bug 4675).
|
||||
- Added support for aliases in languages.cfg (bug 4858).
|
||||
- Added output display to sm_rcon command (bug 5018).
|
||||
- Flood protection bypass access can now be overridden with command name sm_flood_access (bug 4584).
|
||||
- Added a reset argument to sm cvars command to revset cvar values to default (bug 5043).
|
||||
- Fixed incorrect language identifiers for Chinese (both Trad. and Simplified) and Brazilian Portuguese not matching cl_language values (bug 5067).
|
||||
- Added translation support for Bulgarian (bg).
|
||||
- Fixed incorrect number of slots being hidden for reserve with sm_hideslots on Source 2009 with SourceTV or replay (bug 5094).
|
||||
- sm_hideslots changes now take effect immediately instead of waiting until a client joins or leaves (bug 5094).
|
||||
- Fixed sv_visiblemaxplayers getting stuck at previous max clients in some cases with reserves and SourceTV or replay (bug 5094).
|
||||
- Removed error logging if an optional extension is not found (bug 5112).
|
||||
- Fixed bots with semicolon in name being unkickable (bug 5120).
|
||||
- Changed strings in ice-related funcommands to be translatable (bug 4540).
|
||||
- Changed Bintools extension to use a single build for every engine (bug 4548).
|
||||
|
||||
Developer Changes:
|
||||
- Provided native interface for basecomm (bug 2594).
|
||||
- Client language detection is too late. (bug 3714) (Tony A. "GoD-Tony").
|
||||
- Added ServerCommandEx native to execute server command and retrieve output (bug 3873).
|
||||
- Added ability to update clientprefs cookies values on clients not currently connected (bug 3882) (databomb).
|
||||
- Added library "matchmaking_ds" support to gamedata lookups (bug 4158).
|
||||
- Rooted menu handles to callbacks (bug 4353).
|
||||
- Fixed corner cases with ExplodeString (bug 4629). (Michael "LumiStance").
|
||||
- Fixed return omission with else-after-return (bug 4852).
|
||||
- Added OnConditionAdded and OnConditionRemoved forwards to TF2 extension (bug 4851).
|
||||
- Added new natives and forward to the cstrike extension (bug 4732, bug 4985) (Dr!fter).
|
||||
- Added WaitingForPlayers forwards to the TF2 extension (bug 4704) (CrimsonGT).
|
||||
- Updated and added more TF2 condition, weapon, and damagecustom defines (multiple bug#s).
|
||||
- Fixed TF2_RemoveCondition not always removing conditions (bug 4981).
|
||||
- Fixed MaxClients not being updated correctly in some places with SourceTV or replay active (bug 4986).
|
||||
- Fixed some vars not being marked for init on first compile pass (bug 4643).
|
||||
- Increased symbol name limit to 63 characters (bug 4564) (javalia).
|
||||
- Fixed crash when dynamic arrays run out of memory (bug 4632).
|
||||
- Fixed a crash that could happen from looking up out-of-bounds edict or entity indexes (bug 5080).
|
||||
- Fixed client serials not getting cleared on disconnect (bug 5121).
|
||||
- Added error on declaring arrays that the compiler is too buggy to handle (bug 4977).
|
||||
- Removed reliance on gamedata for multiple SDKTools functions in ep2 and later (bug 4899).
|
||||
- Added InvalidateClient and ReconnectClient natives to SDKTools (bug 4931) (Brian "Afronanny" Simon).
|
||||
- Added ability to lookup and set values on the gamerules class (bug 4983.
|
||||
- BaseComm now uses AddCommandListener for chat hooks (bug 4991).
|
||||
- Fixed shutdown bug in SDKTools (bug 5063).
|
||||
- Fixed MM-enabled extensions continuing to load after failing MM attach (bug 5042).
|
||||
- Added GetDistGainFromSoundLevel native to SDKTools (bug 5066) (javalia).
|
||||
- Added CheckAccess native to check an AdminId's command access (bug 5083).
|
||||
- Fixed GetEntProp not sign-extending unsigned values less than 32 bits (bug 5105).
|
||||
- Fixed crashing when calling CreateEntityByName or CreateFakeClient when no map is running (now errors) (bug 5119).
|
||||
- Fixed erring in kick function (e. bad translation) causing client to become unkickable until disconnect (bug 5120).
|
||||
- Fixed KickClientEx not immediately kicking client if client was in kick queue (bug 5120).
|
||||
- Added IsClientSourceTV and IsClientReplay natives (bug 5124).
|
||||
- Added support for getting and setting individual array elements with Get/Set EntProp functions (bug 4160).
|
||||
- Added support for threaded query handles to SQL_GetInsertId and SQL_GetAffectedRows (bug 4699) (Nephyrin).
|
||||
- Added a GetGameRules function to ISDKTools for extensions to easily get the GameRules class pointer (bug 4707).
|
||||
- Added GetMessageName to IUserMessages (bug 4573) (Zach "theY4Kman" Kanzler)
|
||||
- Added HintTextMsg to IGameHelpers (bug 4950).
|
||||
- Added ProcessTargetString simple filter API (bug 4404).
|
||||
- Moved much functionality from core bins to logic bin (bug 4406, bug 4402).
|
||||
- Fixed bogus asserts in sp compiler (bug 4486, bug 4487).
|
||||
- Greatly improved sp compiler performance (~5x overall speedup) (bug 3820, bug 4493, bug 4495).
|
||||
- Changed entity output detours to use CDetour (bug 4416).
|
||||
- Enhanced nominations API (bug 4677) (CrimsonGT).
|
||||
- Added Linux support for profiling natives (bug 4927).
|
||||
- Added a new ValveCallType that allows for arbitrary |this| parameters, as well as associated features in gamedata and for reading/writing memory (bug 3520) (Downtown1).
|
||||
- Updated TF2 extension to handle Valve's changes to the "holiday" system (bug 5150).
|
||||
|
||||
-----------------------------
|
||||
|
||||
SourceMod 1.3.8 [2011-06-23]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.8_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated support for various games, including Garry's Mod, Zombie Panic, and Dino D-Day.
|
||||
- Added gamedata for Eternal Silence.
|
||||
- Fixed libgcc_s.so.1 load error present on some systems (bug 4876).
|
||||
- Handle leak notices now print to error log (in addition fatal log) (bug 4929).
|
||||
- Translator now properly falls back on bad server language (bug 4861).
|
||||
- Fixed invalid client errors from bad MaxClients value when SourceTV is late-loaded (bug 4881).
|
||||
- Fixed crash on plugin unload when two commands exist with same name, different casing (bug 4698).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Updated TF2 condition defines (bug 4916).
|
||||
- Fixed var names and docs for TF2_MakeBleed native (bug 4928).
|
||||
- Removed compiler double include check (bug 4863).
|
||||
- Fixed plugin compile errors when using GetEntityClassname (bug 4798).
|
||||
|
||||
---------------------------
|
||||
|
||||
SourceMod 1.3.7 [2011-04-15]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.7_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||
- Updated support for various games, including Zombie Panic, CS ProMod, Empires, and GoldenEye: Source.
|
||||
- Added gamedata for Dino D-Day.
|
||||
- Fix precedence of voice mute flag versus specific client overrides (bug 4826).
|
||||
- Fix mistaken unhooking of voice hooks (bug 4804).
|
||||
- Fixed graphical glitches with funcommands effects in L4D1 (bug 3486).
|
||||
- Fixed bug in nominations that could cause "Unknown command" error (bug 4797).
|
||||
- Removed tv_enable hook to fix rare max client count issue (bug 4791).
|
||||
- Added missing unhooking of ClientConnect in PlayerManager (bug 4749).
|
||||
- Fixed sm_rtv printing "unknown command" (bug 4730).
|
||||
- Fixed voting crash when client console, chat, and SourceTV are enabled (bug 4676).
|
||||
- Fixed CDetour crash in TF2 extension when last plugin using forward is unloaded (bug 4713).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- SetEntProp now marks edict state as changed (bug 4855).
|
||||
- Added GetEntityClassname stock (bug 4798).
|
||||
- Fix compiler hanging when #including a directory (bug 4822).
|
||||
- Added GetEntityFlags and SetEntityFlags natives for better cross-engine compatibility. (bug 4809).
|
||||
- Fixed ClientPrefs natives not being marked optional when REQUIRE_EXTENSIONS not defined (bug 4839).
|
||||
- Changed some instances of LogMessage to LogAction (bug 4649).
|
||||
- Added some new language natives (bug 4613).
|
||||
- Fixed SetTeamScore not updating score on client (bug 2736).
|
||||
- Raised MAXPLAYERS from 64 to 65 (bug 4490).
|
||||
- Added and updated many TF2-specific defines in tf2.inc and tf2_stocks.inc.
|
||||
- Fixed TF2_GetPlayerConditionFlags no longer necessarily returning all set flags (bug 4726).
|
||||
- Fixed profiler flush not clearing, added 'report' and 'clear' (bug 4674).
|
||||
- Fixed GetPlayerDecalFile crash on L4D and L4D2 (bug 4729).
|
||||
- Fixed TF2_OnGetHoliday detour no longer firing under all circumstances (bug 4700).
|
||||
- Added TF2_IsPlayerInDuel native to TF2 extension (bug 4695).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.6 [2010-10-31]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.6_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for latest Left 4 Dead 1 (bug 4681).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Updated TF2 custom kill defines (bug 4682).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.5 [2010-10-17]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.5_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Updated support for CS:S, Garry's Mod, DoD:S, TF2, HL2DM.
|
||||
- Added support for Firearms: Source (bug 4537).
|
||||
- Added support for Fistful of Frags (bug 3883).
|
||||
- Added support for Alien Swarm (bug 4530).
|
||||
- Fixed living players hearing dead players if alltalk is disabled while deadtalk is on (bug 4533, thanks Zach Callear).
|
||||
- Fixed timeleft not getting reset on Game_Commencing in CS:S (bug 4557).
|
||||
- Fixed PlayerRunCmd being hooked when not used (bug 3990).
|
||||
- Fixed errors and missing effects caused by missing sprites on L4D2 (bug 4512).
|
||||
- Fixed 'sm plugins' public command skipping plugins in recommended listing (bug 4501).
|
||||
- Fixed corruption with large database.cfg files (bug 4286).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added TF2 object stocks (bug 4536).
|
||||
- Added TF2_MakeBleed native to TF2 ext (bug 4542).
|
||||
- Added support for logical entities in Synergy (bug 4534).
|
||||
- Updated TF2 conditions enum and defines (bug 4526).
|
||||
- Fixed potential crash with IMemUtils::FindPattern on Linux (bug 4554).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.4 [2010-07-18]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.4_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Support for latest TF update (bug 4506).
|
||||
- Support for latest L4D2 update (bug 4509).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added FindFlagChar native (bug 3776).
|
||||
- Added GetConVarDefault native (bug 4502).
|
||||
- Added forward for TF's GetHoliday function (bug 4462).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.3 [2010-06-23]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.3_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added support for CS:S on Orange Box
|
||||
- Added gamedata for Resistance and Liberation (bug 4418).
|
||||
- Updated gamedata for SourceForts, Empires, Obsidian Conflict, Zombie Master.
|
||||
- Fixed memory corruption and leaks with some voice functionality (bug 4415).
|
||||
- Fixed UI bug in sm_motd (bug 4460).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added new player condition (TFCond_CritCola, bug 4447).
|
||||
- Fixed clientprefs deleting cookies twice in rare cases (bug 4412).
|
||||
- Fixed OnClientConnected forward not firing for bots (bug 4443).
|
||||
- Fixed sm_dump_datamaps crash (bug 4424).
|
||||
- Fixed switch case comparisons failing with large numbers (bug 4457).
|
||||
- Fixed rare crash in output hooks (bug 4422).
|
||||
- Fixed bug with dynamically sized arrays being sliced (bug 4428).
|
||||
- Fixed SendConVarValue() on TF2, DOD:S, L4D, and L4D2 (bug 4273).
|
||||
- Fixed TF2 natives not being marked optional (bug 4389).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.2 [2010-05-02]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.2_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Support for recent TF, DoD, and L4D2 updates (bug 4356, bug 4361, bug 4371, bug 4374, bug 4375).
|
||||
- Fixed rare crash when replicating cvars to clients (bug 4315).
|
||||
- Lots of extra game support for Insurgency, ZPS, CSProMod, PVKII, and FortressForever (thanks
|
||||
Nicholas "psychonic" hastings).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added TF functions for stunning, conditions, regeneration, and power play (bug 4166, bug 4331).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.1 [2010-02-09]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.1_Release_Notes
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added extended support for CSProMod (bug 4255).
|
||||
- Fixed client disconnect crash on many third party games (bug 4231).
|
||||
- Improved support for Battlegrounds 2 (bug 4146).
|
||||
- Improved support for Insurgency (bug 4180).
|
||||
- Improved support for Garry's Mod (bug 4230, bug 4268).
|
||||
- Improved support for Synergy (bug 4235).
|
||||
- Updated Day of Defeat support for 20010123 update (bug 4262).
|
||||
- Fixed Webternet extension not loading on Windows 2000 (bug 4234).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Fixed compiler complaints when using |any| tag on array arguments (bug 4274).
|
||||
- Fixed GetClientCookieTime not being exported (bug 4237).
|
||||
- Fixed potential crash in entity handling code (bug 4249).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.3.0 [2010-01-15]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.3.0_Release_Notes
|
||||
|
||||
Major Features:
|
||||
* Left 4 Dead 2 support
|
||||
* Non-networked entity support
|
||||
|
||||
User Changes:
|
||||
|
||||
- Added Left 4 Dead 2 support (bug 4075).
|
||||
- Added much richer voting progress feedback (bug 1997).
|
||||
- Improved support for various third-party games (Nicholas "psychonic" Hastings).
|
||||
- Added @spec target (bug 2718).
|
||||
- Added sm_resetcvar command (bug 3636).
|
||||
- Added "motd" chat trigger (bug 2694).
|
||||
- Updated GeoIP to OCT-2009.
|
||||
- Fixed rare map vote error (bug 3905).
|
||||
- Fixed small leak in the nominations plugin (bug 4104).
|
||||
- Fixed last client being excluded from some command effects (bug 3984).
|
||||
- Fixed crashes in plugin [|un|re]loading (bug 4034, bug 4038, bug 4044, bug 4153).
|
||||
- Special target "@me" is now filtered for certain statuses properly (bug 4000).
|
||||
- Improved non-admin to admin chat (bug 3844).
|
||||
- Removed "auto.*" extension folders (bug 3949).
|
||||
|
||||
Developer Changes:
|
||||
|
||||
- Added non-networked entity support (bug 2459).
|
||||
- Added improved random number generator (bug 3831).
|
||||
- Added GetClientCookieTime native (bug 3736).
|
||||
- Added AskPluginLoad2 callback (bug 3716).
|
||||
- Added PlayerRunCmd callback (bug 3289).
|
||||
- Added PointOutsideWorld native (bug 3906).
|
||||
- Added API for "blanket" command hooks (bug 4015).
|
||||
- Added ability to test for SourceMod features (bug 4021).
|
||||
- Added ability to change broadcast status on hooked events (bug 3886).
|
||||
- OnClientCommand no longer receives unconnected clients (bug 3732).
|
||||
- Fixed various bugs in client listening API (bug 3818).
|
||||
- Fixed crash in BanClient (bug 3912).
|
||||
- Fixed various crashes in self-removing callbacks (bug 4059).
|
||||
- Fixed rare HUD text crash on TF (bug 4016).
|
||||
- Fixed OnConfigsExecuted not running on EP1 games with large configs (bug 3828).
|
||||
- Fixed entity output hooks not working (bug 3988).
|
||||
- Gamedata folder matches are now case-insensitive (bug 3913).
|
||||
- Blocked plugins from hooking "sm" command (bug 4013).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.2.4 [2009-10-03]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.2.4_Release_Notes
|
||||
|
||||
- Updated for L4D changes (bugs 4032, 4033, 4035).
|
||||
- Updated GeoLite Country database for GeoIP extension.
|
||||
- Fixed crash when block-loading more than eight plugins (bug 4034).
|
||||
- Fixed rare crash in hudtext code on TF (bug 4016).
|
||||
- Fixed crash when reloading a blocked plugin failed (bug 4038).
|
||||
- Fixed Huntsman not firing critical callback on TF (bug 3927).
|
||||
- Registering the "sm" command no longer has any effect (bug 4013).
|
||||
- Fixed translation bug in extension API (bug 4010).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.2.3 [2009-08-28]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.2.3_Release_Notes
|
||||
|
||||
- Fix extension filename lookup. (bug 3975).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.2.2 [2009-08-28]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.2.2_Release_Notes
|
||||
|
||||
- Removed auto folders. (bug 3949).
|
||||
- Added PointOutsideWorld native to sdktools. (bug 3906).
|
||||
- Added "motd" chat trigger to basetriggers. (bug 2694).
|
||||
- Added manual extension reloading command to root console menu. (bug 3934)
|
||||
- Fixed 'list' type custom menu entries overwriting admin restrictions. (bug 3783).
|
||||
- Added sm_resetcvar command to basecommands. (bug 3636).
|
||||
- Updated gamedata for DOD:S. (bug 3948).
|
||||
- Updated gamedata for TF2. (bug 3948).
|
||||
- Added new .ep2v build config for valve OB based games. (bug 3948).
|
||||
- Fixed incorrect escaping in clientprefs SQLite queries. (bug 3904)
|
||||
- Updated gamedata for Synergy. (bug 3315).
|
||||
- Upgraded to pcre-7.9 (bug 3923).
|
||||
- Switched Insurgency chat printing to SayText. (bug 3738).
|
||||
- Updated gamedata for Insurgency. (bug 3511).
|
||||
- Updated gamedata for ZM. (bug 3746).
|
||||
- Updated gamedata for Empires. (bug 3500).
|
||||
- Updated gamedata for ZPS. (bug 3877).
|
||||
- Updated gamedata for AoC. (bug 3891).
|
||||
- Fixed RemovePlayerDisguise signature for TF2. (bug 3892).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.2.1 [2009-05-31]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.2.1_Release_Notes
|
||||
|
||||
- Updated SDKTools for latest Team Fortress update.
|
||||
- Added L4D handling to GuessSDKVersion() (bug 3842).
|
||||
- Updated Zombie Panic Source offsets (bug 3632).
|
||||
- Fixed crash when clientprefs saw disconnect from 64th client (bug 3821).
|
||||
- Fixed Plugin_Handled acting like a Stop in usermsg hooks (bug 3685).
|
||||
- Fixed early tv_enable causing crashes (bug 3766).
|
||||
- Fixed unhook event crash (bug 3814).
|
||||
- Fixed compiler reading uninitialized strings while processing varargs (bug 3811).
|
||||
- Fixed compiler choosing whether to emit stradjust.pri on dynamic arrays based on uninitialized memory (bug 3810).
|
||||
- Fixed Windows L4D CreateFakeClient signature (bug 3792).
|
||||
- Fixed sm_slap for EP1 games (bug 3768).
|
||||
- Fixed casting problems in TextParsers breaking TrimString for non-ASCII characters (bug 3800).
|
||||
- Fixed OnClientConnect rejectmsg handling, improved doc (bug 3690).
|
||||
- Fixed clientprefs not loading cookies for clients on late load (bug 3735).
|
||||
- Fixed GetCommandFlags on original engine games (bug 3759).
|
||||
- Fixed compiler asserting when returning a string literal (bug 3836).
|
||||
- Fixed compiler erroring when tagging functions for string return (bug 3837).
|
||||
- Fixed compiler not handling constant chained relational operators correctly (bug 3838).
|
||||
- Fixed revote bug and inflexibilities in RedrawClientVoteMenu (bug 3834).
|
||||
- Fixed auto update URL being set too late (bug 3699).
|
||||
- Disabled nextmap in Synergy and Dystopia (bug 3687, bug 3741).
|
||||
- Removed unnecessary SSE optimizations from msvc9 project files (bug 3756).
|
||||
- Removed short-lived tag system (bug 3751).
|
||||
- Removed the alive check from sm_rename. (bug 3698).
|
||||
- Switched FortressForever to Valve menus (bug 3819).
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.2.0 [2009-03-05]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.2.0_Release_Notes
|
||||
|
||||
Major Features:
|
||||
* Left 4 Dead Support
|
||||
* Dark Messiah Support
|
||||
* New and Improved Updater
|
||||
|
||||
Changes:
|
||||
|
||||
- Added Left 4 Dead support (bug 3414).
|
||||
- Added Dark Messiah game support (requires Metamod:Source 1.7.1 or higher).
|
||||
- Added sm_name command (bug 2150).
|
||||
- Added extension-level dynamic hooking to bintools (bug 2616).
|
||||
- Added client validation API to replace passing userids asynchronously.
|
||||
- Added cURL extension, available to other extensions (bug 3560).
|
||||
- Added parsing of custom gamedata files (bug 3644).
|
||||
- Added case insensitivity search to ReplaceString (bug 3639, Fyren).
|
||||
- Added more detail to certain player-oriented menu titles (bug 2740, Fyren).
|
||||
- Added sv_tags API (bug 3677).
|
||||
- Greatly improved admin-sql-prefetch performance for large tables (bug 3354, FLOOR_MASTER).
|
||||
- Exposed IServer address to extensions (bug 3545).
|
||||
- New gamedata organization; files are now smaller and per-game (bug 3546).
|
||||
- Split sound functions into a new plugin, sounds.smx.
|
||||
- Fixed slap and slay on Insurgency (bug 2560).
|
||||
- Fixed blank admins being created from invalid admin file lines (bug 3431).
|
||||
- Fixed basetriggers not working on Insurgency (bug 3497).
|
||||
- Fixed client preferences missing some clients (bug 3616).
|
||||
- Improved database fallback mechanism in clientprefs (bug 3564).
|
||||
- Improved timer handling in funcommands (bug 3498).
|
||||
- Improved compile.sh to take filenames (bug 3550, jonasfietz).
|
||||
- sm_kick now shows the kick reason when available.
|
||||
- Fixed MsgPostHook (ex MsgSentNotify) callbacks not firing on intercept hook (bug 3631).
|
||||
- Note: SourceMod now adds "sourcemod" to the sv_tags cvar.
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.1.2 [2009-02-26]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.1.2_Release_Notes
|
||||
|
||||
Changes:
|
||||
|
||||
- Fixed critical hits being permanently disabled (bug 2674)
|
||||
|
||||
----------------------------
|
||||
|
||||
SourceMod 1.1.1 [2009-02-25]
|
||||
|
||||
URL: http://wiki.alliedmods.net/SourceMod_1.1.1_Release_Notes
|
||||
|
||||
Changes:
|
||||
|
||||
- Added Age of Chivalry support (bug 3366, IceMatrix).
|
||||
- Added Obsidian Conflict support (bug 2699, The DOO).
|
||||
- Fixed compatibility issues with latest TF2 update.
|
||||
- Fixed crash when an event handler fired an event of the same name (bug 3468).
|
||||
- Fixed rare crash in the event manager on post hooks (bug 3548).
|
||||
- Fixed formatting error with zero precision floats (bug 3447).
|
||||
- Fixed various Insurgency offsets (bug 3544).
|
||||
- Fixed admin menu (topmenu) categories being selectable when not usable (bug 3256).
|
||||
- Fixed sm_sql_addgroup not working (bug 3578).
|
||||
- Fixed memory leak when events were hooked as EventHookMode_Post.
|
||||
- Fixed nextmap trigger showing wrong output with end-of-map voting disabled and sm_trigger_show set to zero (bug 3597, mr.e.unk).
|
||||
|
||||
----------------------------
|
||||
|
||||
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"
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
// "@Full Admins"
|
||||
//
|
||||
// You can also specify immunity values. Two examples:
|
||||
// "83:abcdefg" //Immunity is 83, flags are abcefgh
|
||||
// "83:abcdefgh" //Immunity is 83, flags are abcdefgh
|
||||
// "6:@Full Admins" //Immunity is 6, group is "Full Admins"
|
||||
//
|
||||
// Immunity values can be any number. An admin cannot target an admin with
|
||||
@@ -37,9 +37,9 @@
|
||||
////////////////////////////////
|
||||
// Examples: (do not put // in front of real lines, as // means 'comment')
|
||||
//
|
||||
// "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID, no immunity
|
||||
// "STEAM_0:1:16" "bce" //generic, kick, unban for this steam ID, no immunity
|
||||
// "!127.0.0.1" "99:z" //all permissions for this ip, immunity value is 99
|
||||
// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban
|
||||
// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, generic, kick
|
||||
//
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//This file unloads all plugins, re-loads a few "safe" ones, and then prevents
|
||||
//any more plugins from being loaded.
|
||||
sm plugins unload_all
|
||||
sm plugins load_unlock
|
||||
sm plugins load basebans.smx
|
||||
sm plugins load basecommands.smx
|
||||
sm plugins load admin-flatfile.smx
|
||||
|
||||
@@ -80,21 +80,21 @@ sm_reserve_type 0
|
||||
sm_reserved_slots 0
|
||||
|
||||
// Specifies whether or not reserved slots will be hidden (subtracted from max
|
||||
// slot count). Valid values are 0 (visible) or 1 (hidden).
|
||||
// slot count). Valid values are 0 (Visible) or 1 (Hidden).
|
||||
// --
|
||||
// Requires: reservedslots.smx
|
||||
// Default: 0
|
||||
sm_hide_slots 0
|
||||
|
||||
// Specifies whether or not non-admins can send messages to admins using
|
||||
// say_team @<message>. Valid values are 0 (disabled) or 1 (enabled)
|
||||
// say_team @<message>. Valid values are 0 (Disabled) or 1 (Enabled)
|
||||
// --
|
||||
// Requires: basechat.smx
|
||||
// Default: 1
|
||||
sm_chat_mode 1
|
||||
|
||||
// Specifies whether or not "timeleft" will automaticly be triggered every
|
||||
// x seconds. Valid values are 0 (disabled) to 1800 seconds.
|
||||
// x seconds. Valid values are 0 (Disabled) to 1800 seconds.
|
||||
// --
|
||||
// Requires: basetriggers.smx
|
||||
// Default: 0
|
||||
@@ -107,3 +107,28 @@ sm_timeleft_interval 0
|
||||
// Requires: basetriggers.smx
|
||||
// Default: 1
|
||||
sm_trigger_show 1
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// "hint" box (near the bottom of the screen in most games).
|
||||
// Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_hintbox 0
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// chat area. Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_chat 0
|
||||
|
||||
// Specifies whether or not to display vote progress in the server console.
|
||||
// Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_console 0
|
||||
|
||||
// Specifies whether or not to display vote progress to clients in the
|
||||
// client console. Valid values are 0 (Disabled) or 1 (Enabled).
|
||||
// --
|
||||
// Default: 0
|
||||
sm_vote_progress_client_console 0
|
||||
|
||||
+45
-8
@@ -4,14 +4,6 @@
|
||||
*/
|
||||
"Core"
|
||||
{
|
||||
/**
|
||||
* Relative path to SourceMod's base directory. This is relative to the game/mod directory.
|
||||
* Only change this if you have installed SourceMod in a non-default location.
|
||||
*
|
||||
* The default value is "addons/sourcemod"
|
||||
*/
|
||||
"BasePath" "addons/sourcemod"
|
||||
|
||||
/**
|
||||
* This option determines if SourceMod logging is enabled.
|
||||
*
|
||||
@@ -88,4 +80,49 @@
|
||||
* "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"
|
||||
|
||||
/**
|
||||
* URL to use for retrieving update information.
|
||||
* SSL is not yet supported.
|
||||
*/
|
||||
"AutoUpdateURL" "http://update.sourcemod.net/update/"
|
||||
|
||||
/**
|
||||
* Whether to show debug spew.
|
||||
* Currently this will log details about the gamedata updating process.
|
||||
*/
|
||||
"DebugSpew" "no"
|
||||
|
||||
/**
|
||||
* If set to yes, SourceMod will validate steamid auth strings with the Steam backend before giving out admin access.
|
||||
* This can prevent malicious users from impersonating admins with stolen Steam apptickets.
|
||||
* If Steam is down, admins will not be authenticated until Steam comes back up.
|
||||
* This option increases the security of your server, but is still experimental.
|
||||
*/
|
||||
"SteamAuthstringValidation" "no"
|
||||
|
||||
/**
|
||||
* Enables or disables whether SourceMod blocks known or potentially malicious plugins from loading.
|
||||
* It is STRONGLY advised that this is left enabled, there have been cases in the past with plugins that
|
||||
* allow anyone to delete files on the server, gain full rcon control, etc.
|
||||
*
|
||||
* "yes" - Block malware or illegal plugins from loading (default)
|
||||
* "no" - Warn about malware or illegal plugins loading
|
||||
*/
|
||||
"BlockBadPlugins" "yes"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
{
|
||||
"driver_default" "mysql"
|
||||
|
||||
// When specifying "host", you may use an IP address, a hostname, or a socket file path
|
||||
|
||||
"default"
|
||||
{
|
||||
"driver" "default"
|
||||
@@ -18,4 +20,15 @@
|
||||
"driver" "sqlite"
|
||||
"database" "sourcemod-local"
|
||||
}
|
||||
|
||||
"clientprefs"
|
||||
{
|
||||
"driver" "sqlite"
|
||||
"host" "localhost"
|
||||
"database" "clientprefs-sqlite"
|
||||
"user" "root"
|
||||
"pass" ""
|
||||
//"timeout" "0"
|
||||
//"port" "0"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,4 @@
|
||||
"Languages"
|
||||
{
|
||||
"en" "English"
|
||||
"es" "Español"
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
"target" "default"
|
||||
}
|
||||
|
||||
/* For the "randomcycle" plugin */
|
||||
"rockthevote"
|
||||
/* 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)
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet:
|
||||
import sys
|
||||
import ambuild.runner as runner
|
||||
|
||||
run = runner.Runner()
|
||||
run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
help='Enable debugging symbols')
|
||||
run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||
help='Enable optimization')
|
||||
run.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
|
||||
help='Disable building MySQL extension')
|
||||
run.options.add_option('-s', '--sdks', default='all', dest='sdks',
|
||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
||||
'comma-delimited list of engine names (default: %default)')
|
||||
run.Configure(sys.path[0])
|
||||
+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
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
from ambuild.command import SymlinkCommand
|
||||
|
||||
for i in SM.sdkInfo:
|
||||
sdk = SM.sdkInfo[i]
|
||||
if AMBuild.target['platform'] not in sdk['platform']:
|
||||
continue
|
||||
|
||||
name = 'sourcemod.' + sdk['ext']
|
||||
|
||||
compiler = SM.DefaultHL2Compiler('core', i)
|
||||
|
||||
if i == 'csgo':
|
||||
# Protobuf 2.3 headers have some signed/unsigned compares. I believe that it's fixed in later versions, but Valve.
|
||||
if isinstance(compiler.cxx, Cpp.CompatGCC):
|
||||
compiler.AddToListVar('CFLAGS', '-Wno-sign-compare')
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache[sdk['sdk']], 'common', 'protobuf-2.3.0', 'src'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache[sdk['sdk']], 'public', 'engine', 'protobuf'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache[sdk['sdk']], 'public', 'game', 'shared', 'csgo', 'protobuf'))
|
||||
|
||||
extension = AMBuild.AddJob(name)
|
||||
binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler)
|
||||
SM.PreSetupHL2Job(extension, binary, i)
|
||||
|
||||
if i == 'csgo':
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
link = os.path.join(os.path.join(AMBuild.outputFolder, extension.workFolder), 'libprotobuf.a')
|
||||
target = os.path.join(os.path.join(AMBuild.cache[sdk['sdk']], 'lib', 'linux32', 'release'), 'libprotobuf.a')
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
extension.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'darwin':
|
||||
link = os.path.join(os.path.join(AMBuild.outputFolder, extension.workFolder), 'libprotobuf.a')
|
||||
target = os.path.join(os.path.join(AMBuild.cache[sdk['sdk']], 'lib', 'osx32', 'release'), 'libprotobuf.a')
|
||||
try:
|
||||
os.lstat(link)
|
||||
except:
|
||||
extension.AddCommand(SymlinkCommand(link, target))
|
||||
elif AMBuild.target['platform'] == 'windows':
|
||||
libPath = os.path.join(AMBuild.cache[sdk['sdk']], 'lib', 'win32', 'release', 'vs2010', 'libprotobuf.lib')
|
||||
binary.RebuildIfNewer(libPath)
|
||||
binary['POSTLINKFLAGS'].append(libPath)
|
||||
|
||||
files = [
|
||||
'AdminCache.cpp',
|
||||
'ExtensionSys.cpp',
|
||||
'MenuStyle_Valve.cpp',
|
||||
'logic_bridge.cpp',
|
||||
'smn_entities.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'ADTFactory.cpp',
|
||||
'ForwardSys.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'smn_events.cpp',
|
||||
'smn_menus.cpp',
|
||||
'sm_trie.cpp',
|
||||
'CDataPack.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'NativeInvoker.cpp',
|
||||
'smn_fakenatives.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'ChatTriggers.cpp',
|
||||
'NativeOwner.cpp',
|
||||
'smn_filesystem.cpp',
|
||||
'smn_player.cpp',
|
||||
'sourcemod.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'NextMap.cpp',
|
||||
'ConCmdManager.cpp',
|
||||
'HandleSys.cpp',
|
||||
'ConVarManager.cpp',
|
||||
'LibrarySys.cpp',
|
||||
'PlayerManager.cpp',
|
||||
'TimerSys.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'Logger.cpp',
|
||||
'PluginInfoDatabase.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'PluginSys.cpp',
|
||||
'smn_console.cpp',
|
||||
'UserMessages.cpp',
|
||||
'Database.cpp',
|
||||
'MenuManager.cpp',
|
||||
'smn_core.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'DebugReporter.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'ShareSys.cpp',
|
||||
'smn_database.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_vector.cpp',
|
||||
'EventManager.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'sm_srvcmds.cpp',
|
||||
'ConsoleDetours.cpp'
|
||||
]
|
||||
|
||||
if i == 'csgo':
|
||||
files.append('smn_protobuf.cpp')
|
||||
else:
|
||||
files.append('smn_bitbuffer.cpp')
|
||||
|
||||
binary.AddSourceFiles('core', files)
|
||||
|
||||
if i == 'csgo':
|
||||
files = [
|
||||
os.path.join('public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join('public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
|
||||
os.path.join('public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
||||
]
|
||||
binary.AddSourceFiles(AMBuild.cache[sdk['sdk']], files)
|
||||
|
||||
SM.PostSetupHL2Job(extension, binary, i)
|
||||
|
||||
if i == 'csgo':
|
||||
if AMBuild.target['platform'] in ['linux', 'darwin']:
|
||||
binary.AddObjectFiles(['libprotobuf.a'])
|
||||
|
||||
SM.AutoVersion('core', binary)
|
||||
SM.ExtractDebugInfo(extension, binary)
|
||||
binary.SendToJob()
|
||||
|
||||
+374
-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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1144,6 +1170,11 @@ bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
|
||||
|
||||
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
|
||||
{
|
||||
if (ident[0] == '\0')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
|
||||
if (!pUser || pUser->magic != USR_MAGIC_SET)
|
||||
{
|
||||
@@ -1156,6 +1187,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 +1215,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 +1455,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 +1636,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 +1651,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;
|
||||
@@ -1653,7 +1719,7 @@ bool AdminCache::CanAdminUseCommand(int client, const char *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
return g_ConCmds.CheckCommandAccess(client, cmd, bits);
|
||||
return g_ConCmds.CheckClientCommandAccess(client, cmd, bits);
|
||||
}
|
||||
|
||||
unsigned int AdminCache::SetGroupImmunityLevel(GroupId gid, unsigned int level)
|
||||
@@ -1728,5 +1794,305 @@ bool AdminCache::CheckAccess(int client, const char *cmd, FlagBits flags, bool o
|
||||
GetCommandOverride(cmd, Override_Command, &bits);
|
||||
}
|
||||
|
||||
return g_ConCmds.CheckCommandAccess(client, cmd, bits) ? 1 : 0;
|
||||
return g_ConCmds.CheckClientCommandAccess(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
|
||||
|
||||
@@ -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
|
||||
|
||||
+140
-97
@@ -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,14 +34,14 @@
|
||||
#include "sm_stringutil.h"
|
||||
#include "ConCmdManager.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "Translator.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "logic_bridge.h"
|
||||
|
||||
/* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
|
||||
* While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one
|
||||
* can technically be compiled against any MM:S version after 1.4.2.
|
||||
*/
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
|
||||
#else
|
||||
@@ -53,20 +53,23 @@ extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate
|
||||
#elif SH_IMPL_VERSION == 3
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#endif //SH_IMPL_VERSION
|
||||
#endif //ORANGEBOX_BUILD
|
||||
#endif //SE_ORANGEBOX
|
||||
|
||||
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)
|
||||
m_ReplyTo(SM_REPLY_CONSOLE)
|
||||
{
|
||||
m_PubTrigger = sm_strdup("!");
|
||||
m_PrivTrigger = sm_strdup("/");
|
||||
m_PubTriggerSize = 1;
|
||||
m_PrivTriggerSize = 1;
|
||||
m_bIsChatTrigger = false;
|
||||
m_bPluginIgnored = false;
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
m_bIsINS = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
ChatTriggers::~ChatTriggers()
|
||||
@@ -110,43 +113,19 @@ void ChatTriggers::OnSourceModAllInitialized()
|
||||
{
|
||||
m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
|
||||
m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
|
||||
m_pOnClientSayCmd = g_Forwards.CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String);
|
||||
m_pOnClientSayCmd_Post = g_Forwards.CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
unsigned int file_id;
|
||||
|
||||
file_id = g_Translator.FindOrAddPhraseFile("antiflood.phrases.txt");
|
||||
g_pFloodPhrases = g_Translator.GetFileByIndex(file_id);
|
||||
logicore.AddCorePhraseFile("antiflood.phrases");
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModGameInitialized()
|
||||
{
|
||||
unsigned int total = 2;
|
||||
ConCommandBase *pCmd = icvar->GetCommands();
|
||||
const char *name;
|
||||
while (pCmd)
|
||||
{
|
||||
if (pCmd->IsCommand())
|
||||
{
|
||||
name = pCmd->GetName();
|
||||
if (!m_pSayCmd && strcmp(name, "say") == 0)
|
||||
{
|
||||
m_pSayCmd = (ConCommand *)pCmd;
|
||||
if (--total == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} else if (!m_pSayTeamCmd && strcmp(name, "say_team") == 0) {
|
||||
m_pSayTeamCmd = (ConCommand *)pCmd;
|
||||
if (--total == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pCmd = const_cast<ConCommandBase *>(pCmd->GetNext());
|
||||
}
|
||||
m_pSayCmd = FindCommand("say");
|
||||
m_pSayTeamCmd = FindCommand("say_team");
|
||||
|
||||
if (m_pSayCmd)
|
||||
{
|
||||
@@ -158,26 +137,65 @@ void ChatTriggers::OnSourceModGameInitialized()
|
||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
||||
|
||||
if (m_bIsINS)
|
||||
{
|
||||
m_pSay2Cmd = FindCommand("say2");
|
||||
if (m_pSay2Cmd)
|
||||
{
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
}
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
m_pSaySquadCmd = FindCommand("say_squad");
|
||||
|
||||
if (m_pSaySquadCmd)
|
||||
{
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_ADD_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChatTriggers::OnSourceModShutdown()
|
||||
{
|
||||
if (m_pSayTeamCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
}
|
||||
if (m_pSayCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
||||
}
|
||||
|
||||
if (m_pSayTeamCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (m_bIsINS && m_pSay2Cmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
if (m_pSaySquadCmd)
|
||||
{
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_Forwards.ReleaseForward(m_pShouldFloodBlock);
|
||||
g_Forwards.ReleaseForward(m_pDidFloodBlock);
|
||||
g_Forwards.ReleaseForward(m_pOnClientSayCmd);
|
||||
g_Forwards.ReleaseForward(m_pOnClientSayCmd_Post);
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
@@ -185,24 +203,10 @@ void ChatTriggers::OnSayCommand_Pre()
|
||||
{
|
||||
CCommand command;
|
||||
#endif
|
||||
int client;
|
||||
CPlayer *pPlayer;
|
||||
|
||||
client = g_ConCmds.GetCommandClient();
|
||||
int client = g_ConCmds.GetCommandClient();
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
|
||||
/* The server console cannot do this */
|
||||
if (client == 0 || (pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/* We guarantee the client is connected */
|
||||
if (!pPlayer->IsConnected())
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
m_bPluginIgnored = false;
|
||||
|
||||
const char *args = command.ArgS();
|
||||
|
||||
@@ -211,23 +215,38 @@ void ChatTriggers::OnSayCommand_Pre()
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/* Save these off for post hook as the command data returned from the engine in older engine versions
|
||||
* can be NULL, despite the data still being there and valid. */
|
||||
m_Arg0Backup = command.Arg(0);
|
||||
m_ArgSBackup = command.ArgS();
|
||||
|
||||
/* The server console cannot do this */
|
||||
if (client == 0)
|
||||
{
|
||||
cell_t res = CallOnClientSayCommand(client);
|
||||
if (res >= Pl_Handled)
|
||||
{
|
||||
m_bPluginIgnored = (res >= Pl_Stop);
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
|
||||
/* We guarantee the client is connected */
|
||||
if (!pPlayer || !pPlayer->IsConnected())
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/* Check if we need to block this message from being sent */
|
||||
if (ClientIsFlooding(client))
|
||||
{
|
||||
char buffer[128];
|
||||
|
||||
/* :TODO: log an error? */
|
||||
if (g_Translator.CoreTransEx(g_pFloodPhrases,
|
||||
client,
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"Flooding the server",
|
||||
NULL,
|
||||
NULL)
|
||||
!= Trans_Okay)
|
||||
{
|
||||
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client))
|
||||
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
|
||||
}
|
||||
|
||||
/* :TODO: we should probably kick people who spam too much. */
|
||||
|
||||
@@ -248,6 +267,13 @@ void ChatTriggers::OnSayCommand_Pre()
|
||||
is_quoted = true;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (m_bIsINS && strcmp(m_Arg0Backup, "say2") == 0 && strlen(args) >= 4)
|
||||
{
|
||||
args += 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_trigger = false;
|
||||
bool is_silent = false;
|
||||
|
||||
@@ -264,38 +290,28 @@ void ChatTriggers::OnSayCommand_Pre()
|
||||
args = &args[m_PrivTriggerSize];
|
||||
}
|
||||
|
||||
if (!is_trigger)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this is actually a command!
|
||||
*/
|
||||
if (!PreProcessTrigger(engine->PEntityOfEntIndex(client), args, is_quoted))
|
||||
if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args, is_quoted))
|
||||
{
|
||||
CPlayer *pPlayer;
|
||||
if (is_silent
|
||||
&& g_bSupressSilentFails
|
||||
&& client != 0
|
||||
&& (pPlayer = g_Players.GetPlayerByIndex(client)) != NULL
|
||||
&& pPlayer->GetAdminId() != INVALID_ADMIN_ID)
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
RETURN_META(MRES_IGNORED);
|
||||
m_bIsChatTrigger = true;
|
||||
|
||||
/**
|
||||
* We'll execute it in post.
|
||||
*/
|
||||
m_bWillProcessInPost = true;
|
||||
}
|
||||
|
||||
m_bIsChatTrigger = true;
|
||||
cell_t res = CallOnClientSayCommand(client);
|
||||
|
||||
/**
|
||||
* We'll execute it in post.
|
||||
*/
|
||||
m_bWillProcessInPost = true;
|
||||
m_bTriggerWasSilent = is_silent;
|
||||
if (res >= Pl_Handled)
|
||||
{
|
||||
m_bPluginIgnored = (res >= Pl_Stop);
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
/* If we're silent, block */
|
||||
if (is_silent)
|
||||
if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
|
||||
{
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
@@ -304,25 +320,39 @@ void ChatTriggers::OnSayCommand_Pre()
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
|
||||
#else
|
||||
void ChatTriggers::OnSayCommand_Post()
|
||||
#endif
|
||||
{
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
int client = g_ConCmds.GetCommandClient();
|
||||
|
||||
if (m_bWillProcessInPost)
|
||||
{
|
||||
/* Reset this for re-entrancy */
|
||||
m_bWillProcessInPost = false;
|
||||
|
||||
/* Execute the cached command */
|
||||
int client = g_ConCmds.GetCommandClient();
|
||||
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
|
||||
serverpluginhelpers->ClientCommand(engine->PEntityOfEntIndex(client), m_ToExecute);
|
||||
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
|
||||
SetReplyTo(old);
|
||||
}
|
||||
|
||||
if (m_bPluginIgnored)
|
||||
{
|
||||
m_bPluginIgnored = false;
|
||||
}
|
||||
else if (!m_bWasFloodedMessage && !m_bIsChatTrigger && m_pOnClientSayCmd_Post->GetFunctionCount() != 0)
|
||||
{
|
||||
m_pOnClientSayCmd_Post->PushCell(client);
|
||||
m_pOnClientSayCmd_Post->PushString(m_Arg0Backup);
|
||||
m_pOnClientSayCmd_Post->PushString(m_ArgSBackup);
|
||||
m_pOnClientSayCmd_Post->Execute(NULL);
|
||||
}
|
||||
|
||||
m_bIsChatTrigger = false;
|
||||
m_bWasFloodedMessage = false;
|
||||
}
|
||||
|
||||
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted)
|
||||
@@ -399,6 +429,19 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_
|
||||
return true;
|
||||
}
|
||||
|
||||
cell_t ChatTriggers::CallOnClientSayCommand(int client)
|
||||
{
|
||||
cell_t res = Pl_Continue;
|
||||
if (!m_bIsChatTrigger && m_pOnClientSayCmd->GetFunctionCount() != 0)
|
||||
{
|
||||
m_pOnClientSayCmd->PushCell(client);
|
||||
m_pOnClientSayCmd->PushString(m_Arg0Backup);
|
||||
m_pOnClientSayCmd->PushString(m_ArgSBackup);
|
||||
m_pOnClientSayCmd->Execute(&res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
|
||||
{
|
||||
unsigned int old = m_ReplyTo;
|
||||
|
||||
+16
-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
|
||||
@@ -54,7 +54,7 @@ public: //SMGlobalClass
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
private: //ConCommand
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnSayCommand_Pre(const CCommand &command);
|
||||
void OnSayCommand_Post(const CCommand &command);
|
||||
#else
|
||||
@@ -69,21 +69,34 @@ public:
|
||||
private:
|
||||
bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
|
||||
bool ClientIsFlooding(int client);
|
||||
cell_t CallOnClientSayCommand(int client);
|
||||
private:
|
||||
ConCommand *m_pSayCmd;
|
||||
ConCommand *m_pSayTeamCmd;
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
ConCommand *m_pSay2Cmd;
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
ConCommand *m_pSaySquadCmd;
|
||||
#endif
|
||||
char *m_PubTrigger;
|
||||
size_t m_PubTriggerSize;
|
||||
char *m_PrivTrigger;
|
||||
size_t m_PrivTriggerSize;
|
||||
bool m_bWillProcessInPost;
|
||||
bool m_bTriggerWasSilent;
|
||||
bool m_bIsChatTrigger;
|
||||
bool m_bWasFloodedMessage;
|
||||
bool m_bPluginIgnored;
|
||||
unsigned int m_ReplyTo;
|
||||
char m_ToExecute[300];
|
||||
const char *m_Arg0Backup;
|
||||
const char *m_ArgSBackup;
|
||||
IForward *m_pShouldFloodBlock;
|
||||
IForward *m_pDidFloodBlock;
|
||||
IForward *m_pOnClientSayCmd;
|
||||
IForward *m_pOnClientSayCmd_Post;
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
bool m_bIsINS;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern ChatTriggers g_ChatTriggers;
|
||||
|
||||
+95
-111
@@ -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,13 +34,13 @@
|
||||
#include "AdminCache.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "Translator.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "ChatTriggers.h"
|
||||
#include "logic_bridge.h"
|
||||
|
||||
ConCmdManager g_ConCmds;
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#else
|
||||
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
@@ -205,7 +205,7 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
|
||||
delete pList;
|
||||
}
|
||||
}
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CommandCallback(const CCommand &command)
|
||||
{
|
||||
#else
|
||||
@@ -226,49 +226,78 @@ void ConCmdManager::SetCommandClient(int client)
|
||||
m_CmdClient = client + 1;
|
||||
}
|
||||
|
||||
ConCmdInfo *ConCmdManager::FindInTrie(const char *name)
|
||||
{
|
||||
ConCmdInfo *pInfo;
|
||||
if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
|
||||
return NULL;
|
||||
return pInfo;
|
||||
}
|
||||
|
||||
ConCmdList::iterator ConCmdManager::FindInList(const char *cmd)
|
||||
{
|
||||
List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
|
||||
|
||||
while (iter != m_CmdList.end())
|
||||
{
|
||||
if (strcasecmp((*iter)->pCmd->GetName(), cmd) == 0)
|
||||
break;
|
||||
iter++;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
|
||||
{
|
||||
ConCmdInfo *pInfo;
|
||||
if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
|
||||
|
||||
if ((pInfo = FindInTrie(cmd)) == NULL)
|
||||
{
|
||||
cell_t result = type;
|
||||
cell_t tempres = result;
|
||||
List<CmdHook *>::iterator iter;
|
||||
CmdHook *pHook;
|
||||
for (iter=pInfo->conhooks.begin();
|
||||
iter!=pInfo->conhooks.end();
|
||||
iter++)
|
||||
ConCmdList::iterator item = FindInList(cmd);
|
||||
if (item == m_CmdList.end())
|
||||
return type;
|
||||
pInfo = *item;
|
||||
}
|
||||
|
||||
cell_t result = type;
|
||||
cell_t tempres = result;
|
||||
List<CmdHook *>::iterator iter;
|
||||
CmdHook *pHook;
|
||||
for (iter=pInfo->conhooks.begin();
|
||||
iter!=pInfo->conhooks.end();
|
||||
iter++)
|
||||
{
|
||||
pHook = (*iter);
|
||||
if (!pHook->pf->IsRunnable())
|
||||
{
|
||||
pHook = (*iter);
|
||||
if (!pHook->pf->IsRunnable())
|
||||
continue;
|
||||
}
|
||||
if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin))
|
||||
{
|
||||
if (result < Pl_Handled)
|
||||
{
|
||||
continue;
|
||||
result = Pl_Handled;
|
||||
}
|
||||
if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin))
|
||||
continue;
|
||||
}
|
||||
pHook->pf->PushCell(client);
|
||||
pHook->pf->PushCell(args);
|
||||
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
|
||||
{
|
||||
if (tempres > result)
|
||||
{
|
||||
if (result < Pl_Handled)
|
||||
{
|
||||
result = Pl_Handled;
|
||||
}
|
||||
continue;
|
||||
result = tempres;
|
||||
}
|
||||
pHook->pf->PushCell(client);
|
||||
pHook->pf->PushCell(args);
|
||||
if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
|
||||
if (result == Pl_Stop)
|
||||
{
|
||||
if (tempres > result)
|
||||
{
|
||||
result = tempres;
|
||||
}
|
||||
if (result == Pl_Stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
type = (ResultType)result;
|
||||
}
|
||||
|
||||
type = (ResultType)result;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -293,10 +322,20 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
|
||||
*/
|
||||
const char *cmd = g_HL2.CurrentCommandName();
|
||||
|
||||
ConCmdInfo *pInfo;
|
||||
if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
|
||||
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||
if (pInfo == NULL)
|
||||
{
|
||||
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;
|
||||
|
||||
ConCmdList::iterator item = FindInList(cmd);
|
||||
if (item == m_CmdList.end())
|
||||
return;
|
||||
|
||||
pInfo = *item;
|
||||
}
|
||||
|
||||
/* This is a hack to prevent say triggers from firing on messages that were
|
||||
@@ -379,14 +418,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)
|
||||
@@ -411,7 +450,7 @@ void ConCmdManager::InternalDispatch(const CCommand &command)
|
||||
}
|
||||
}
|
||||
|
||||
bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmdflags)
|
||||
bool ConCmdManager::CheckClientCommandAccess(int client, const char *cmd, FlagBits cmdflags)
|
||||
{
|
||||
if (cmdflags == 0 || client == 0)
|
||||
{
|
||||
@@ -432,7 +471,11 @@ bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmd
|
||||
return false;
|
||||
}
|
||||
|
||||
AdminId adm = player->GetAdminId();
|
||||
return CheckAdminCommandAccess(player->GetAdminId(), cmd, cmdflags);
|
||||
}
|
||||
|
||||
bool ConCmdManager::CheckAdminCommandAccess(AdminId adm, const char *cmd, FlagBits cmdflags)
|
||||
{
|
||||
if (adm != INVALID_ADMIN_ID)
|
||||
{
|
||||
FlagBits bits = g_Admins.GetAdminFlags(adm, Access_Effective);
|
||||
@@ -485,17 +528,16 @@ bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmd
|
||||
|
||||
bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin)
|
||||
{
|
||||
if (CheckCommandAccess(client, cmd, pAdmin->eflags))
|
||||
if (CheckClientCommandAccess(client, cmd, pAdmin->eflags))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
edict_t *pEdict = engine->PEntityOfEntIndex(client);
|
||||
edict_t *pEdict = PEntityOfEntIndex(client);
|
||||
|
||||
/* 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 (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "No Access", &client))
|
||||
{
|
||||
UTIL_Format(buffer, sizeof(buffer), "You do not have access to this command");
|
||||
}
|
||||
@@ -517,44 +559,6 @@ bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmi
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
|
||||
const char *name,
|
||||
const char *description,
|
||||
int flags)
|
||||
{
|
||||
ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
|
||||
|
||||
if (!pInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CmdHook *pHook = new CmdHook();
|
||||
|
||||
pHook->pf = pFunction;
|
||||
if (description && description[0])
|
||||
{
|
||||
pHook->helptext.assign(description);
|
||||
}
|
||||
pInfo->conhooks.push_back(pHook);
|
||||
|
||||
/* Add to the plugin */
|
||||
CmdList *pList;
|
||||
IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
|
||||
if (!pPlugin->GetProperty("CommandList", (void **)&pList))
|
||||
{
|
||||
pList = new CmdList();
|
||||
pPlugin->SetProperty("CommandList", pList);
|
||||
}
|
||||
PlCmdInfo info;
|
||||
info.pInfo = pInfo;
|
||||
info.type = Cmd_Console;
|
||||
info.pHook = pHook;
|
||||
AddToPlCmdList(pList, info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
||||
const char *name,
|
||||
const char *group,
|
||||
@@ -616,7 +620,6 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
||||
/* Finally, add the hook */
|
||||
pInfo->conhooks.push_back(pHook);
|
||||
pInfo->admin = *(pHook->pAdmin);
|
||||
pInfo->is_admin_set = true;
|
||||
|
||||
/* Now add to the plugin */
|
||||
CmdList *pList;
|
||||
@@ -761,7 +764,6 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
|
||||
pInfo->admin = *(pHook->pAdmin);
|
||||
}
|
||||
}
|
||||
pInfo->is_admin_set = true;
|
||||
}
|
||||
else if (type == Override_CommandGroup)
|
||||
{
|
||||
@@ -795,7 +797,6 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
|
||||
}
|
||||
}
|
||||
}
|
||||
pInfo->is_admin_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,7 +864,7 @@ bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags)
|
||||
|
||||
*pFlags = pInfo->admin.eflags;
|
||||
|
||||
return pInfo->is_admin_set;
|
||||
return true;
|
||||
}
|
||||
|
||||
ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
|
||||
@@ -871,25 +872,13 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
|
||||
ConCmdInfo *pInfo;
|
||||
if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
|
||||
{
|
||||
ConCmdList::iterator item = FindInList(name);
|
||||
if (item != m_CmdList.end())
|
||||
return *item;
|
||||
|
||||
pInfo = new ConCmdInfo();
|
||||
/* Find the commandopan */
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
ConCommand *pCmd = NULL;
|
||||
while (pBase)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), name) == 0)
|
||||
{
|
||||
/* Don't want to return convar with same name */
|
||||
if (!pBase->IsCommand())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pCmd = (ConCommand *)pBase;
|
||||
break;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
ConCommand *pCmd = FindCommand(name);
|
||||
|
||||
if (!pCmd)
|
||||
{
|
||||
@@ -912,7 +901,6 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
|
||||
}
|
||||
|
||||
pInfo->pCmd = pCmd;
|
||||
pInfo->is_admin_set = false;
|
||||
|
||||
sm_trie_insert(m_pCmds, name, pInfo);
|
||||
AddToCmdList(pInfo);
|
||||
@@ -965,13 +953,9 @@ void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
|
||||
{
|
||||
type = "server";
|
||||
}
|
||||
else if (cmd.type == Cmd_Console)
|
||||
{
|
||||
type = "console";
|
||||
}
|
||||
else if (cmd.type == Cmd_Admin)
|
||||
{
|
||||
type = "admin";
|
||||
type = (cmd.pInfo->admin.eflags == 0)?"console":"admin";
|
||||
}
|
||||
name = cmd.pInfo->pCmd->GetName();
|
||||
if (cmd.pHook->helptext.size())
|
||||
|
||||
+14
-7
@@ -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
|
||||
@@ -48,7 +48,6 @@ using namespace SourceHook;
|
||||
enum CmdType
|
||||
{
|
||||
Cmd_Server,
|
||||
Cmd_Console,
|
||||
Cmd_Admin,
|
||||
};
|
||||
|
||||
@@ -89,16 +88,17 @@ struct ConCmdInfo
|
||||
List<CmdHook *> srvhooks; /**< Hooks as a server command */
|
||||
List<CmdHook *> conhooks; /**< Hooks as a console command */
|
||||
AdminCmdInfo admin; /**< Admin info, if any */
|
||||
bool is_admin_set; /**< Whether or not admin info is set */
|
||||
};
|
||||
|
||||
typedef List<ConCmdInfo *> ConCmdList;
|
||||
|
||||
class ConCmdManager :
|
||||
public SMGlobalClass,
|
||||
public IRootConsoleCommand,
|
||||
public IPluginsListener,
|
||||
public IConCommandTracker
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
friend void CommandCallback(const CCommand &command);
|
||||
#else
|
||||
friend void CommandCallback();
|
||||
@@ -117,7 +117,6 @@ public: //IConCommandTracker
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||
public:
|
||||
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
|
||||
bool AddConsoleCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
|
||||
bool AddAdminCommand(IPluginFunction *pFunction,
|
||||
const char *name,
|
||||
const char *group,
|
||||
@@ -128,7 +127,8 @@ public:
|
||||
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
|
||||
bool LookForSourceModCommand(const char *cmd);
|
||||
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
|
||||
bool CheckCommandAccess(int client, const char *cmd, FlagBits flags);
|
||||
bool CheckClientCommandAccess(int client, const char *cmd, FlagBits flags);
|
||||
bool CheckAdminCommandAccess(AdminId adm, const char *cmd, FlagBits flags);
|
||||
private:
|
||||
void InternalDispatch(const CCommand &command);
|
||||
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
|
||||
@@ -139,6 +139,12 @@ private:
|
||||
void RemoveConCmds(List<CmdHook *> &cmdlist);
|
||||
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
|
||||
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
||||
|
||||
// Case insensitive
|
||||
ConCmdList::iterator FindInList(const char *name);
|
||||
|
||||
// Case sensitive
|
||||
ConCmdInfo *FindInTrie(const char *name);
|
||||
public:
|
||||
inline int GetCommandClient()
|
||||
{
|
||||
@@ -151,7 +157,7 @@ public:
|
||||
private:
|
||||
Trie *m_pCmds; /* command lookup */
|
||||
Trie *m_pCmdGrps; /* command group lookup */
|
||||
List<ConCmdInfo *> m_CmdList; /* command list */
|
||||
ConCmdList m_CmdList; /* command list */
|
||||
int m_CmdClient; /* current client */
|
||||
BaseStringTable m_Strings; /* string table */
|
||||
};
|
||||
@@ -159,3 +165,4 @@ private:
|
||||
extern ConCmdManager g_ConCmds;
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#ifndef _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
|
||||
#define _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
class ConCommandBaseIterator
|
||||
{
|
||||
public:
|
||||
inline ConCommandBaseIterator() : iter(icvar)
|
||||
{
|
||||
iter.SetFirst();
|
||||
}
|
||||
|
||||
inline bool IsValid()
|
||||
{
|
||||
return iter.IsValid();
|
||||
}
|
||||
|
||||
inline void Next()
|
||||
{
|
||||
iter.Next();
|
||||
}
|
||||
|
||||
inline ConCommandBase *Get()
|
||||
{
|
||||
return iter.Get();
|
||||
}
|
||||
private:
|
||||
ICvar::Iterator iter;
|
||||
};
|
||||
#else
|
||||
class ConCommandBaseIterator
|
||||
{
|
||||
public:
|
||||
inline ConCommandBaseIterator()
|
||||
{
|
||||
iter = icvar->GetCommands();
|
||||
}
|
||||
|
||||
inline bool IsValid()
|
||||
{
|
||||
return iter != NULL;
|
||||
}
|
||||
|
||||
inline void Next()
|
||||
{
|
||||
iter = const_cast<ConCommandBase *>(iter->GetNext());
|
||||
}
|
||||
|
||||
inline ConCommandBase *Get()
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
private:
|
||||
ConCommandBase *iter;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_CON_COMMAND_BASE_ITERATOR_H_ */
|
||||
|
||||
+103
-30
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -25,8 +25,6 @@
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ConVarManager.h"
|
||||
@@ -41,23 +39,59 @@
|
||||
|
||||
ConVarManager g_ConVarManager;
|
||||
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
#define CallGlobalChangeCallbacks CallGlobalChangeCallback
|
||||
#endif
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
|
||||
#else
|
||||
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||
#endif
|
||||
|
||||
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
||||
typedef List<const ConVar *> ConVarList;
|
||||
KTrie<ConVarInfo *> convar_cache;
|
||||
|
||||
class ConVarReentrancyGuard
|
||||
{
|
||||
ConVar *cvar;
|
||||
ConVarReentrancyGuard *up;
|
||||
public:
|
||||
static ConVarReentrancyGuard *chain;
|
||||
|
||||
ConVarReentrancyGuard(ConVar *cvar)
|
||||
: cvar(cvar), up(chain)
|
||||
{
|
||||
chain = this;
|
||||
}
|
||||
|
||||
~ConVarReentrancyGuard()
|
||||
{
|
||||
assert(chain == this);
|
||||
chain = up;
|
||||
}
|
||||
|
||||
static bool IsCvarInChain(ConVar *cvar)
|
||||
{
|
||||
ConVarReentrancyGuard *guard = chain;
|
||||
while (guard != NULL)
|
||||
{
|
||||
if (guard->cvar == cvar)
|
||||
return true;
|
||||
guard = guard->up;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
ConVarReentrancyGuard *ConVarReentrancyGuard::chain = NULL;
|
||||
|
||||
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
|
||||
{
|
||||
}
|
||||
@@ -84,7 +118,7 @@ void ConVarManager::OnSourceModAllInitialized()
|
||||
/**
|
||||
* Episode 2 has this function by default, but the older versions do not.
|
||||
*/
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||
if (g_SMAPI->GetGameDLLVersion() >= 6)
|
||||
{
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
@@ -94,6 +128,8 @@ void ConVarManager::OnSourceModAllInitialized()
|
||||
|
||||
SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
|
||||
|
||||
g_PluginSys.AddPluginsListener(this);
|
||||
|
||||
/* Add the 'convars' option to the 'sm' console command */
|
||||
g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
|
||||
}
|
||||
@@ -141,6 +177,7 @@ void ConVarManager::OnSourceModShutdown()
|
||||
}
|
||||
convar_cache.clear();
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
/* Unhook things */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
@@ -152,12 +189,15 @@ void ConVarManager::OnSourceModShutdown()
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
m_bIsVSPQueryHooked = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
SH_REMOVE_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
|
||||
|
||||
/* Remove the 'convars' option from the 'sm' console command */
|
||||
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
|
||||
|
||||
g_PluginSys.RemovePluginsListener(this);
|
||||
|
||||
/* Remove the 'ConVar' handle type */
|
||||
g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
|
||||
}
|
||||
@@ -176,7 +216,7 @@ void ConVarManager::OnSourceModVSPReceived()
|
||||
}
|
||||
|
||||
/* For later MM:S versions, use the updated API, since it's cleaner. */
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
|
||||
int engine = g_SMAPI->GetSourceEngineBuild();
|
||||
if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
|
||||
{
|
||||
@@ -189,8 +229,10 @@ void ConVarManager::OnSourceModVSPReceived()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
m_bIsVSPQueryHooked = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
|
||||
@@ -246,12 +288,23 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
ConVarList *pConVarList;
|
||||
List<ConVarQuery>::iterator iter;
|
||||
|
||||
/* If plugin has a convar list, free its memory */
|
||||
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
||||
{
|
||||
delete pConVarList;
|
||||
}
|
||||
|
||||
/* Remove convar queries for this plugin that haven't returned results yet */
|
||||
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end(); iter++)
|
||||
{
|
||||
ConVarQuery &query = (*iter);
|
||||
if (query.pCallback->GetParentRuntime() == plugin->GetRuntime())
|
||||
{
|
||||
m_ConVarQueries.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
@@ -269,8 +322,15 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
|
||||
int argcount = command.ArgC();
|
||||
if (argcount >= 3)
|
||||
{
|
||||
bool wantReset = false;
|
||||
|
||||
/* Get plugin index that was passed */
|
||||
const char *arg = command.Arg(2);
|
||||
if (argcount >= 4 && strcmp(arg, "reset") == 0)
|
||||
{
|
||||
wantReset = true;
|
||||
arg = command.Arg(3);
|
||||
}
|
||||
|
||||
/* Get plugin object */
|
||||
CPlugin *plugin = g_PluginSys.FindPluginByConsoleArg(arg);
|
||||
@@ -295,21 +355,34 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
|
||||
return;
|
||||
}
|
||||
|
||||
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
|
||||
|
||||
/* Iterate convar list and display each one */
|
||||
if (!wantReset)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
|
||||
}
|
||||
|
||||
/* Iterate convar list and display/reset each one */
|
||||
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
|
||||
{
|
||||
const ConVar *pConVar = (*iter);
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
||||
/*const */ConVar *pConVar = const_cast<ConVar *>(*iter);
|
||||
if (!wantReset)
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
||||
} else {
|
||||
pConVar->Revert();
|
||||
}
|
||||
}
|
||||
|
||||
if (wantReset)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Reset %d convars for: %s", pConVarList->size(), plname);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Display usage of subcommand */
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm convars <plugin #>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm cvars [reset] <plugin #>");
|
||||
}
|
||||
|
||||
Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *description, int flags, bool hasMin, float min, bool hasMax, float max)
|
||||
@@ -359,17 +432,10 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
/* To prevent creating a convar that has the same name as a console command... ugh */
|
||||
ConCommandBase *pBase = icvar->GetCommands();
|
||||
|
||||
while (pBase)
|
||||
/* Prevent creating a convar that has the same name as a console command */
|
||||
if (FindCommand(name))
|
||||
{
|
||||
if (pBase->IsCommand() && strcmp(pBase->GetName(), name) == 0)
|
||||
{
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
/* Create and initialize ConVarInfo structure */
|
||||
@@ -524,7 +590,8 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
|
||||
}
|
||||
|
||||
/* If the forward now has 0 functions in it... */
|
||||
if (pForward->GetFunctionCount() == 0)
|
||||
if (pForward->GetFunctionCount() == 0 &&
|
||||
!ConVarReentrancyGuard::IsCvarInChain(pConVar))
|
||||
{
|
||||
/* Free this forward */
|
||||
g_Forwards.ReleaseForward(pForward);
|
||||
@@ -535,8 +602,9 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
|
||||
|
||||
QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl)
|
||||
{
|
||||
QueryCvarCookie_t cookie;
|
||||
QueryCvarCookie_t cookie = 0;
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
@@ -553,6 +621,7 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
|
||||
|
||||
ConVarQuery query = {cookie, pCallback, hndl};
|
||||
m_ConVarQueries.push_back(query);
|
||||
#endif
|
||||
|
||||
return cookie;
|
||||
}
|
||||
@@ -595,7 +664,7 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar
|
||||
}
|
||||
}
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
|
||||
#else
|
||||
void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
||||
@@ -623,7 +692,7 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
||||
i != pInfo->changeListeners.end();
|
||||
i++)
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
(*i)->OnConVarChanged(pConVar, oldValue, flOldValue);
|
||||
#else
|
||||
(*i)->OnConVarChanged(pConVar, oldValue, atof(oldValue));
|
||||
@@ -633,6 +702,8 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
||||
|
||||
if (pForward != NULL)
|
||||
{
|
||||
ConVarReentrancyGuard guard(pConVar);
|
||||
|
||||
/* Now call forwards in plugins that have hooked this */
|
||||
pForward->PushCell(pInfo->handle);
|
||||
pForward->PushString(oldValue);
|
||||
@@ -646,6 +717,7 @@ bool ConVarManager::IsQueryingSupported()
|
||||
return (m_bIsDLLQueryHooked || m_bIsVSPQueryHooked);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||
{
|
||||
IPluginFunction *pCallback = NULL;
|
||||
@@ -668,7 +740,7 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *
|
||||
cell_t ret;
|
||||
|
||||
pCallback->PushCell(cookie);
|
||||
pCallback->PushCell(engine->IndexOfEdict(pPlayer));
|
||||
pCallback->PushCell(IndexOfEdict(pPlayer));
|
||||
pCallback->PushCell(result);
|
||||
pCallback->PushString(cvarName);
|
||||
|
||||
@@ -687,6 +759,7 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *
|
||||
m_ConVarQueries.erase(iter);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
||||
{
|
||||
|
||||
@@ -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,11 @@
|
||||
#include <compat_wrappers.h>
|
||||
#include "concmd_cleaner.h"
|
||||
|
||||
#if SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
class EQueryCvarValueStatus;
|
||||
typedef int QueryCvarCookie_t;
|
||||
#endif
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
class IConVarChangeListener
|
||||
@@ -140,7 +145,7 @@ private:
|
||||
/**
|
||||
* Static callback that Valve's ConVar object executes when the convar's value changes.
|
||||
*/
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
static void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||
#else
|
||||
static void OnConVarChanged(ConVar *pConVar, const char *oldValue);
|
||||
@@ -149,8 +154,10 @@ private:
|
||||
/**
|
||||
* Callback for when StartQueryCvarValue() has finished.
|
||||
*/
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
|
||||
const char *cvarName, const char *cvarValue);
|
||||
#endif
|
||||
private:
|
||||
HandleType_t m_ConVarType;
|
||||
List<ConVarInfo *> m_ConVars;
|
||||
|
||||
@@ -0,0 +1,747 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* On SourceHook v4.3 or lower, there are no DVP hooks. Very sad, right?
|
||||
* Only do this on newer versions. For the older code, we'll do an incredibly
|
||||
* hacky detour.
|
||||
*
|
||||
* The idea of the "non-hacky" (yeah... no) code is that every unique
|
||||
* ConCommand vtable gets its own DVP hook. We watch for unloading and
|
||||
* loading commands to remove stale hooks from SH.
|
||||
*/
|
||||
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "Logger.h"
|
||||
#include "compat_wrappers.h"
|
||||
#include "ConsoleDetours.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "ConCmdManager.h"
|
||||
#include "HalfLife2.h"
|
||||
#include "ConCommandBaseIterator.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
#if defined PLATFORM_POSIX
|
||||
# include <dlfcn.h>
|
||||
# include <sys/mman.h>
|
||||
# include <stdint.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if SH_IMPL_VERSION >= 5
|
||||
# if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
# else
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
# endif
|
||||
#else
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHVPAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>,bool);
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
# endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
#if SH_IMPL_VERSION >= 4
|
||||
|
||||
class GenericCommandHooker : public IConCommandLinkListener
|
||||
{
|
||||
struct HackInfo
|
||||
{
|
||||
void **vtable;
|
||||
int hook;
|
||||
unsigned int refcount;
|
||||
};
|
||||
CVector<HackInfo> vtables;
|
||||
bool enabled;
|
||||
SourceHook::MemFuncInfo dispatch;
|
||||
|
||||
inline void **GetVirtualTable(ConCommandBase *pBase)
|
||||
{
|
||||
return *reinterpret_cast<void***>(reinterpret_cast<char*>(pBase) +
|
||||
dispatch.thisptroffs +
|
||||
dispatch.vtbloffs);
|
||||
}
|
||||
|
||||
inline bool FindVtable(void **ptr, size_t& index)
|
||||
{
|
||||
for (size_t i = 0; i < vtables.size(); i++)
|
||||
{
|
||||
if (vtables[i].vtable == ptr)
|
||||
{
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MakeHookable(ConCommandBase *pBase)
|
||||
{
|
||||
if (!pBase->IsCommand())
|
||||
return;
|
||||
|
||||
ConCommand *cmd = (ConCommand*)pBase;
|
||||
void **vtable = GetVirtualTable(cmd);
|
||||
|
||||
size_t index;
|
||||
if (!FindVtable(vtable, index))
|
||||
{
|
||||
HackInfo hack;
|
||||
hack.vtable = vtable;
|
||||
hack.hook = SH_ADD_VPHOOK(ConCommand, Dispatch, cmd, SH_MEMBER(this, &GenericCommandHooker::Dispatch), false);
|
||||
hack.refcount = 1;
|
||||
vtables.push_back(hack);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtables[index].refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
# if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void Dispatch(const CCommand& args)
|
||||
# else
|
||||
void Dispatch()
|
||||
# endif
|
||||
{
|
||||
cell_t res = ConsoleDetours::Dispatch(META_IFACEPTR(ConCommand)
|
||||
# if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
, args
|
||||
# endif
|
||||
);
|
||||
if (res >= Pl_Handled)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void ReparseCommandList()
|
||||
{
|
||||
for (size_t i = 0; i < vtables.size(); i++)
|
||||
vtables[i].refcount = 0;
|
||||
for (ConCommandBaseIterator iter; iter.IsValid(); iter.Next())
|
||||
MakeHookable(iter.Get());
|
||||
CVector<HackInfo>::iterator iter = vtables.begin();
|
||||
while (iter != vtables.end())
|
||||
{
|
||||
if ((*iter).refcount)
|
||||
{
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
/* Damn it. This event happens AFTER the plugin has unloaded!
|
||||
* There's two options. Remove the hook now and hope SH's memory
|
||||
* protection will prevent a crash. Otherwise, we can wait until
|
||||
* the server shuts down and more likely crash then.
|
||||
*
|
||||
* This situation only arises if:
|
||||
* 1) Someone has used AddCommandFilter()
|
||||
* 2) ... on a Dark Messiah server (mm:s new api)
|
||||
* 3) ... and another MM:S plugin that uses ConCommands has unloaded.
|
||||
*
|
||||
* Even though the impact is really small, we'll wait until the
|
||||
* server shuts down, so normal operation isn't interrupted.
|
||||
*
|
||||
* See bug 4018.
|
||||
*/
|
||||
iter = vtables.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void UnhookCommand(ConCommandBase *pBase)
|
||||
{
|
||||
if (!pBase->IsCommand())
|
||||
return;
|
||||
|
||||
ConCommand *cmd = (ConCommand*)pBase;
|
||||
void **vtable = GetVirtualTable(cmd);
|
||||
|
||||
size_t index;
|
||||
if (!FindVtable(vtable, index))
|
||||
{
|
||||
g_Logger.LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vtables[index].refcount > 0);
|
||||
vtables[index].refcount--;
|
||||
if (vtables[index].refcount == 0)
|
||||
{
|
||||
SH_REMOVE_HOOK_ID(vtables[index].hook);
|
||||
vtables.erase(vtables.iterAt(index));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GenericCommandHooker() : enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool Enable()
|
||||
{
|
||||
SourceHook::GetFuncInfo(&ConCommand::Dispatch, dispatch);
|
||||
|
||||
if (dispatch.thisptroffs < 0)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not determine ConCommand layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ConCommandBaseIterator iter; iter.IsValid(); iter.Next())
|
||||
MakeHookable(iter.Get());
|
||||
|
||||
if (!vtables.size())
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find any cvars!");
|
||||
return false;
|
||||
}
|
||||
|
||||
enabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
for (size_t i = 0; i < vtables.size(); i++)
|
||||
SH_REMOVE_HOOK_ID(vtables[i].hook);
|
||||
vtables.clear();
|
||||
}
|
||||
|
||||
virtual void OnLinkConCommand(ConCommandBase *pBase)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
MakeHookable(pBase);
|
||||
}
|
||||
|
||||
virtual void OnUnlinkConCommand(ConCommandBase *pBase)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
if (pBase == NULL)
|
||||
ReparseCommandList();
|
||||
else
|
||||
UnhookCommand(pBase);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* END DVP HOOK VERSION
|
||||
*/
|
||||
|
||||
#else /* SH_IMPL_VERSION >= 4 */
|
||||
|
||||
/**
|
||||
* BEGIN ENGINE DETOUR VERSION
|
||||
*/
|
||||
|
||||
# include <jit/jit_helpers.h>
|
||||
# include <jit/x86/x86_macros.h>
|
||||
|
||||
class GenericCommandHooker
|
||||
{
|
||||
struct Patch
|
||||
{
|
||||
Patch() : applied(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool applied;
|
||||
void *base;
|
||||
unsigned char search[16];
|
||||
size_t search_len;
|
||||
size_t offset;
|
||||
size_t saveat;
|
||||
int regparam;
|
||||
void *detour;
|
||||
};
|
||||
|
||||
Patch ces;
|
||||
Patch cgc;
|
||||
|
||||
public:
|
||||
static void DelayedActivation(void *inparam)
|
||||
{
|
||||
GenericCommandHooker *cdtrs = reinterpret_cast<GenericCommandHooker*>(inparam);
|
||||
/* Safe to re-enter because the frame queue is lock+swapped. */
|
||||
if ((!cdtrs->ces.applied || !cdtrs->cgc.applied) &&
|
||||
g_HL2.PeekCommandStack() != NULL)
|
||||
{
|
||||
g_SourceMod.AddFrameAction(GenericCommandHooker::DelayedActivation, cdtrs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cdtrs->ces.applied)
|
||||
cdtrs->ApplyPatch(&cdtrs->ces);
|
||||
if (!cdtrs->cgc.applied)
|
||||
cdtrs->ApplyPatch(&cdtrs->cgc);
|
||||
}
|
||||
|
||||
bool Enable()
|
||||
{
|
||||
const char *platform = NULL;
|
||||
# if defined(PLATFORM_WINDOWS)
|
||||
platform = "Windows";
|
||||
# else
|
||||
void *addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
|
||||
Dl_info info;
|
||||
if (!dladdr(addrInBase, &info))
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find engine name");
|
||||
return false;
|
||||
}
|
||||
if (strstr(info.dli_fname, "engine_i486"))
|
||||
{
|
||||
platform = "Linux_486";
|
||||
}
|
||||
else if (strstr(info.dli_fname, "engine_i686"))
|
||||
{
|
||||
platform = "Linux_686";
|
||||
}
|
||||
else if (strstr(info.dli_fname, "engine_amd"))
|
||||
{
|
||||
platform = "Linux_AMD";
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Logger.LogError("Command filter could not determine engine (%s)", info.dli_fname);
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!PrepPatch("Cmd_ExecuteString", "CES", platform, &ces))
|
||||
return false;
|
||||
if (!PrepPatch("CGameClient::ExecuteString", "CGC", platform, &cgc))
|
||||
return false;
|
||||
|
||||
if (g_HL2.PeekCommandStack() != NULL)
|
||||
{
|
||||
g_SourceMod.AddFrameAction(GenericCommandHooker::DelayedActivation, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
ApplyPatch(&ces);
|
||||
ApplyPatch(&cgc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
UndoPatch(&ces);
|
||||
UndoPatch(&cgc);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
# if !defined PLATFORM_WINDOWS
|
||||
# define PAGE_READWRITE PROT_READ|PROT_WRITE
|
||||
# define PAGE_EXECUTE_READ PROT_READ|PROT_EXEC
|
||||
|
||||
static inline uintptr_t AddrToPage(uintptr_t address)
|
||||
{
|
||||
return (address & ~(uintptr_t(sysconf(_SC_PAGE_SIZE) - 1)));
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
void Protect(void *addr, size_t length, int prot)
|
||||
{
|
||||
# if defined PLATFORM_WINDOWS
|
||||
DWORD ignore;
|
||||
VirtualProtect(addr, length, prot, &ignore);
|
||||
# else
|
||||
uintptr_t startPage = AddrToPage(uintptr_t(addr));
|
||||
length += (uintptr_t(addr) - startPage);
|
||||
mprotect((void*)startPage, length, prot);
|
||||
# endif
|
||||
}
|
||||
|
||||
void UndoPatch(Patch *patch)
|
||||
{
|
||||
if (!patch->applied || patch->detour == NULL)
|
||||
return;
|
||||
|
||||
g_pSourcePawn->FreePageMemory(patch->detour);
|
||||
|
||||
unsigned char *source = (unsigned char *)patch->base + patch->offset;
|
||||
Protect(source, patch->search_len, PAGE_READWRITE);
|
||||
for (size_t i = 0; i < patch->search_len; i++)
|
||||
source[i] = patch->search[i];
|
||||
Protect(source, patch->search_len, PAGE_EXECUTE_READ);
|
||||
}
|
||||
|
||||
void ApplyPatch(Patch *patch)
|
||||
{
|
||||
assert(!patch->applied);
|
||||
|
||||
size_t length = 0;
|
||||
void *callback = (void*)&ConsoleDetours::Dispatch;
|
||||
|
||||
/* Bogus assignment to make compiler is doing the right thing. */
|
||||
patch->detour = callback;
|
||||
|
||||
/* Assemgle the detour. */
|
||||
JitWriter writer;
|
||||
writer.outbase = NULL;
|
||||
writer.outptr = NULL;
|
||||
do
|
||||
{
|
||||
/* Need a specific register, or value on stack? */
|
||||
if (patch->regparam != -1)
|
||||
IA32_Push_Reg(&writer, patch->regparam);
|
||||
/* Call real function. */
|
||||
IA32_Write_Jump32_Abs(&writer, IA32_Call_Imm32(&writer, 0), callback);
|
||||
/* Restore stack. */
|
||||
if (patch->regparam != -1)
|
||||
IA32_Pop_Reg(&writer, patch->regparam);
|
||||
/* Copy any saved bytes */
|
||||
if (patch->saveat)
|
||||
{
|
||||
for (size_t i = patch->saveat; i < patch->search_len; i++)
|
||||
{
|
||||
writer.write_ubyte(patch->search[i]);
|
||||
}
|
||||
}
|
||||
/* Jump back to the caller. */
|
||||
unsigned char *target = (unsigned char *)patch->base + patch->offset + patch->search_len;
|
||||
IA32_Jump_Imm32_Abs(&writer, target);
|
||||
/* Assemble, if we can. */
|
||||
if (writer.outbase == NULL)
|
||||
{
|
||||
length = writer.outptr - writer.outbase;
|
||||
patch->detour = g_pSourcePawn->AllocatePageMemory(length);
|
||||
if (patch->detour == NULL)
|
||||
{
|
||||
g_Logger.LogError("Ran out of memory!");
|
||||
return;
|
||||
}
|
||||
g_pSourcePawn->SetReadWrite(patch->detour);
|
||||
writer.outbase = (jitcode_t)patch->detour;
|
||||
writer.outptr = writer.outbase;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
g_pSourcePawn->SetReadExecute(patch->detour);
|
||||
|
||||
unsigned char *source = (unsigned char *)patch->base + patch->offset;
|
||||
Protect(source, 6, PAGE_READWRITE);
|
||||
source[0] = 0xFF;
|
||||
source[1] = 0x25;
|
||||
*(void **)&source[2] = &patch->detour;
|
||||
Protect(source, 6, PAGE_EXECUTE_READ);
|
||||
|
||||
patch->applied = true;
|
||||
}
|
||||
|
||||
bool PrepPatch(const char *signature, const char *name, const char *platform, Patch *patch)
|
||||
{
|
||||
/* Get the base address of the function. */
|
||||
if (!g_pGameConf->GetMemSig(signature, &patch->base) || patch->base == NULL)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find signature: %s", signature);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *value;
|
||||
char keyname[255];
|
||||
|
||||
/* Get the verification bytes that will be written over. */
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Patch_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) == NULL)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find key: %s", keyname);
|
||||
return false;
|
||||
}
|
||||
patch->search_len = UTIL_DecodeHexString(patch->search, sizeof(patch->search), value);
|
||||
if (patch->search_len < 6)
|
||||
{
|
||||
g_Logger.LogError("Error decoding %s value, or not long enough", keyname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the offset into the function. */
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Offset_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) == NULL)
|
||||
{
|
||||
g_Logger.LogError("Command filter could not find key: %s", keyname);
|
||||
return false;
|
||||
}
|
||||
patch->offset = atoi(value);
|
||||
if (patch->offset > 20000)
|
||||
{
|
||||
g_Logger.LogError("Command filter %s value is bogus", keyname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the number of bytes to save from what was written over. */
|
||||
patch->saveat = 0;
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Save_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) != NULL)
|
||||
{
|
||||
patch->saveat = atoi(value);
|
||||
if (patch->saveat >= patch->search_len)
|
||||
{
|
||||
g_Logger.LogError("Command filter %s value is too large", keyname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get register for parameter, if any. */
|
||||
patch->regparam = -1;
|
||||
UTIL_Format(keyname, sizeof(keyname), "%s_Reg_%s", name, platform);
|
||||
if ((value = g_pGameConf->GetKeyValue(keyname)) != NULL)
|
||||
{
|
||||
patch->regparam = atoi(value);
|
||||
}
|
||||
|
||||
/* Everything loaded from gamedata, make sure the patch will succeed. */
|
||||
unsigned char *address = (unsigned char *)patch->base + patch->offset;
|
||||
for (size_t i = 0; i < patch->search_len; i++)
|
||||
{
|
||||
if (address[i] != patch->search[i])
|
||||
{
|
||||
g_Logger.LogError("Command filter %s has changed (byte %x is not %x sub-offset %d)",
|
||||
name, address[i], patch->search[i], i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static bool dummy_hook_set = false;
|
||||
void DummyHook()
|
||||
{
|
||||
if (dummy_hook_set)
|
||||
{
|
||||
dummy_hook_set = false;
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* BEGIN THE ACTUALLY GENERIC CODE.
|
||||
*/
|
||||
|
||||
#define FEATURECAP_COMMANDLISTENER "command listener"
|
||||
|
||||
static GenericCommandHooker s_GenericHooker;
|
||||
ConsoleDetours g_ConsoleDetours;
|
||||
|
||||
ConsoleDetours::ConsoleDetours() : status(FeatureStatus_Unknown)
|
||||
{
|
||||
}
|
||||
|
||||
void ConsoleDetours::OnSourceModAllInitialized()
|
||||
{
|
||||
m_pForward = g_Forwards.CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
|
||||
Param_String, Param_Cell);
|
||||
g_ShareSys.AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
|
||||
}
|
||||
|
||||
void ConsoleDetours::OnSourceModShutdown()
|
||||
{
|
||||
List<Listener*>::iterator iter = m_Listeners.begin();
|
||||
while (iter != m_Listeners.end())
|
||||
{
|
||||
Listener *listener = (*iter);
|
||||
g_Forwards.ReleaseForward(listener->forward);
|
||||
delete listener;
|
||||
iter = m_Listeners.erase(iter);
|
||||
}
|
||||
|
||||
g_Forwards.ReleaseForward(m_pForward);
|
||||
s_GenericHooker.Disable();
|
||||
}
|
||||
|
||||
FeatureStatus ConsoleDetours::GetFeatureStatus(FeatureType type, const char *name)
|
||||
{
|
||||
return GetStatus();
|
||||
}
|
||||
|
||||
FeatureStatus ConsoleDetours::GetStatus()
|
||||
{
|
||||
if (status == FeatureStatus_Unknown)
|
||||
{
|
||||
status = s_GenericHooker.Enable() ? FeatureStatus_Available : FeatureStatus_Unavailable;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
||||
{
|
||||
if (GetStatus() != FeatureStatus_Available)
|
||||
return false;
|
||||
|
||||
if (command == NULL)
|
||||
{
|
||||
m_pForward->AddFunction(fun);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *str = UTIL_ToLowerCase(command);
|
||||
Listener *listener;
|
||||
Listener **plistener = m_CmdLookup.retrieve(str);
|
||||
if (plistener == NULL)
|
||||
{
|
||||
listener = new Listener;
|
||||
listener->forward = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
|
||||
Param_String, Param_Cell);
|
||||
m_CmdLookup.insert(str, listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
listener = *plistener;
|
||||
}
|
||||
listener->forward->AddFunction(fun);
|
||||
delete [] str;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
|
||||
{
|
||||
if (command == NULL)
|
||||
{
|
||||
return m_pForward->RemoveFunction(fun);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *str = UTIL_ToLowerCase(command);
|
||||
Listener *listener;
|
||||
Listener **plistener = m_CmdLookup.retrieve(str);
|
||||
delete [] str;
|
||||
if (plistener == NULL)
|
||||
return false;
|
||||
listener = *plistener;
|
||||
return listener->forward->RemoveFunction(fun);
|
||||
}
|
||||
}
|
||||
|
||||
cell_t ConsoleDetours::InternalDispatch(int client, const CCommand& args)
|
||||
{
|
||||
char name[255];
|
||||
const char *realname = args.Arg(0);
|
||||
size_t len = strlen(realname);
|
||||
|
||||
// Disallow command strings that are too long, for now.
|
||||
if (len >= sizeof(name) - 1)
|
||||
return Pl_Continue;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (realname[i] >= 'A' && realname[i] <= 'Z')
|
||||
name[i] = tolower(realname[i]);
|
||||
else
|
||||
name[i] = realname[i];
|
||||
}
|
||||
name[len] = '\0';
|
||||
|
||||
cell_t result = Pl_Continue;
|
||||
m_pForward->PushCell(client);
|
||||
m_pForward->PushString(name);
|
||||
m_pForward->PushCell(args.ArgC() - 1);
|
||||
m_pForward->Execute(&result, NULL);
|
||||
|
||||
/* Don't let plugins block this. */
|
||||
if (strcmp(name, "sm") == 0)
|
||||
result = Pl_Continue;
|
||||
|
||||
if (result >= Pl_Handled)
|
||||
return result;
|
||||
|
||||
Listener **plistener = m_CmdLookup.retrieve(name);
|
||||
if (plistener == NULL)
|
||||
return result;
|
||||
Listener *listener = *plistener;
|
||||
if (listener->forward->GetFunctionCount() == 0)
|
||||
return result;
|
||||
|
||||
cell_t result2 = Pl_Continue;
|
||||
listener->forward->PushCell(client);
|
||||
listener->forward->PushString(name);
|
||||
listener->forward->PushCell(args.ArgC() - 1);
|
||||
listener->forward->Execute(&result2, NULL);
|
||||
|
||||
if (result2 > result)
|
||||
result = result2;
|
||||
|
||||
/* "sm" should not have flown through the above. */
|
||||
assert(strcmp(name, "sm") != 0 || result == Pl_Continue);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
cell_t ConsoleDetours::Dispatch(ConCommand *pBase, const CCommand& args)
|
||||
{
|
||||
#else
|
||||
cell_t ConsoleDetours::Dispatch(ConCommand *pBase)
|
||||
{
|
||||
CCommand args;
|
||||
#endif
|
||||
g_HL2.PushCommandStack(&args);
|
||||
cell_t res = g_ConsoleDetours.InternalDispatch(g_ConCmds.GetCommandClient(), args);
|
||||
g_HL2.PopCommandStack();
|
||||
|
||||
#if SH_IMPL_VERSION < 4
|
||||
if (res >= Pl_Handled)
|
||||
{
|
||||
/* See bug 4020 - we can't optimize this because looking at the vtable
|
||||
* is probably more expensive, since there's no SH_GET_ORIG_VFNPTR_ENTRY.
|
||||
*/
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pBase, DummyHook, false);
|
||||
dummy_hook_set = true;
|
||||
pBase->Dispatch();
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, pBase, DummyHook, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure the command gets invoked. See bug 4019 on making this better. */
|
||||
pBase->Dispatch();
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#ifndef _INCLUDE_SOURCEMOD_CONSOLE_DETOURS_H_
|
||||
#define _INCLUDE_SOURCEMOD_CONSOLE_DETOURS_H_
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "ForwardSys.h"
|
||||
#include <sm_trie_tpl.h>
|
||||
|
||||
class ConsoleDetours :
|
||||
public SMGlobalClass,
|
||||
public IFeatureProvider
|
||||
{
|
||||
friend class PlayerManager;
|
||||
friend class GenericCommandHooker;
|
||||
|
||||
struct Listener
|
||||
{
|
||||
IChangeableForward *forward;
|
||||
};
|
||||
public:
|
||||
ConsoleDetours();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
public: //IFeatureProvider
|
||||
FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
|
||||
public:
|
||||
bool AddListener(IPluginFunction *fun, const char *command);
|
||||
bool RemoveListener(IPluginFunction *fun, const char *command);
|
||||
private:
|
||||
cell_t InternalDispatch(int client, const CCommand& args);
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
static cell_t Dispatch(ConCommand *pBase, const CCommand& args);
|
||||
#else
|
||||
static cell_t Dispatch(ConCommand *pBase);
|
||||
#endif
|
||||
public:
|
||||
FeatureStatus GetStatus();
|
||||
bool IsEnabled()
|
||||
{
|
||||
return status == FeatureStatus_Available;
|
||||
}
|
||||
private:
|
||||
FeatureStatus status;
|
||||
IChangeableForward *m_pForward;
|
||||
KTrie<Listener*> m_CmdLookup;
|
||||
List<Listener*> m_Listeners;
|
||||
};
|
||||
|
||||
extern ConsoleDetours g_ConsoleDetours;
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_CONSOLE_DETOURS_H_ */
|
||||
|
||||
+181
-15
@@ -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,29 +34,97 @@
|
||||
#include "sourcemod.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_srvcmds.h"
|
||||
#include "sm_version.h"
|
||||
#include <sourcemod_version.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "Logger.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ForwardSys.h"
|
||||
#include "frame_hooks.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
|
||||
#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 SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
void Hook_ExecDispatchPre(const CCommand &cmd)
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
void Hook_ExecDispatchPre()
|
||||
#else
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
void Hook_ExecDispatchPre()
|
||||
#endif
|
||||
{
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
CCommand cmd;
|
||||
#endif
|
||||
|
||||
const char *arg = cmd.Arg(1);
|
||||
|
||||
if (!g_bServerExecd && arg != NULL && strcmp(arg, g_ServerCfgFile->GetString()) == 0)
|
||||
{
|
||||
g_bGotTrigger = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
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)
|
||||
{
|
||||
g_PendingInternalPush = true;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
CoreConfig::CoreConfig() : m_Strings(512)
|
||||
{
|
||||
}
|
||||
|
||||
CoreConfig::~CoreConfig()
|
||||
{
|
||||
}
|
||||
|
||||
void CoreConfig::OnSourceModShutdown()
|
||||
@@ -64,11 +132,51 @@ 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)
|
||||
{
|
||||
g_pExecPtr = FindCommand("exec");
|
||||
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)
|
||||
@@ -85,17 +193,30 @@ void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &comma
|
||||
|
||||
if (res == ConfigResult_Reject)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
|
||||
g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\". (%s)", option, value, error);
|
||||
} else if (res == ConfigResult_Ignore) {
|
||||
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||
} else {
|
||||
g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
|
||||
g_RootMenu.ConsolePrint("[SM] Config option \"%s\" successfully set to \"%s\".", option, value);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (argcount >= 3) {
|
||||
const char *option = command.Arg(2);
|
||||
|
||||
const char *value = GetCoreConfigValue(option);
|
||||
|
||||
if (value == NULL)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||
} else {
|
||||
g_RootMenu.ConsolePrint("[SM] Config option \"%s\" is set to \"%s\".", option, value);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> [value]");
|
||||
}
|
||||
|
||||
void CoreConfig::Initialize()
|
||||
@@ -106,14 +227,32 @@ void CoreConfig::Initialize()
|
||||
/* Try to get command line value of core config convar */
|
||||
const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
|
||||
|
||||
/* If sm_corecfgfile not specified on command line, use default value */
|
||||
if (!corecfg)
|
||||
/* If sm_corecfgfile is on the command line, use that
|
||||
* If sm_corecfgfile isn't there, check sm_basepath on the command line and build the path off that
|
||||
* If sm_basepath isn't there, just use the default path for the cfg
|
||||
*/
|
||||
if (corecfg)
|
||||
{
|
||||
corecfg = sm_corecfgfile.GetDefault();
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *basepath = icvar->GetCommandLineValue("sm_basepath");
|
||||
|
||||
/* Format path to config file */
|
||||
if (basepath)
|
||||
{
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s/%s", g_SourceMod.GetGamePath(), basepath, "configs/core.cfg");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), sm_corecfgfile.GetDefault());
|
||||
}
|
||||
}
|
||||
|
||||
/* Format path to config file */
|
||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||
/* Reset cached key values */
|
||||
m_KeyValues.clear();
|
||||
m_Strings.Reset();
|
||||
|
||||
/* Parse config file */
|
||||
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
|
||||
@@ -153,9 +292,21 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
|
||||
pBase = pBase->m_pGlobalClassNext;
|
||||
}
|
||||
|
||||
m_KeyValues.replace(option, m_Strings.AddString(value));
|
||||
|
||||
return ConfigResult_Ignore;
|
||||
}
|
||||
|
||||
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
||||
{
|
||||
int *pKey = m_KeyValues.retrieve(key);
|
||||
if (pKey == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return m_Strings.GetString(*pKey);
|
||||
}
|
||||
|
||||
bool SM_AreConfigsExecuted()
|
||||
{
|
||||
return g_bConfigsExecd;
|
||||
@@ -165,7 +316,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
|
||||
}
|
||||
@@ -257,7 +408,7 @@ bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
FILE *fp = fopen(file, "wt");
|
||||
if (fp)
|
||||
{
|
||||
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
|
||||
fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SM_VERSION_STRING);
|
||||
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
|
||||
fprintf(fp, "\n\n");
|
||||
|
||||
@@ -314,6 +465,11 @@ bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||
can_create = false;
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Logger.LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
|
||||
return can_create;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +538,7 @@ void SM_ExecuteForPlugin(IPluginContext *ctx)
|
||||
|
||||
void SM_ExecuteAllConfigs()
|
||||
{
|
||||
if (g_bConfigsExecd)
|
||||
if (g_bGotServerStart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -403,7 +559,8 @@ void SM_ExecuteAllConfigs()
|
||||
}
|
||||
iter->Release();
|
||||
|
||||
engine->ServerCommand("sm internal 1\n");
|
||||
g_bGotServerStart = true;
|
||||
CheckAndFinalizeConfigs();
|
||||
}
|
||||
|
||||
void SM_ConfigsExecuted_Global()
|
||||
@@ -418,3 +575,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;
|
||||
}
|
||||
|
||||
|
||||
+11
-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
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "sm_globals.h"
|
||||
#include <ITextParsers.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_memtable.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
@@ -43,6 +45,9 @@ class CoreConfig :
|
||||
public ITextListener_SMC,
|
||||
public IRootConsoleCommand
|
||||
{
|
||||
public:
|
||||
CoreConfig();
|
||||
~CoreConfig();
|
||||
public: // SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
@@ -56,11 +61,15 @@ public:
|
||||
* Initializes CoreConfig by reading from core.cfg file
|
||||
*/
|
||||
void Initialize();
|
||||
const char *GetCoreConfigValue(const char *key);
|
||||
private:
|
||||
/**
|
||||
* Sets configuration option by notifying SourceMod components that rely on core.cfg
|
||||
*/
|
||||
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
||||
private:
|
||||
BaseStringTable m_Strings;
|
||||
KTrie<int> m_KeyValues;
|
||||
};
|
||||
|
||||
extern bool SM_AreConfigsExecuted();
|
||||
@@ -68,6 +77,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
|
||||
|
||||
+48
-33
@@ -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
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "Logger.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include <stdlib.h>
|
||||
#include "ThreadSupport.h"
|
||||
#include <IThreader.h>
|
||||
|
||||
#define DBPARSE_LEVEL_NONE 0
|
||||
#define DBPARSE_LEVEL_MAIN 1
|
||||
@@ -47,7 +47,7 @@ DBManager g_DBMan;
|
||||
static bool s_OneTimeThreaderErrorMsg = false;
|
||||
|
||||
DBManager::DBManager()
|
||||
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
|
||||
: m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ void DBManager::OnSourceModShutdown()
|
||||
m_pQueueLock->DestroyThis();
|
||||
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
|
||||
ClearConfigs();
|
||||
}
|
||||
|
||||
unsigned int DBManager::GetInterfaceVersion()
|
||||
@@ -133,13 +134,20 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
|
||||
void DBManager::ReadSMC_ParseStart()
|
||||
{
|
||||
m_confs.clear();
|
||||
ClearConfigs();
|
||||
m_ParseLevel = 0;
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
m_StrTab.Reset();
|
||||
m_DefDriver.clear();
|
||||
}
|
||||
|
||||
void DBManager::ClearConfigs()
|
||||
{
|
||||
List<ConfDbInfo *>::iterator iter;
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
delete (*iter);
|
||||
m_confs.clear();
|
||||
}
|
||||
|
||||
ConfDbInfo s_CurInfo;
|
||||
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
{
|
||||
@@ -159,7 +167,7 @@ SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *nam
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||
s_CurInfo = ConfDbInfo();
|
||||
s_CurInfo.name = m_StrTab.AddString(name);
|
||||
s_CurInfo.name = name;
|
||||
m_ParseState = DBPARSE_LEVEL_DATABASE;
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
m_ParseLevel++;
|
||||
@@ -186,16 +194,16 @@ SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
||||
{
|
||||
if (strcmp(value, "default") != 0)
|
||||
{
|
||||
s_CurInfo.driver = m_StrTab.AddString(value);
|
||||
s_CurInfo.driver = value;
|
||||
}
|
||||
} else if (strcmp(key, "database") == 0) {
|
||||
s_CurInfo.database = m_StrTab.AddString(value);
|
||||
s_CurInfo.database = value;
|
||||
} else if (strcmp(key, "host") == 0) {
|
||||
s_CurInfo.host = m_StrTab.AddString(value);
|
||||
s_CurInfo.host = value;
|
||||
} else if (strcmp(key, "user") == 0) {
|
||||
s_CurInfo.user = m_StrTab.AddString(value);
|
||||
s_CurInfo.user = value;
|
||||
} else if (strcmp(key, "pass") == 0) {
|
||||
s_CurInfo.pass = m_StrTab.AddString(value);
|
||||
s_CurInfo.pass = value;
|
||||
} else if (strcmp(key, "timeout") == 0) {
|
||||
s_CurInfo.info.maxTimeout = atoi(value);
|
||||
} else if (strcmp(key, "port") == 0) {
|
||||
@@ -206,13 +214,6 @@ SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
#define ASSIGN_VAR(var) \
|
||||
if (s_CurInfo.var == -1) { \
|
||||
s_CurInfo.info.var = ""; \
|
||||
} else { \
|
||||
s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
|
||||
}
|
||||
|
||||
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
@@ -223,17 +224,26 @@ SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||
{
|
||||
/* Set all of the info members to either a blank string
|
||||
* or the string pointer from the string table.
|
||||
*/
|
||||
ASSIGN_VAR(driver);
|
||||
ASSIGN_VAR(database);
|
||||
ASSIGN_VAR(host);
|
||||
ASSIGN_VAR(user);
|
||||
ASSIGN_VAR(pass);
|
||||
ConfDbInfo *cdb = new ConfDbInfo();
|
||||
|
||||
cdb->name = s_CurInfo.name;
|
||||
cdb->driver = s_CurInfo.driver;
|
||||
cdb->host = s_CurInfo.host;
|
||||
cdb->user = s_CurInfo.user;
|
||||
cdb->pass = s_CurInfo.pass;
|
||||
cdb->database = s_CurInfo.database;
|
||||
cdb->realDriver = s_CurInfo.realDriver;
|
||||
cdb->info.maxTimeout = s_CurInfo.info.maxTimeout;
|
||||
cdb->info.port = s_CurInfo.info.port;
|
||||
|
||||
cdb->info.driver = cdb->driver.c_str();
|
||||
cdb->info.database = cdb->database.c_str();
|
||||
cdb->info.host = cdb->host.c_str();
|
||||
cdb->info.user = cdb->user.c_str();
|
||||
cdb->info.pass = cdb->pass.c_str();
|
||||
|
||||
/* Save it.. */
|
||||
m_confs.push_back(s_CurInfo);
|
||||
m_confs.push_back(cdb);
|
||||
|
||||
/* Go up one level */
|
||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||
@@ -244,7 +254,6 @@ SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
#undef ASSIGN_VAR
|
||||
|
||||
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||
{
|
||||
@@ -333,10 +342,10 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
}
|
||||
|
||||
/* Make sure NOTHING references this! */
|
||||
List<ConfDbInfo>::iterator iter;
|
||||
List<ConfDbInfo *>::iterator iter;
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
ConfDbInfo &db = (*iter);
|
||||
ConfDbInfo &db = *(*iter);
|
||||
if (db.realDriver == pDriver)
|
||||
{
|
||||
db.realDriver = NULL;
|
||||
@@ -448,12 +457,12 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
||||
|
||||
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
|
||||
{
|
||||
List<ConfDbInfo>::iterator iter;
|
||||
List<ConfDbInfo *>::iterator iter;
|
||||
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
ConfDbInfo &conf = (*iter);
|
||||
if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
|
||||
ConfDbInfo &conf = *(*iter);
|
||||
if (conf.name == name)
|
||||
{
|
||||
return &conf;
|
||||
}
|
||||
@@ -717,3 +726,9 @@ const char *DBManager::GetDefaultDriverName()
|
||||
{
|
||||
return m_DefDriver.c_str();
|
||||
}
|
||||
|
||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||
{
|
||||
g_Extensions.AddRawDependency(myself, driver->GetIdentity(), driver);
|
||||
}
|
||||
|
||||
|
||||
+11
-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
|
||||
@@ -47,16 +47,15 @@ using namespace SourceHook;
|
||||
|
||||
struct ConfDbInfo
|
||||
{
|
||||
ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
|
||||
database(-1), realDriver(NULL)
|
||||
ConfDbInfo() : realDriver(NULL)
|
||||
{
|
||||
}
|
||||
int name;
|
||||
int driver;
|
||||
int host;
|
||||
int user;
|
||||
int pass;
|
||||
int database;
|
||||
String name;
|
||||
String driver;
|
||||
String host;
|
||||
String user;
|
||||
String pass;
|
||||
String database;
|
||||
IDBDriver *realDriver;
|
||||
DatabaseInfo info;
|
||||
};
|
||||
@@ -92,6 +91,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);
|
||||
@@ -120,6 +120,7 @@ public:
|
||||
return m_DatabaseType;
|
||||
}
|
||||
private:
|
||||
void ClearConfigs();
|
||||
void KillWorkerThread();
|
||||
private:
|
||||
CVector<IDBDriver *> m_drivers;
|
||||
@@ -133,11 +134,10 @@ private:
|
||||
IMutex *m_pQueueLock; /* Queue safety lock */
|
||||
IMutex *m_pThinkLock; /* Think-queue lock */
|
||||
|
||||
List<ConfDbInfo> m_confs;
|
||||
List<ConfDbInfo *> m_confs;
|
||||
HandleType_t m_DriverType;
|
||||
HandleType_t m_DatabaseType;
|
||||
String m_DefDriver;
|
||||
BaseStringTable m_StrTab;
|
||||
char m_Filename[PLATFORM_MAX_PATH];
|
||||
unsigned int m_ParseLevel;
|
||||
unsigned int m_ParseState;
|
||||
|
||||
+29
-14
@@ -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,27 +36,39 @@
|
||||
|
||||
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::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
||||
void DebugReport::OnDebugSpew(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, message);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||
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;
|
||||
|
||||
va_start(ap, message);
|
||||
GenerateErrorVA(ctx, func_idx, err, message, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap)
|
||||
{
|
||||
char buffer[512];
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, 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 +85,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 +103,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 +115,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 +193,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,7 +43,10 @@ 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 GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
|
||||
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
||||
private:
|
||||
int _GetPluginIndex(IPluginContext *ctx);
|
||||
|
||||
+89
-22
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -42,6 +42,20 @@ SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *,
|
||||
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
|
||||
typedef List<EventHook *> EventHookList;
|
||||
|
||||
class EventForwardFilter : public IForwardFilter
|
||||
{
|
||||
EventInfo *pEventInfo;
|
||||
public:
|
||||
EventForwardFilter(EventInfo *pEventInfo) : pEventInfo(pEventInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
|
||||
{
|
||||
params[2].val = pEventInfo->bDontBroadcast ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
EventManager::EventManager() : m_EventType(0)
|
||||
{
|
||||
/* Create an event lookup trie */
|
||||
@@ -147,6 +161,13 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
|
||||
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
int EventManager::GetEventDebugID()
|
||||
{
|
||||
return EVENT_DEBUG_ID_INIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
|
||||
{
|
||||
EventHook *pHook;
|
||||
@@ -193,6 +214,9 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
||||
pHook->pPostHook->AddFunction(pFunction);
|
||||
}
|
||||
|
||||
/* Cache the name for post hooks */
|
||||
pHook->name = sm_strdup(name);
|
||||
|
||||
/* Increase reference count */
|
||||
pHook->refCount++;
|
||||
|
||||
@@ -296,6 +320,9 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
||||
/* Delete entry in trie */
|
||||
sm_trie_delete(m_EventHooks, name);
|
||||
|
||||
/* Free the cached name */
|
||||
delete pHook->name;
|
||||
|
||||
/* And finally free structure memory */
|
||||
delete pHook;
|
||||
}
|
||||
@@ -321,6 +348,7 @@ EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name,
|
||||
|
||||
pInfo->pEvent = pEvent;
|
||||
pInfo->pOwner = pContext->GetIdentity();
|
||||
pInfo->bDontBroadcast = false;
|
||||
|
||||
return pInfo;
|
||||
}
|
||||
@@ -359,33 +387,49 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
IChangeableForward *pForward;
|
||||
const char *name;
|
||||
cell_t res = Pl_Continue;
|
||||
|
||||
/* Get the event name, we're going to need this for passing to post hooks */
|
||||
bool broadcast = bDontBroadcast;
|
||||
|
||||
/* 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 = pEvent->GetName();
|
||||
|
||||
m_EventNames.push(name);
|
||||
|
||||
|
||||
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
|
||||
{
|
||||
/* Push the event onto the event stack. The reference count is increased to make sure
|
||||
* the structure is not garbage collected in between now and the post hook.
|
||||
*/
|
||||
pHook->refCount++;
|
||||
m_EventStack.push(pHook);
|
||||
|
||||
pForward = pHook->pPreHook;
|
||||
|
||||
if (pForward)
|
||||
{
|
||||
EventInfo info = { pEvent, NULL };
|
||||
|
||||
EventInfo info(pEvent, NULL);
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
info.bDontBroadcast = bDontBroadcast;
|
||||
|
||||
EventForwardFilter filter(&info);
|
||||
|
||||
pForward->PushCell(hndl);
|
||||
pForward->PushString(name);
|
||||
pForward->PushCell(bDontBroadcast);
|
||||
pForward->Execute(&res, NULL);
|
||||
pForward->Execute(&res, &filter);
|
||||
|
||||
broadcast = info.bDontBroadcast;
|
||||
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
}
|
||||
|
||||
if (pHook->postCopy)
|
||||
{
|
||||
pHook->pEventCopy = gameevents->DuplicateEvent(pEvent);
|
||||
m_EventCopies.push(gameevents->DuplicateEvent(pEvent));
|
||||
}
|
||||
|
||||
if (res)
|
||||
@@ -394,6 +438,13 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_EventStack.push(NULL);
|
||||
}
|
||||
|
||||
if (broadcast != bDontBroadcast)
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &IGameEventManager2::FireEvent, (pEvent, broadcast));
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
@@ -401,24 +452,30 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
/* IGameEventManager2::FireEvent post hook */
|
||||
bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
{
|
||||
IGameEvent *pEventCopy = NULL;
|
||||
EventHook *pHook;
|
||||
EventInfo info;
|
||||
IChangeableForward *pForward;
|
||||
const char *name;
|
||||
Handle_t hndl = 0;
|
||||
|
||||
name = m_EventNames.front();
|
||||
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
|
||||
if (!pEvent)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
|
||||
pHook = m_EventStack.front();
|
||||
|
||||
if (pHook != NULL)
|
||||
{
|
||||
pForward = pHook->pPostHook;
|
||||
|
||||
if (pForward)
|
||||
{
|
||||
EventInfo info = { pHook->pEventCopy, NULL };
|
||||
|
||||
if (pHook->postCopy)
|
||||
{
|
||||
info.bDontBroadcast = bDontBroadcast;
|
||||
info.pEvent = m_EventCopies.front();
|
||||
info.pOwner = NULL;
|
||||
hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
pForward->PushCell(hndl);
|
||||
@@ -426,7 +483,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
pForward->PushCell(BAD_HANDLE);
|
||||
}
|
||||
|
||||
pForward->PushString(name);
|
||||
pForward->PushString(pHook->name);
|
||||
pForward->PushCell(bDontBroadcast);
|
||||
pForward->Execute(NULL);
|
||||
|
||||
@@ -437,13 +494,23 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
|
||||
/* Free event structure */
|
||||
gameevents->FreeEvent(pEventCopy);
|
||||
pHook->pEventCopy = NULL;
|
||||
gameevents->FreeEvent(info.pEvent);
|
||||
m_EventCopies.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement reference count, check if a delayed delete is needed */
|
||||
if (--pHook->refCount == 0)
|
||||
{
|
||||
assert(pHook->pPostHook == NULL);
|
||||
assert(pHook->pPreHook == NULL);
|
||||
sm_trie_delete(m_EventHooks, pHook->name);
|
||||
delete pHook->name;
|
||||
delete pHook;
|
||||
}
|
||||
}
|
||||
|
||||
m_EventNames.pop();
|
||||
m_EventStack.pop();
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
+14
-4
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -45,8 +45,15 @@ using namespace SourceHook;
|
||||
|
||||
struct EventInfo
|
||||
{
|
||||
EventInfo()
|
||||
{
|
||||
}
|
||||
EventInfo(IGameEvent *ev, IdentityToken_t *owner) : pEvent(ev), pOwner(owner)
|
||||
{
|
||||
}
|
||||
IGameEvent *pEvent;
|
||||
IdentityToken_t *pOwner;
|
||||
bool bDontBroadcast;
|
||||
};
|
||||
|
||||
struct EventHook
|
||||
@@ -56,14 +63,13 @@ struct EventHook
|
||||
pPreHook = NULL;
|
||||
pPostHook = NULL;
|
||||
postCopy = false;
|
||||
pEventCopy = NULL;
|
||||
refCount = 0;
|
||||
}
|
||||
IChangeableForward *pPreHook;
|
||||
IChangeableForward *pPostHook;
|
||||
bool postCopy;
|
||||
IGameEvent *pEventCopy;
|
||||
unsigned int refCount;
|
||||
char *name;
|
||||
};
|
||||
|
||||
enum EventHookMode
|
||||
@@ -99,6 +105,9 @@ public: // IPluginsListener
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public: // IGameEventListener2
|
||||
void FireGameEvent(IGameEvent *pEvent);
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
int GetEventDebugID();
|
||||
#endif
|
||||
public:
|
||||
/**
|
||||
* Get the 'GameEvent' handle type ID.
|
||||
@@ -120,7 +129,8 @@ private:
|
||||
HandleType_t m_EventType;
|
||||
Trie *m_EventHooks;
|
||||
CStack<EventInfo *> m_FreeEvents;
|
||||
CStack<const char *> m_EventNames;
|
||||
CStack<EventHook *> m_EventStack;
|
||||
CStack<IGameEvent *> m_EventCopies;
|
||||
};
|
||||
|
||||
extern EventManager g_EventManager;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_srvcmds.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "PlayerManager.h"
|
||||
|
||||
CExtensionManager g_Extensions;
|
||||
IdentityType_t g_ExtType;
|
||||
@@ -49,6 +50,9 @@ void CExtension::Initialize(const char *filename, const char *path)
|
||||
m_bFullyLoaded = false;
|
||||
m_File.assign(filename);
|
||||
m_Path.assign(path);
|
||||
char real_name[PLATFORM_MAX_PATH];
|
||||
g_LibSys.GetFileFromPath(real_name, sizeof(real_name), m_Path.c_str());
|
||||
m_RealFile.assign(real_name);
|
||||
}
|
||||
|
||||
CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
|
||||
@@ -57,6 +61,42 @@ CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filena
|
||||
m_pAPI = pAPI;
|
||||
}
|
||||
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||
#define GAMEFIX "2.l4d"
|
||||
#elif SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
#define GAMEFIX "2.l4d2"
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
#define GAMEFIX "2.nd"
|
||||
#elif SOURCE_ENGINE == SE_ALIENSWARM
|
||||
#define GAMEFIX "2.swarm"
|
||||
#elif SOURCE_ENGINE == SE_ORANGEBOX
|
||||
#define GAMEFIX "2.ep2"
|
||||
#elif SOURCE_ENGINE == SE_BLOODYGOODTIME
|
||||
#define GAMEFIX "2.bgt"
|
||||
#elif SOURCE_ENGINE == SE_EYE
|
||||
#define GAMEFIX "2.eye"
|
||||
#elif SOURCE_ENGINE == SE_CSS
|
||||
#define GAMEFIX "2.css"
|
||||
#elif SOURCE_ENGINE == SE_HL2DM
|
||||
#define GAMEFIX "2.hl2dm"
|
||||
#elif SOURCE_ENGINE == SE_DODS
|
||||
#define GAMEFIX "2.dods"
|
||||
#elif SOURCE_ENGINE == SE_TF2
|
||||
#define GAMEFIX "2.tf2"
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
#define GAMEFIX "2.darkm"
|
||||
#elif SOURCE_ENGINE == SE_PORTAL2
|
||||
#define GAMEFIX "2.portal2"
|
||||
#elif SOURCE_ENGINE == SE_CSGO
|
||||
#define GAMEFIX "2.csgo"
|
||||
#else
|
||||
#define GAMEFIX "2.ep1"
|
||||
#endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
|
||||
#else //METAMOD_PLAPI_VERSION
|
||||
#define GAMEFIX "1.ep1"
|
||||
#endif //METAMOD_PLAPI_VERSION
|
||||
|
||||
CLocalExtension::CLocalExtension(const char *filename)
|
||||
{
|
||||
m_PlId = 0;
|
||||
@@ -64,27 +104,68 @@ CLocalExtension::CLocalExtension(const char *filename)
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
|
||||
/* Special case for new bintools binary */
|
||||
if (strcmp(filename, "bintools.ext") == 0)
|
||||
{
|
||||
goto normal;
|
||||
}
|
||||
|
||||
/* Zeroth, see if there is an engine specific build in the new place. */
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s." GAMEFIX "." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
|
||||
if (g_LibSys.IsPathFile(path))
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM
|
||||
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
|
||||
if (g_LibSys.IsPathFile(path))
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
|
||||
if (g_LibSys.IsPathFile(path))
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* First see if there is an engine specific build! */
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
#if defined ORANGEBOX_BUILD
|
||||
"extensions/auto.2.ep2/%s",
|
||||
#else
|
||||
"extensions/auto.2.ep1/%s",
|
||||
#endif //ORANGEBOX_BUILD
|
||||
#else //METAMOD_PLAPI_VERSION
|
||||
"extensions/auto.1.ep1/%s",
|
||||
#endif //METAMOD_PLAPI_VERSION
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/auto." GAMEFIX "/%s." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
|
||||
/* Try the "normal" version */
|
||||
if (!g_LibSys.IsPathFile(path))
|
||||
{
|
||||
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
|
||||
normal:
|
||||
g_SourceMod.BuildPath(Path_SM,
|
||||
path,
|
||||
PLATFORM_MAX_PATH,
|
||||
"extensions/%s." PLATFORM_LIB_EXT,
|
||||
filename);
|
||||
}
|
||||
|
||||
found:
|
||||
Initialize(filename, path);
|
||||
}
|
||||
|
||||
@@ -141,6 +222,28 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
bool already;
|
||||
m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
|
||||
|
||||
// Check the plugin didn't refuse load
|
||||
Pl_Status status;
|
||||
|
||||
#ifndef METAMOD_PLAPI_VERSION
|
||||
const char *file;
|
||||
PluginId source;
|
||||
#endif
|
||||
|
||||
if (!m_PlId || (
|
||||
#ifndef METAMOD_PLAPI_VERSION
|
||||
g_pMMPlugins->Query(m_PlId, file, status, source)
|
||||
#else
|
||||
g_pMMPlugins->Query(m_PlId, NULL, &status, NULL)
|
||||
#endif
|
||||
&& status < Pl_Paused))
|
||||
{
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
m_pAPI = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CExtension::Load(error, maxlength))
|
||||
@@ -183,6 +286,23 @@ void CLocalExtension::Unload()
|
||||
}
|
||||
}
|
||||
|
||||
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
||||
{
|
||||
snprintf(error, maxlength, "Remote extensions do not support reloading");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CLocalExtension::Reload(char *error, size_t maxlength)
|
||||
{
|
||||
if (m_pLib == NULL) // FIXME: just load it instead?
|
||||
return false;
|
||||
|
||||
m_pAPI->OnExtensionUnload();
|
||||
Unload();
|
||||
|
||||
return Load(error, maxlength);
|
||||
}
|
||||
|
||||
bool CRemoteExtension::IsExternal()
|
||||
{
|
||||
return true;
|
||||
@@ -266,43 +386,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +407,12 @@ IExtensionInterface *CExtension::GetAPI()
|
||||
|
||||
const char *CExtension::GetFilename()
|
||||
{
|
||||
return m_File.c_str();
|
||||
return m_RealFile.c_str();
|
||||
}
|
||||
|
||||
const char *CExtension::GetPath() const
|
||||
{
|
||||
return m_Path.c_str();
|
||||
}
|
||||
|
||||
IdentityToken_t *CExtension::GetIdentity()
|
||||
@@ -336,7 +430,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())
|
||||
{
|
||||
@@ -521,7 +615,7 @@ void CExtensionManager::TryAutoload()
|
||||
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
len = UTIL_Format(file, sizeof(file), "%s", lfile);
|
||||
strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
|
||||
strcpy(&file[len - 9], ".ext");
|
||||
|
||||
LoadAutoExtension(file);
|
||||
|
||||
@@ -529,13 +623,16 @@ void CExtensionManager::TryAutoload()
|
||||
}
|
||||
}
|
||||
|
||||
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
||||
IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOnMissing)
|
||||
{
|
||||
if (!strstr(path, "." PLATFORM_LIB_EXT))
|
||||
/* Remove platform extension if it's there. Compat hack. */
|
||||
const char *ext = g_LibSys.GetFileExtension(path);
|
||||
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||
{
|
||||
char newpath[PLATFORM_MAX_PATH];
|
||||
g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
|
||||
return LoadAutoExtension(newpath);
|
||||
char path2[PLATFORM_MAX_PATH];
|
||||
UTIL_Format(path2, sizeof(path2), "%s", path);
|
||||
path2[strlen(path) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
|
||||
return LoadAutoExtension(path2, bErrorOnMissing);
|
||||
}
|
||||
|
||||
IExtension *pAlready;
|
||||
@@ -554,7 +651,11 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
||||
|
||||
if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
|
||||
if (bErrorOnMissing || g_LibSys.IsPathFile(p->GetPath()))
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
|
||||
}
|
||||
|
||||
p->SetError(error);
|
||||
}
|
||||
|
||||
@@ -573,24 +674,12 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
|
||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
||||
{
|
||||
pExt = (*iter);
|
||||
char short_file[PLATFORM_MAX_PATH];
|
||||
g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
|
||||
if (strcmp(lookup, short_file) == 0)
|
||||
if (pExt->IsSameFile(lookup))
|
||||
{
|
||||
return pExt;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got no results, test if there was a platform extension.
|
||||
* If not, add one.
|
||||
*/
|
||||
if (!strstr(file, "." PLATFORM_LIB_EXT))
|
||||
{
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
|
||||
return FindExtensionByFile(path);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -628,6 +717,16 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
||||
|
||||
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
||||
{
|
||||
/* Remove platform extension if it's there. Compat hack. */
|
||||
const char *ext = g_LibSys.GetFileExtension(file);
|
||||
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||
{
|
||||
char path2[PLATFORM_MAX_PATH];
|
||||
UTIL_Format(path2, sizeof(path2), "%s", file);
|
||||
path2[strlen(file) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
|
||||
return LoadExtension(path2, error, maxlength);
|
||||
}
|
||||
|
||||
IExtension *pAlready;
|
||||
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
||||
{
|
||||
@@ -664,6 +763,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 +784,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 +797,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 +822,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)
|
||||
@@ -794,6 +836,13 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Tell it to unload */
|
||||
if (pExt->IsLoaded())
|
||||
{
|
||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||
pAPI->OnExtensionUnload();
|
||||
}
|
||||
|
||||
/* First remove us from internal lists */
|
||||
g_ShareSys.RemoveInterfaces(_pExt);
|
||||
m_Libs.remove(pExt);
|
||||
@@ -804,12 +853,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;
|
||||
@@ -817,31 +866,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
s_iter != pExt->m_Libraries.end();
|
||||
s_iter++)
|
||||
{
|
||||
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;
|
||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), LibraryAction_Removed);
|
||||
}
|
||||
|
||||
/* Notify and/or unload all dependencies */
|
||||
@@ -898,44 +923,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;
|
||||
@@ -962,44 +950,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;
|
||||
@@ -1085,11 +1035,42 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (strcmp(cmd, "load") == 0)
|
||||
{
|
||||
if (argcount < 4)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm exts load <file>");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filename = command.Arg(3);
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
char error[256];
|
||||
|
||||
UTIL_Format(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "",
|
||||
!strstr(filename, "." PLATFORM_LIB_EXT) ? "." PLATFORM_LIB_EXT : "");
|
||||
|
||||
if (FindExtensionByFile(path) != NULL)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Extension %s is already loaded.", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LoadExtension(path, error, sizeof(error)))
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Loaded extension %s successfully.", path);
|
||||
} else
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Extension %s failed to load: %s", path, error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (strcmp(cmd, "info") == 0)
|
||||
{
|
||||
if (argcount < 4)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm exts info <#>");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1097,7 +1078,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
unsigned int id = atoi(sId);
|
||||
if (id <= 0)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm exts info <#>");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1174,7 +1155,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
{
|
||||
if (argcount < 4)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm exts unload <#> [code]");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1206,7 +1187,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 +1197,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 +1227,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 +1241,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())
|
||||
@@ -1287,14 +1268,148 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (strcmp(cmd, "reload") == 0)
|
||||
{
|
||||
if (argcount < 4)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm exts reload <#>");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *arg = command.Arg(3);
|
||||
unsigned int num = atoi(arg);
|
||||
CExtension *pExt = FindByOrder(num);
|
||||
|
||||
if (!pExt)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pExt->IsLoaded())
|
||||
{
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
char error[255];
|
||||
|
||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||
|
||||
if (pExt->Reload(error, sizeof(error)))
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Extension %s is now reloaded.", filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Extension %s failed to reload: %s", filename, error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Extension %s is not loaded.", pExt->GetFilename());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
|
||||
g_RootMenu.DrawGenericOption("info", "Extra extension information");
|
||||
g_RootMenu.DrawGenericOption("list", "List extensions");
|
||||
g_RootMenu.DrawGenericOption("load", "Load an extension");
|
||||
g_RootMenu.DrawGenericOption("reload", "Reload an extension");
|
||||
g_RootMenu.DrawGenericOption("unload", "Unload an extension");
|
||||
}
|
||||
|
||||
void CExtensionManager::ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
||||
{
|
||||
char buffer[256];
|
||||
int numExtensions = m_Libs.size();
|
||||
edict_t *edict = player->GetEdict();
|
||||
unsigned int id = 0;
|
||||
unsigned int start = 0;
|
||||
|
||||
if (!numExtensions)
|
||||
{
|
||||
ClientConsolePrint(edict, "[SM] No extensions found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ArgC() > 2)
|
||||
{
|
||||
start = atoi(args.Arg(2));
|
||||
}
|
||||
|
||||
CExtension *ext;
|
||||
SourceHook::List<CExtension *>::iterator iter;
|
||||
|
||||
for (iter = m_Libs.begin();
|
||||
iter != m_Libs.end();
|
||||
iter++)
|
||||
{
|
||||
ext = (*iter);
|
||||
|
||||
char error[255];
|
||||
if (!ext->IsRunning(error, sizeof(error)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
id++;
|
||||
if (id < start)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id - start > 10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
IExtensionInterface *api = ext->GetAPI();
|
||||
|
||||
const char *name = api->GetExtensionName();
|
||||
const char *version = api->GetExtensionVerString();
|
||||
const char *author = api->GetExtensionAuthor();
|
||||
const char *description = api->GetExtensionDescription();
|
||||
|
||||
size_t len = UTIL_Format(buffer, sizeof(buffer), " \"%s\"", name);
|
||||
|
||||
if (version != NULL && IS_STR_FILLED(version))
|
||||
{
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", version);
|
||||
}
|
||||
|
||||
if (author != NULL && IS_STR_FILLED(author))
|
||||
{
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", author);
|
||||
}
|
||||
|
||||
if (description != NULL && IS_STR_FILLED(description))
|
||||
{
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, ": %s", description);
|
||||
}
|
||||
|
||||
|
||||
ClientConsolePrint(edict, "%s", buffer);
|
||||
}
|
||||
|
||||
while (iter != m_Libs.end())
|
||||
{
|
||||
char error[255];
|
||||
if ((*iter)->IsRunning(error, sizeof(error)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter != m_Libs.end())
|
||||
{
|
||||
ClientConsolePrint(edict, "To see more, type \"sm exts %d\"", id);
|
||||
}
|
||||
}
|
||||
|
||||
CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
|
||||
{
|
||||
if (ptr->type == g_ExtType)
|
||||
@@ -1317,7 +1432,7 @@ void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
|
||||
{
|
||||
CExtension *pExt = (CExtension *)pSource;
|
||||
pExt->AddLibrary(library);
|
||||
g_PluginSys.OnLibraryAction(library, false, false);
|
||||
g_PluginSys.OnLibraryAction(library, LibraryAction_Added);
|
||||
}
|
||||
|
||||
bool CExtensionManager::LibraryExists(const char *library)
|
||||
@@ -1369,3 +1484,33 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CLocalExtension::IsSameFile(const char *file)
|
||||
{
|
||||
/* Only care about the shortened name. */
|
||||
return strcmp(file, m_File.c_str()) == 0;
|
||||
}
|
||||
|
||||
bool CRemoteExtension::IsSameFile(const char *file)
|
||||
{
|
||||
/* :TODO: this could be better, but no one uses this API anyway. */
|
||||
return strcmp(file, m_Path.c_str()) == 0;
|
||||
}
|
||||
|
||||
@@ -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,9 @@
|
||||
#include <IPluginSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include "PluginSys.h"
|
||||
#include "NativeOwner.h"
|
||||
|
||||
class CPlayer;
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
@@ -55,15 +58,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:
|
||||
@@ -71,6 +68,7 @@ public:
|
||||
public: //IExtension
|
||||
IExtensionInterface *GetAPI();
|
||||
const char *GetFilename();
|
||||
const char *GetPath() const;
|
||||
IdentityToken_t *GetIdentity();
|
||||
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||
@@ -78,17 +76,18 @@ 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:
|
||||
virtual bool Load(char *error, size_t maxlength);
|
||||
virtual bool IsLoaded() =0;
|
||||
virtual void Unload() =0;
|
||||
virtual bool Reload(char *error, size_t maxlength) =0;
|
||||
virtual bool IsSameFile(const char* file) =0;
|
||||
protected:
|
||||
void Initialize(const char *filename, const char *path);
|
||||
bool PerformAPICheck(char *error, size_t maxlength);
|
||||
@@ -98,15 +97,12 @@ protected:
|
||||
IdentityToken_t *m_pIdentToken;
|
||||
IExtensionInterface *m_pAPI;
|
||||
String m_File;
|
||||
String m_RealFile;
|
||||
String m_Path;
|
||||
String m_Error;
|
||||
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;
|
||||
@@ -120,7 +116,9 @@ public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
void Unload();
|
||||
bool Reload(char *error, size_t maxlength);
|
||||
bool IsExternal();
|
||||
bool IsSameFile(const char *file);
|
||||
private:
|
||||
PluginId m_PlId;
|
||||
ILibrary *m_pLib;
|
||||
@@ -134,7 +132,9 @@ public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
void Unload();
|
||||
bool Reload(char *error, size_t maxlength);
|
||||
bool IsExternal();
|
||||
bool IsSameFile(const char *file);
|
||||
};
|
||||
|
||||
class CExtensionManager :
|
||||
@@ -166,28 +166,31 @@ public: //IPluginsListener
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public:
|
||||
IExtension *LoadAutoExtension(const char *path);
|
||||
IExtension *LoadAutoExtension(const char *path, bool bErrorOnMissing=true);
|
||||
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:
|
||||
void ListExtensionsToClient(CPlayer *player, const CCommand &args);
|
||||
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;
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* 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);
|
||||
}
|
||||
@@ -250,6 +255,7 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu
|
||||
}
|
||||
|
||||
CForward *pForward = g_Forwards.ForwardMake();
|
||||
pForward->m_IterGuard = NULL;
|
||||
pForward->m_curparam = 0;
|
||||
pForward->m_ExecType = et;
|
||||
snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
|
||||
@@ -283,17 +289,13 @@ 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 success=0;
|
||||
unsigned int num_params = m_curparam;
|
||||
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
FwdParamInfo *param;
|
||||
@@ -303,20 +305,29 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
memcpy(temp_info, m_params, sizeof(m_params));
|
||||
m_curparam = 0;
|
||||
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||
FuncIteratorGuard guard(&m_IterGuard, &iter);
|
||||
|
||||
while (iter != m_functions.end())
|
||||
{
|
||||
func = (*iter);
|
||||
|
||||
if (filter)
|
||||
filter->Preprocess(func, temp_info);
|
||||
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
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,39 +336,37 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the function and deal with the return value. */
|
||||
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
||||
if ((err=func->Execute(&cur_result)) == SP_ERROR_NONE)
|
||||
{
|
||||
if (filter)
|
||||
{
|
||||
filter->OnErrorReport(this, func, err);
|
||||
}
|
||||
failed++;
|
||||
} else {
|
||||
success++;
|
||||
switch (m_ExecType)
|
||||
{
|
||||
@@ -381,14 +390,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;
|
||||
}
|
||||
@@ -398,28 +405,45 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!guard.Triggered())
|
||||
iter++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -663,6 +687,7 @@ bool CForward::RemoveFunction(IPluginFunction *func)
|
||||
{
|
||||
if ((*iter) == func)
|
||||
{
|
||||
m_IterGuard->FixIteratorChain(iter);
|
||||
found = true;
|
||||
lst->erase(iter);
|
||||
break;
|
||||
@@ -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
|
||||
@@ -61,6 +61,58 @@ struct FwdParamInfo
|
||||
ParamType pushedas;
|
||||
};
|
||||
|
||||
class SourceMod::IForwardFilter
|
||||
{
|
||||
public:
|
||||
virtual void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FuncIteratorGuard
|
||||
{
|
||||
bool triggered;
|
||||
FuncIteratorGuard **pprev;
|
||||
FuncIter *iter;
|
||||
FuncIteratorGuard *next;
|
||||
public:
|
||||
FuncIteratorGuard(FuncIteratorGuard **pprev, FuncIter *iter)
|
||||
: triggered(false), pprev(pprev), iter(iter), next(*pprev)
|
||||
{
|
||||
*pprev = this;
|
||||
}
|
||||
|
||||
~FuncIteratorGuard()
|
||||
{
|
||||
*pprev = next;
|
||||
}
|
||||
|
||||
inline bool Triggered()
|
||||
{
|
||||
bool t = triggered;
|
||||
triggered = false;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should not read from |this| before the NULL check, because FwdSys
|
||||
* can call (NULL)->FixIteratorChain().
|
||||
*/
|
||||
void FixIteratorChain(FuncIter &other)
|
||||
{
|
||||
FuncIteratorGuard *guard = this;
|
||||
while (guard != NULL)
|
||||
{
|
||||
if (*guard->iter == other)
|
||||
{
|
||||
*(guard->iter) = ++(*(guard->iter));
|
||||
guard->triggered = true;
|
||||
}
|
||||
guard = guard->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CForward : public IChangeableForward
|
||||
{
|
||||
public: //ICallable
|
||||
@@ -103,6 +155,7 @@ protected:
|
||||
*/
|
||||
mutable List<IPluginFunction *> m_functions;
|
||||
mutable List<IPluginFunction *> m_paused;
|
||||
FuncIteratorGuard *m_IterGuard;
|
||||
|
||||
/* Type and name information */
|
||||
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
|
||||
+750
-18
@@ -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,12 +35,45 @@
|
||||
#include "UserMessages.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "GameConfigs.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include <compat_wrappers.h>
|
||||
#include <Logger.h>
|
||||
#include "LibrarySys.h"
|
||||
#include "logic_bridge.h"
|
||||
#include <tier0/mem.h>
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#include <cstrike15_usermessages.pb.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef ICommandLine *(*FakeGetCommandLine)();
|
||||
|
||||
#if defined _WIN32
|
||||
#define TIER0_NAME "tier0.dll"
|
||||
#define VSTDLIB_NAME "vstdlib.dll"
|
||||
#elif defined __APPLE__
|
||||
#define TIER0_NAME "libtier0.dylib"
|
||||
#define VSTDLIB_NAME "libvstdlib.dylib"
|
||||
#elif defined __linux__
|
||||
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
#define TIER0_NAME "libtier0_srv.so"
|
||||
#define VSTDLIB_NAME "libvstdlib_srv.so"
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
#define TIER0_NAME "libtier0.so"
|
||||
#define VSTDLIB_NAME "libvstdlib.so"
|
||||
#else
|
||||
#define TIER0_NAME "tier0_i486.so"
|
||||
#define VSTDLIB_NAME "vstdlib_i486.so"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
CHalfLife2 g_HL2;
|
||||
ConVar *sv_lan = NULL;
|
||||
|
||||
static void *g_EntList = NULL;
|
||||
static int entInfoOffset = -1;
|
||||
|
||||
namespace SourceHook
|
||||
{
|
||||
template<>
|
||||
@@ -88,13 +121,20 @@ CHalfLife2::~CHalfLife2()
|
||||
m_Maps.clear();
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
|
||||
#endif
|
||||
|
||||
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
|
||||
bool is_original_engine = false;
|
||||
#endif
|
||||
|
||||
void CHalfLife2::OnSourceModStartup(bool late)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
|
||||
/* The Ship currently is the only known game to use an older version of the engine */
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
|
||||
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
|
||||
#else
|
||||
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
|
||||
@@ -106,29 +146,161 @@ void CHalfLife2::OnSourceModStartup(bool late)
|
||||
{
|
||||
g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CHalfLife2::OnSourceModAllInitialized()
|
||||
{
|
||||
m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg");
|
||||
m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
|
||||
m_SayTextMsg = g_UserMsgs.GetMessageIndex("SayText");
|
||||
m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
|
||||
FindInSendTable("CTFPlayer", "m_nDisguiseClass");
|
||||
}
|
||||
|
||||
#if !defined METAMOD_PLAPI_VERSION
|
||||
void CHalfLife2::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
InitLogicalEntData();
|
||||
InitCommandLine();
|
||||
}
|
||||
|
||||
void CHalfLife2::InitLogicalEntData()
|
||||
{
|
||||
char *addr = NULL;
|
||||
|
||||
/*
|
||||
* gEntList and/or g_pEntityList
|
||||
*
|
||||
* First try to lookup pointer directly for platforms with symbols.
|
||||
* If symbols aren't present (Windows or stripped Linux/Mac),
|
||||
* attempt find via LevelShutdown + offset
|
||||
*/
|
||||
if (g_pGameConf->GetMemSig("gEntList", (void **)&addr))
|
||||
{
|
||||
#if !defined PLATFORM_WINDOWS
|
||||
if (!addr)
|
||||
{
|
||||
// Key exists so notify if lookup fails, but try other method.
|
||||
g_Logger.LogError("Failed lookup of gEntList directly - Reverting to lookup via LevelShutdown");
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
g_EntList = reinterpret_cast<void *>(addr);
|
||||
#if !defined PLATFORM_WINDOWS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (!g_EntList)
|
||||
{
|
||||
if (!g_pGameConf->GetMemSig("LevelShutdown", (void **)&addr))
|
||||
{
|
||||
g_Logger.LogError("Logical Entities not supported by this mod (LevelShutdown) - Reverting to networkable entities only");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
g_Logger.LogError("Failed lookup of LevelShutdown - Reverting to networkable entities only");
|
||||
return;
|
||||
}
|
||||
|
||||
int offset;
|
||||
if (!g_pGameConf->GetOffset("gEntList", &offset))
|
||||
{
|
||||
g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
|
||||
return;
|
||||
}
|
||||
|
||||
g_EntList = *reinterpret_cast<void **>(addr + offset);
|
||||
}
|
||||
|
||||
if (!g_EntList)
|
||||
{
|
||||
g_Logger.LogError("Failed lookup of gEntList - Reverting to networkable entities only");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_pGameConf->GetOffset("EntInfo", &entInfoOffset))
|
||||
{
|
||||
g_Logger.LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CHalfLife2::InitCommandLine()
|
||||
{
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
char error[256];
|
||||
|
||||
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "../bin/" TIER0_NAME);
|
||||
|
||||
if (!g_LibSys.IsPathFile(path))
|
||||
{
|
||||
g_Logger.LogError("Could not find path for: " TIER0_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
ILibrary *lib = g_LibSys.OpenLibrary(path, error, sizeof(error));
|
||||
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine_Tier0");
|
||||
|
||||
/* '_Tier0' dropped on Alien Swarm version */
|
||||
if (m_pGetCommandLine == NULL)
|
||||
{
|
||||
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine");
|
||||
}
|
||||
|
||||
if (m_pGetCommandLine == NULL)
|
||||
{
|
||||
/* We probably have a Ship engine. */
|
||||
lib->CloseLibrary();
|
||||
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "../bin/" VSTDLIB_NAME);
|
||||
if (!g_LibSys.IsPathFile(path))
|
||||
{
|
||||
g_Logger.LogError("Could not find path for: " VSTDLIB_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((lib = g_LibSys.OpenLibrary(path, error, sizeof(error))) == NULL)
|
||||
{
|
||||
g_Logger.LogError("Could not load %s: %s", path, error);
|
||||
return;
|
||||
}
|
||||
|
||||
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine");
|
||||
|
||||
if (m_pGetCommandLine == NULL)
|
||||
{
|
||||
g_Logger.LogError("Could not locate any command line functionality");
|
||||
}
|
||||
|
||||
lib->CloseLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
ICommandLine *CHalfLife2::GetValveCommandLine()
|
||||
{
|
||||
if (!m_pGetCommandLine)
|
||||
return NULL;
|
||||
|
||||
return ((FakeGetCommandLine)((FakeGetCommandLine *)m_pGetCommandLine))();
|
||||
}
|
||||
|
||||
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
|
||||
bool CHalfLife2::IsOriginalEngine()
|
||||
{
|
||||
return is_original_engine;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
|
||||
{
|
||||
return engine->GetChangeAccessor( (const edict_t *)this );
|
||||
}
|
||||
#endif
|
||||
|
||||
bool UTIL_FindInSendTable(SendTable *pTable,
|
||||
const char *name,
|
||||
@@ -165,8 +337,13 @@ bool UTIL_FindInSendTable(SendTable *pTable,
|
||||
return false;
|
||||
}
|
||||
|
||||
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
|
||||
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name, bool *isNested)
|
||||
{
|
||||
if (isNested)
|
||||
{
|
||||
*isNested = false;
|
||||
}
|
||||
|
||||
while (pMap)
|
||||
{
|
||||
for (int i=0; i<pMap->dataNumFields; i++)
|
||||
@@ -181,10 +358,21 @@ typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
|
||||
}
|
||||
if (pMap->dataDesc[i].td)
|
||||
{
|
||||
typedescription_t *_td;
|
||||
if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
|
||||
if (isNested)
|
||||
{
|
||||
return _td;
|
||||
*isNested = (UTIL_FindInDataMap(pMap->dataDesc[i].td, name, NULL) != NULL);
|
||||
if (*isNested)
|
||||
{
|
||||
return NULL;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else { // Use the old behaviour, we dont want to spring this on extensions - even if they're doing bad things.
|
||||
typedescription_t *_td;
|
||||
if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name, NULL)) != NULL)
|
||||
{
|
||||
return _td;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,6 +465,11 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
|
||||
}
|
||||
|
||||
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
|
||||
{
|
||||
return this->FindInDataMap(pMap, offset, NULL);
|
||||
}
|
||||
|
||||
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset, bool *isNested)
|
||||
{
|
||||
typedescription_t *td = NULL;
|
||||
DataMapTrie &val = m_Maps[pMap];
|
||||
@@ -287,7 +480,7 @@ typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset
|
||||
}
|
||||
if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
|
||||
{
|
||||
if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
|
||||
if ((td = UTIL_FindInDataMap(pMap, offset, isNested)) != NULL)
|
||||
{
|
||||
sm_trie_insert(val.trie, offset, td);
|
||||
}
|
||||
@@ -298,6 +491,7 @@ typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset
|
||||
|
||||
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
if (g_pSharedChangeInfo != NULL)
|
||||
{
|
||||
if (offset)
|
||||
@@ -310,6 +504,7 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pEdict->m_fStateFlags |= FL_EDICT_CHANGED;
|
||||
}
|
||||
@@ -317,16 +512,72 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||
|
||||
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
bf_write *pBitBuf = NULL;
|
||||
#endif
|
||||
cell_t players[] = {client};
|
||||
|
||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
if (dest == HUD_PRINTTALK)
|
||||
{
|
||||
const char *chat_saytext = g_pGameConf->GetKeyValue("ChatSayText");
|
||||
|
||||
/* Use SayText user message instead */
|
||||
if (chat_saytext != NULL && strcmp(chat_saytext, "yes") == 0)
|
||||
{
|
||||
char buffer[192];
|
||||
UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg);
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
CCSUsrMsg_SayText *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pMsg->set_ent_idx(0);
|
||||
pMsg->set_text(buffer);
|
||||
pMsg->set_chat(false);
|
||||
#else
|
||||
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pBitBuf->WriteByte(0);
|
||||
pBitBuf->WriteString(buffer);
|
||||
pBitBuf->WriteByte(1);
|
||||
#endif
|
||||
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
CCSUsrMsg_TextMsg *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Client tries to read all 5 'params' and will crash if less
|
||||
pMsg->set_msg_dst(dest);
|
||||
pMsg->add_params(msg);
|
||||
pMsg->add_params("");
|
||||
pMsg->add_params("");
|
||||
pMsg->add_params("");
|
||||
pMsg->add_params("");
|
||||
#else
|
||||
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pBitBuf->WriteByte(dest);
|
||||
pBitBuf->WriteString(msg);
|
||||
#endif
|
||||
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
return true;
|
||||
@@ -334,10 +585,20 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
||||
|
||||
bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
{
|
||||
bf_write *pBitBuf = NULL;
|
||||
cell_t players[] = {client};
|
||||
|
||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
CCSUsrMsg_HintText *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pMsg->set_text(msg);
|
||||
#else
|
||||
bf_write *pBitBuf = NULL;
|
||||
|
||||
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -348,6 +609,38 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
pBitBuf->WriteByte(1);
|
||||
}
|
||||
pBitBuf->WriteString(msg);
|
||||
#endif
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
CCSUsrMsg_HintText *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pMsg->set_text(msg);
|
||||
#else
|
||||
bf_write *pBitBuf = NULL;
|
||||
|
||||
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte");
|
||||
if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0)
|
||||
{
|
||||
pBitBuf->WriteByte(1);
|
||||
}
|
||||
pBitBuf->WriteString(msg);
|
||||
#endif
|
||||
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
return true;
|
||||
@@ -355,15 +648,23 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
|
||||
bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
|
||||
{
|
||||
bf_write *pBitBuf = NULL;
|
||||
KeyValues *SubKey = NULL;
|
||||
int count = 0;
|
||||
cell_t players[] = {client};
|
||||
|
||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
CCSUsrMsg_VGUIMenu *pMsg;
|
||||
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bf_write *pBitBuf = NULL;
|
||||
if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data)
|
||||
{
|
||||
@@ -376,6 +677,18 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
||||
SubKey = data->GetFirstSubKey();
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
pMsg->set_name(name);
|
||||
pMsg->set_show(show);
|
||||
|
||||
while (SubKey)
|
||||
{
|
||||
CCSUsrMsg_VGUIMenu_Subkey *key = pMsg->add_subkeys();
|
||||
key->set_name(SubKey->GetName());
|
||||
key->set_str(SubKey->GetString());
|
||||
SubKey = SubKey->GetNextKey();
|
||||
}
|
||||
#else
|
||||
pBitBuf->WriteString(name);
|
||||
pBitBuf->WriteByte((show) ? 1 : 0);
|
||||
pBitBuf->WriteByte(count);
|
||||
@@ -385,6 +698,8 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
||||
pBitBuf->WriteString(SubKey->GetString());
|
||||
SubKey = SubKey->GetNextKey();
|
||||
}
|
||||
#endif
|
||||
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
return true;
|
||||
@@ -437,12 +752,53 @@ 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 || PLAPI_VERSION >= 11
|
||||
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;
|
||||
|
||||
info.args = cmd;
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
strncopy(info.cmd, cmd->Arg(0), sizeof(info.cmd));
|
||||
#endif
|
||||
|
||||
@@ -466,9 +822,385 @@ void CHalfLife2::PopCommandStack()
|
||||
|
||||
const char *CHalfLife2::CurrentCommandName()
|
||||
{
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
return m_CommandStack.front().args->Arg(0);
|
||||
#else
|
||||
return m_CommandStack.front().cmd;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
|
||||
{
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
if (!pPlayer || !pPlayer->IsConnected() || pPlayer->IsInKickQueue())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->MarkAsBeingKicked();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
edict_t *CHalfLife2::EdictOfIndex(int index)
|
||||
{
|
||||
return ::PEntityOfEntIndex(index);
|
||||
}
|
||||
|
||||
int CHalfLife2::IndexOfEdict(edict_t *pEnt)
|
||||
{
|
||||
return ::IndexOfEdict(pEnt);
|
||||
}
|
||||
|
||||
edict_t *CHalfLife2::GetHandleEntity(CBaseHandle &hndl)
|
||||
{
|
||||
if (!hndl.IsValid())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int index = hndl.GetEntryIndex();
|
||||
|
||||
edict_t *pStoredEdict;
|
||||
CBaseEntity *pStoredEntity;
|
||||
|
||||
if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pStoredEdict == NULL || pStoredEntity == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IServerEntity *pSE = pStoredEdict->GetIServerEntity();
|
||||
|
||||
if (pSE == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pSE->GetRefEHandle() != hndl)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pStoredEdict;
|
||||
}
|
||||
|
||||
void CHalfLife2::SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt)
|
||||
{
|
||||
IServerEntity *pEntOther = pEnt->GetIServerEntity();
|
||||
|
||||
if (pEntOther == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hndl.Set(pEntOther);
|
||||
}
|
||||
|
||||
const char *CHalfLife2::GetCurrentMap()
|
||||
{
|
||||
return STRING(gpGlobals->mapname);
|
||||
}
|
||||
|
||||
void CHalfLife2::ServerCommand(const char *buffer)
|
||||
{
|
||||
engine->ServerCommand(buffer);
|
||||
}
|
||||
|
||||
cell_t CHalfLife2::EntityToReference(CBaseEntity *pEntity)
|
||||
{
|
||||
IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
|
||||
CBaseHandle hndl = pUnknown->GetRefEHandle();
|
||||
return (hndl.ToInt() | (1<<31));
|
||||
}
|
||||
|
||||
CBaseEntity *CHalfLife2::ReferenceToEntity(cell_t entRef)
|
||||
{
|
||||
if ((unsigned)entRef == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CEntInfo *pInfo = NULL;
|
||||
|
||||
if (entRef & (1<<31))
|
||||
{
|
||||
/* Proper ent reference */
|
||||
int hndlValue = entRef & ~(1<<31);
|
||||
CBaseHandle hndl(hndlValue);
|
||||
|
||||
pInfo = LookupEntity(hndl.GetEntryIndex());
|
||||
if (!pInfo || pInfo->m_SerialNumber != hndl.GetSerialNumber())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Old style index only */
|
||||
pInfo = LookupEntity(entRef);
|
||||
}
|
||||
|
||||
if (!pInfo)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IServerUnknown *pUnk = static_cast<IServerUnknown *>(pInfo->m_pEntity);
|
||||
if (pUnk)
|
||||
{
|
||||
return pUnk->GetBaseEntity();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CEntInfo pointer from g_EntList for a given entity index
|
||||
*/
|
||||
CEntInfo *CHalfLife2::LookupEntity(int entIndex)
|
||||
{
|
||||
// Make sure that our index is within the bounds of the global ent array
|
||||
if (entIndex < 0 || entIndex >= NUM_ENT_ENTRIES)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!g_EntList || entInfoOffset == -1)
|
||||
{
|
||||
/* Attempt to use engine interface instead */
|
||||
static CEntInfo tempInfo;
|
||||
tempInfo.m_pNext = NULL;
|
||||
tempInfo.m_pPrev = NULL;
|
||||
|
||||
edict_t *pEdict = PEntityOfEntIndex(entIndex);
|
||||
|
||||
if (!pEdict)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IServerUnknown *pUnk = pEdict->GetUnknown();
|
||||
|
||||
if (!pUnk)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tempInfo.m_pEntity = pUnk;
|
||||
tempInfo.m_SerialNumber = pUnk->GetRefEHandle().GetSerialNumber();
|
||||
|
||||
return &tempInfo;
|
||||
}
|
||||
|
||||
CEntInfo *pArray = (CEntInfo *)(((unsigned char *)g_EntList) + entInfoOffset);
|
||||
return &pArray[entIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
SERIAL_MASK = 0x7fff (15 bits)
|
||||
|
||||
#define MAX_EDICT_BITS 11
|
||||
#define NUM_ENT_ENTRY_BITS (MAX_EDICT_BITS + 1)
|
||||
m_Index = iEntry | (iSerialNumber << NUM_ENT_ENTRY_BITS);
|
||||
|
||||
Top 5 bits of a handle are unused.
|
||||
Bit 31 - Our 'reference' flag indicator
|
||||
*/
|
||||
|
||||
cell_t CHalfLife2::IndexToReference(int entIndex)
|
||||
{
|
||||
CBaseEntity *pEnt = ReferenceToEntity(entIndex);
|
||||
if (!pEnt)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
return EntityToReference(pEnt);
|
||||
}
|
||||
|
||||
int CHalfLife2::ReferenceToIndex(cell_t entRef)
|
||||
{
|
||||
if ((unsigned)entRef == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
if (entRef & (1<<31))
|
||||
{
|
||||
/* Proper ent reference */
|
||||
int hndlValue = entRef & ~(1<<31);
|
||||
CBaseHandle hndl(hndlValue);
|
||||
|
||||
CEntInfo *pInfo = LookupEntity(hndl.GetEntryIndex());
|
||||
|
||||
if (pInfo->m_SerialNumber != hndl.GetSerialNumber())
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
return hndl.GetEntryIndex();
|
||||
}
|
||||
|
||||
return entRef;
|
||||
}
|
||||
|
||||
cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
|
||||
{
|
||||
if (pEntity == NULL)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
|
||||
CBaseHandle hndl = pUnknown->GetRefEHandle();
|
||||
|
||||
if (hndl == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
if (hndl.GetEntryIndex() >= MAX_EDICTS)
|
||||
{
|
||||
return (hndl.ToInt() | (1<<31));
|
||||
}
|
||||
else
|
||||
{
|
||||
return hndl.GetEntryIndex();
|
||||
}
|
||||
}
|
||||
|
||||
cell_t CHalfLife2::ReferenceToBCompatRef(cell_t entRef)
|
||||
{
|
||||
if ((unsigned)entRef == INVALID_EHANDLE_INDEX)
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
int hndlValue = entRef & ~(1<<31);
|
||||
CBaseHandle hndl(hndlValue);
|
||||
|
||||
if (hndl.GetEntryIndex() < MAX_EDICTS)
|
||||
{
|
||||
return hndl.GetEntryIndex();
|
||||
}
|
||||
|
||||
return entRef;
|
||||
}
|
||||
|
||||
void *CHalfLife2::GetGlobalEntityList()
|
||||
{
|
||||
return g_EntList;
|
||||
}
|
||||
|
||||
int CHalfLife2::GetSendPropOffset(SendProp *prop)
|
||||
{
|
||||
return prop->GetOffset();
|
||||
}
|
||||
|
||||
const char *CHalfLife2::GetEntityClassname(edict_t * pEdict)
|
||||
{
|
||||
if (pEdict == NULL || pEdict->IsFree())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IServerUnknown *pUnk = pEdict->GetUnknown();
|
||||
if (pUnk == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CBaseEntity * pEntity = pUnk->GetBaseEntity();
|
||||
|
||||
if (pEntity == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return GetEntityClassname(pEntity);
|
||||
}
|
||||
|
||||
const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity)
|
||||
{
|
||||
static int offset = -1;
|
||||
if (offset == -1)
|
||||
{
|
||||
datamap_t *pMap = GetDataMap(pEntity);
|
||||
typedescription_t *pDesc = FindInDataMap(pMap, "m_iClassname");
|
||||
offset = GetTypeDescOffs(pDesc);
|
||||
}
|
||||
|
||||
return *(const char **)(((unsigned char *)pEntity) + offset);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
static bool ResolveFuzzyMapName(const char *fuzzyName, char *outFullname, int size)
|
||||
{
|
||||
static ConCommand *pHelperCmd = g_pCVar->FindCommand("changelevel");
|
||||
if (!pHelperCmd || !pHelperCmd->CanAutoComplete())
|
||||
return false;
|
||||
|
||||
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
||||
|
||||
CUtlVector<CUtlString> results;
|
||||
pHelperCmd->AutoCompleteSuggest(fuzzyName, results);
|
||||
if (results.Count() == 0)
|
||||
return false;
|
||||
|
||||
// Results come back as you'd see in autocomplete. (ie. "changelevel fullmapnamehere"),
|
||||
// so skip ahead to start of map path/name
|
||||
|
||||
// Like the engine, we're only going to deal with the first match.
|
||||
|
||||
strncopy(outFullname, &results[0][helperCmdLen + 1], size);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CHalfLife2::IsMapValid(const char *map)
|
||||
{
|
||||
if (!map || !map[0])
|
||||
return false;
|
||||
|
||||
bool ret = engine->IsMapValid(map);
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
if (!ret)
|
||||
{
|
||||
static char szFuzzyName[PLATFORM_MAX_PATH];
|
||||
if (ResolveFuzzyMapName(map, szFuzzyName, sizeof(szFuzzyName)))
|
||||
{
|
||||
ret = engine->IsMapValid(szFuzzyName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
+64
-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
|
||||
@@ -41,6 +41,13 @@
|
||||
#include "sm_queue.h"
|
||||
#include <IGameHelpers.h>
|
||||
#include <KeyValues.h>
|
||||
#include <server_class.h>
|
||||
#include <datamap.h>
|
||||
#include <ihandleentity.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
#include <string_t.h>
|
||||
#endif
|
||||
|
||||
class CCommand;
|
||||
|
||||
@@ -72,11 +79,32 @@ struct DelayedFakeCliCmd
|
||||
struct CachedCommandInfo
|
||||
{
|
||||
const CCommand *args;
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
||||
char cmd[300];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct DelayedKickInfo
|
||||
{
|
||||
int userid;
|
||||
int client;
|
||||
char buffer[384];
|
||||
};
|
||||
|
||||
// copy from game/shared/entitylist_base.h
|
||||
class CEntInfo
|
||||
{
|
||||
public:
|
||||
IHandleEntity *m_pEntity;
|
||||
int m_SerialNumber;
|
||||
CEntInfo *m_pPrev;
|
||||
CEntInfo *m_pNext;
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
string_t m_iName;
|
||||
string_t m_iClassName;
|
||||
#endif
|
||||
};
|
||||
|
||||
class CHalfLife2 :
|
||||
public SMGlobalClass,
|
||||
public IGameHelpers
|
||||
@@ -87,6 +115,7 @@ public:
|
||||
public:
|
||||
void OnSourceModStartup(bool late);
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModAllInitialized_Post();
|
||||
/*void OnSourceModAllShutdown();*/
|
||||
public: //IGameHelpers
|
||||
SendProp *FindInSendTable(const char *classname, const char *offset);
|
||||
@@ -94,11 +123,33 @@ public: //IGameHelpers
|
||||
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
||||
ServerClass *FindServerClass(const char *classname);
|
||||
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
|
||||
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset, bool *isNested);
|
||||
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
|
||||
bool TextMsg(int client, int dest, const char *msg);
|
||||
bool HintTextMsg(int client, const char *msg);
|
||||
bool HintTextMsg(cell_t *players, int count, const char *msg);
|
||||
bool ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show);
|
||||
bool IsLANServer();
|
||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
||||
edict_t *EdictOfIndex(int index);
|
||||
int IndexOfEdict(edict_t *pEnt);
|
||||
edict_t *GetHandleEntity(CBaseHandle &hndl);
|
||||
void SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt);
|
||||
const char *GetCurrentMap();
|
||||
void ServerCommand(const char *buffer);
|
||||
CBaseEntity *ReferenceToEntity(cell_t entRef);
|
||||
cell_t EntityToReference(CBaseEntity *pEntity);
|
||||
cell_t IndexToReference(int entIndex);
|
||||
int ReferenceToIndex(cell_t entRef);
|
||||
cell_t ReferenceToBCompatRef(cell_t entRef);
|
||||
CEntInfo *LookupEntity(int entIndex);
|
||||
cell_t EntityToBCompatRef(CBaseEntity *pEntity);
|
||||
void *GetGlobalEntityList();
|
||||
int GetSendPropOffset(SendProp *prop);
|
||||
ICommandLine *GetValveCommandLine();
|
||||
const char *GetEntityClassname(edict_t *pEdict);
|
||||
const char *GetEntityClassname(CBaseEntity *pEntity);
|
||||
bool IsMapValid(const char *map);
|
||||
public:
|
||||
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
||||
void ProcessFakeCliCmdQueue();
|
||||
@@ -107,23 +158,33 @@ public:
|
||||
void PopCommandStack();
|
||||
const CCommand *PeekCommandStack();
|
||||
const char *CurrentCommandName();
|
||||
#if !defined METAMOD_PLAPI_VERSION
|
||||
void AddDelayedKick(int client, int userid, const char *msg);
|
||||
void ProcessDelayedKicks();
|
||||
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
|
||||
bool IsOriginalEngine();
|
||||
#endif
|
||||
private:
|
||||
DataTableInfo *_FindServerClass(const char *classname);
|
||||
private:
|
||||
void InitLogicalEntData();
|
||||
void InitCommandLine();
|
||||
private:
|
||||
Trie *m_pClasses;
|
||||
List<DataTableInfo *> m_Tables;
|
||||
THash<datamap_t *, DataMapTrie> m_Maps;
|
||||
int m_MsgTextMsg;
|
||||
int m_HinTextMsg;
|
||||
int m_SayTextMsg;
|
||||
int m_VGUIMenu;
|
||||
Queue<DelayedFakeCliCmd *> m_CmdQueue;
|
||||
CStack<DelayedFakeCliCmd *> m_FreeCmds;
|
||||
CStack<CachedCommandInfo> m_CommandStack;
|
||||
Queue<DelayedKickInfo> m_DelayedKicks;
|
||||
void *m_pGetCommandLine;
|
||||
};
|
||||
|
||||
extern CHalfLife2 g_HL2;
|
||||
|
||||
bool IndexToAThings(cell_t, CBaseEntity **pEntData, edict_t **pEdictData);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -579,6 +579,7 @@ HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Hand
|
||||
}
|
||||
|
||||
pNewHandle->clone = index;
|
||||
pNewHandle->object = NULL;
|
||||
pHandle->refcount++;
|
||||
|
||||
*newhandle = new_handle;
|
||||
@@ -620,8 +621,53 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, Iden
|
||||
return CloneHandle(pHandle, index, newhandle, newOwner);
|
||||
}
|
||||
|
||||
Handle_t HandleSystem::FastCloneHandle(QHandle *pHandle, unsigned int index)
|
||||
{
|
||||
if (pHandle->clone)
|
||||
return FastCloneHandle(&m_Handles[pHandle->clone], pHandle->clone);
|
||||
|
||||
Handle_t hndl;
|
||||
if (CloneHandle(pHandle, index, &hndl, g_pCoreIdent) != HandleError_None)
|
||||
return BAD_HANDLE;
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
|
||||
{
|
||||
QHandle *pHandle;
|
||||
unsigned int index;
|
||||
|
||||
GetHandleUnchecked(hndl, pHandle, index);
|
||||
|
||||
return FastCloneHandle(pHandle, index);
|
||||
}
|
||||
|
||||
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
unsigned int serial = (hndl >> 16);
|
||||
#endif
|
||||
index = (hndl & HANDLESYS_HANDLE_MASK);
|
||||
|
||||
assert(index != 0 && index <= m_HandleTail && index < HANDLESYS_MAX_HANDLES);
|
||||
|
||||
pHandle = &m_Handles[index];
|
||||
|
||||
assert(pHandle->set && pHandle->set != HandleSet_Freed);
|
||||
assert(pHandle->serial == serial);
|
||||
}
|
||||
|
||||
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
{
|
||||
if (pHandle->is_destroying)
|
||||
{
|
||||
/* Someone tried to free this recursively.
|
||||
* We'll just ignore this safely.
|
||||
*/
|
||||
return HandleError_None;
|
||||
}
|
||||
|
||||
QHandleType *pType = &m_Types[pHandle->type];
|
||||
|
||||
if (pHandle->clone)
|
||||
@@ -636,6 +682,7 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
pMaster = &m_Handles[master];
|
||||
|
||||
/* Release the clone now */
|
||||
pHandle->is_destroying = true;
|
||||
ReleasePrimHandle(index);
|
||||
|
||||
/* Decrement the master's reference count */
|
||||
@@ -644,20 +691,27 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
||||
/* Type should be the same but do this anyway... */
|
||||
pType = &m_Types[pMaster->type];
|
||||
pMaster->is_destroying = true;
|
||||
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
|
||||
if (pMaster->object)
|
||||
{
|
||||
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
|
||||
}
|
||||
ReleasePrimHandle(master);
|
||||
}
|
||||
} else if (pHandle->set == HandleSet_Identity) {
|
||||
/* If we're an identity, skip all this stuff!
|
||||
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
|
||||
*/
|
||||
pHandle->is_destroying = true;
|
||||
ReleasePrimHandle(index);
|
||||
} else {
|
||||
/* Decrement, free if necessary */
|
||||
if (--pHandle->refcount == 0)
|
||||
{
|
||||
pHandle->is_destroying = true;
|
||||
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
||||
if (pHandle->object)
|
||||
{
|
||||
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
||||
}
|
||||
ReleasePrimHandle(index);
|
||||
} else {
|
||||
/* We must be cloned, so mark ourselves as freed */
|
||||
@@ -690,14 +744,6 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec
|
||||
return HandleError_Access;
|
||||
}
|
||||
|
||||
if (pHandle->is_destroying)
|
||||
{
|
||||
/* Someone tried to free this recursively.
|
||||
* We'll just ignore this safely.
|
||||
*/
|
||||
return HandleError_None;
|
||||
}
|
||||
|
||||
return FreeHandle(pHandle, index);
|
||||
}
|
||||
|
||||
@@ -756,6 +802,9 @@ void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
|
||||
assert(pHandle->owner == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pHandle->owner = NULL;
|
||||
|
||||
/* Note that since 0 is an invalid handle, if any of these links are 0,
|
||||
* the data can still be set.
|
||||
*/
|
||||
@@ -880,29 +929,9 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pHandle->clone)
|
||||
{
|
||||
/* Get parent */
|
||||
QHandle *pOther = &m_Handles[pHandle->clone];
|
||||
if (--pOther->refcount == 0)
|
||||
{
|
||||
/* Free! */
|
||||
dispatch->OnHandleDestroy(type, pOther->object);
|
||||
ReleasePrimHandle(pHandle->clone);
|
||||
}
|
||||
/* Unlink ourselves since we don't have a reference count */
|
||||
ReleasePrimHandle(i);
|
||||
} else {
|
||||
/* If it's not a clone, we still have to check the reference count.
|
||||
* Either way, we'll be destroyed eventually because the handle types do not change.
|
||||
*/
|
||||
if (--pHandle->refcount == 0)
|
||||
{
|
||||
/* Free! */
|
||||
dispatch->OnHandleDestroy(type, pHandle->object);
|
||||
ReleasePrimHandle(i);
|
||||
}
|
||||
}
|
||||
|
||||
FreeHandle(pHandle, i);
|
||||
|
||||
if (pType->opened == 0)
|
||||
{
|
||||
break;
|
||||
@@ -910,6 +939,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;
|
||||
}
|
||||
|
||||
@@ -941,14 +979,17 @@ bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHa
|
||||
return true;
|
||||
}
|
||||
|
||||
#define HANDLE_LOG_VERY_BAD(message, ...) \
|
||||
g_Logger.LogFatal(message, ##__VA_ARGS__); \
|
||||
g_Logger.LogError(message, ##__VA_ARGS__);
|
||||
|
||||
bool HandleSystem::TryAndFreeSomeHandles()
|
||||
{
|
||||
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
|
||||
IPlugin *highest_owner = NULL;
|
||||
unsigned int highest_handle_count = 0;
|
||||
|
||||
/* Search all plugins */
|
||||
while (pl_iter->MorePlugins())
|
||||
for (IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator(); pl_iter->MorePlugins(); pl_iter->NextPlugin())
|
||||
{
|
||||
IPlugin *plugin = pl_iter->GetPlugin();
|
||||
IdentityToken_t *identity = plugin->GetIdentity();
|
||||
@@ -977,8 +1018,6 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
highest_owner = plugin;
|
||||
highest_handle_count = handle_count;
|
||||
}
|
||||
|
||||
pl_iter->NextPlugin();
|
||||
}
|
||||
|
||||
if (highest_owner == NULL || highest_handle_count == 0)
|
||||
@@ -986,11 +1025,11 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
|
||||
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);
|
||||
HANDLE_LOG_VERY_BAD("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
|
||||
HANDLE_LOG_VERY_BAD("[SM] Unloading plugin to free %d handles.", highest_handle_count);
|
||||
HANDLE_LOG_VERY_BAD("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
|
||||
|
||||
highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS;
|
||||
highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
|
||||
|
||||
return g_PluginSys.UnloadPlugin(highest_owner);
|
||||
}
|
||||
@@ -1045,12 +1084,32 @@ void HandleSystem::Dump(HANDLE_REPORTER rep)
|
||||
const char *type = "ANON";
|
||||
QHandleType *pType = &m_Types[m_Handles[i].type];
|
||||
unsigned int size = 0;
|
||||
unsigned int parentIdx;
|
||||
bool bresult;
|
||||
if (pType->nameIdx != -1)
|
||||
{
|
||||
type = m_strtab->GetString(pType->nameIdx);
|
||||
}
|
||||
|
||||
if ((parentIdx = m_Handles[i].clone) != 0)
|
||||
{
|
||||
if (m_Handles[parentIdx].refcount > 0)
|
||||
{
|
||||
size = 0;
|
||||
bresult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[parentIdx].type, m_Handles[parentIdx].object, &size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
|
||||
}
|
||||
|
||||
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|
||||
|| !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
|
||||
|| !bresult)
|
||||
{
|
||||
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-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
|
||||
@@ -160,6 +160,9 @@ public: //IHandleSystem
|
||||
HandleError *err);
|
||||
|
||||
void Dump(HANDLE_REPORTER rep);
|
||||
|
||||
/* Bypasses security checks. */
|
||||
Handle_t FastCloneHandle(Handle_t hndl);
|
||||
protected:
|
||||
/**
|
||||
* Decodes a handle with sanity and security checking.
|
||||
@@ -170,6 +173,9 @@ protected:
|
||||
unsigned int *index,
|
||||
bool ignoreFree=false);
|
||||
|
||||
Handle_t FastCloneHandle(QHandle *pHandle, unsigned int index);
|
||||
void GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index);
|
||||
|
||||
/**
|
||||
* Creates a basic handle and sets its reference count to 1.
|
||||
* Does not do any type or security checking.
|
||||
@@ -222,4 +228,27 @@ private:
|
||||
|
||||
extern HandleSystem g_HandleSys;
|
||||
|
||||
struct AutoHandleRooter
|
||||
{
|
||||
public:
|
||||
AutoHandleRooter(Handle_t hndl)
|
||||
{
|
||||
if (hndl != BAD_HANDLE)
|
||||
this->hndl = g_HandleSys.FastCloneHandle(hndl);
|
||||
else
|
||||
this->hndl = BAD_HANDLE;
|
||||
}
|
||||
|
||||
~AutoHandleRooter()
|
||||
{
|
||||
if (hndl != BAD_HANDLE)
|
||||
{
|
||||
HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
|
||||
g_HandleSys.FreeHandle(hndl, &sec);
|
||||
}
|
||||
}
|
||||
private:
|
||||
Handle_t hndl;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
@@ -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)
|
||||
@@ -241,7 +241,7 @@ bool LibrarySystem::IsPathDirectory(const char *path)
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
|
||||
if (stat(path, &s) != 0)
|
||||
@@ -272,25 +272,53 @@ 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,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)error,
|
||||
maxlength,
|
||||
NULL);
|
||||
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
(DWORD)code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)error,
|
||||
maxlength,
|
||||
NULL) == 0)
|
||||
{
|
||||
UTIL_Format(error, maxlength, "error code %08x", code);
|
||||
}
|
||||
#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 +329,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 +368,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];
|
||||
}
|
||||
@@ -381,7 +410,7 @@ size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char
|
||||
size_t length = strlen(path);
|
||||
|
||||
for (size_t i = length - 1;
|
||||
i >= 0 && i <= length - 1;
|
||||
i <= length - 1;
|
||||
i--)
|
||||
{
|
||||
if (path[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;
|
||||
+54
-10
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -34,9 +34,9 @@
|
||||
#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"
|
||||
#include <sourcemod_version.h>
|
||||
|
||||
Logger g_Logger;
|
||||
|
||||
@@ -149,7 +149,7 @@ void Logger::_NewMapFile()
|
||||
} else {
|
||||
char date[32];
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SVN_FULL_VERSION);
|
||||
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SM_VERSION_STRING);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -252,6 +265,32 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
||||
return;
|
||||
}
|
||||
|
||||
static ConVar *sv_logecho = icvar->FindVar("sv_logecho");
|
||||
|
||||
char buffer[3072];
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
char date[32];
|
||||
time_t t;
|
||||
GetAdjustedTime(&t);
|
||||
tm *curtime = localtime(&t);
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
|
||||
if (!sv_logecho || sv_logecho->GetBool())
|
||||
{
|
||||
g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[3072];
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||
|
||||
@@ -262,7 +301,7 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
|
||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||
g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void Logger::LogMessage(const char *vafmt, ...)
|
||||
@@ -323,7 +362,7 @@ void Logger::LogMessage(const char *vafmt, ...)
|
||||
char date[32];
|
||||
m_DailyPrintHdr = false;
|
||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SVN_FULL_VERSION);
|
||||
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SM_VERSION_STRING);
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
@@ -345,6 +384,14 @@ print_error:
|
||||
}
|
||||
|
||||
void Logger::LogError(const char *vafmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
LogErrorEx(vafmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::LogErrorEx(const char *vafmt, va_list ap)
|
||||
{
|
||||
if (!m_Active)
|
||||
{
|
||||
@@ -375,10 +422,7 @@ void Logger::LogError(const char *vafmt, ...)
|
||||
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||
m_ErrMapStart = true;
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, vafmt);
|
||||
LogToOpenFileEx(fp, vafmt, ap);
|
||||
va_end(ap);
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
|
||||
+5
-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
|
||||
@@ -75,9 +75,13 @@ public:
|
||||
void DisableLogging();
|
||||
void LogMessage(const char *msg, ...);
|
||||
void LogError(const char *msg, ...);
|
||||
void LogErrorEx(const char *msg, va_list ap);
|
||||
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;
|
||||
|
||||
+171
-88
@@ -1,133 +1,216 @@
|
||||
#(C)2004-2008 Metamod:Source Development Team
|
||||
# (C)2004-2008 SourceMod Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
#Local paths
|
||||
SMSDK = ..
|
||||
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
|
||||
HL2SDK_CSS = ../../hl2sdk-css
|
||||
HL2SDK_OB_VALVE = ../../hl2sdk-ob-valve
|
||||
HL2SDK_L4D = ../../hl2sdk-l4d
|
||||
HL2SDK_L4D2 = ../../hl2sdk-l4d2
|
||||
HL2SDK_CSGO = ../../hl2sdk-csgo
|
||||
MMSOURCE = ../../mmsource-central
|
||||
|
||||
#####################################
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
#####################################
|
||||
|
||||
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
|
||||
Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \
|
||||
MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \
|
||||
sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
|
||||
Database.cpp DebugReporter.cpp EventManager.cpp HalfLife2.cpp Logger.cpp \
|
||||
PlayerManager.cpp TimerSys.cpp UserMessages.cpp \
|
||||
sm_autonatives.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
|
||||
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
|
||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
|
||||
frame_hooks.cpp concmd_cleaner.cpp Profiler.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
|
||||
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
|
||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp \
|
||||
frame_hooks.cpp concmd_cleaner.cpp NextMap.cpp \
|
||||
NativeOwner.cpp logic_bridge.cpp ConsoleDetours.cpp
|
||||
OBJECTS += smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||
smn_database.cpp smn_entities.cpp smn_events.cpp \
|
||||
smn_fakenatives.cpp smn_filesystem.cpp smn_halflife.cpp \
|
||||
smn_keyvalues.cpp smn_player.cpp \
|
||||
smn_usermsgs.cpp smn_menus.cpp smn_vector.cpp \
|
||||
smn_hudtext.cpp smn_nextmap.cpp
|
||||
OBJECTS += ExtensionSys.cpp \
|
||||
ForwardSys.cpp \
|
||||
HandleSys.cpp \
|
||||
LibrarySys.cpp \
|
||||
PluginInfoDatabase.cpp \
|
||||
PluginSys.cpp \
|
||||
ShareSys.cpp \
|
||||
NativeInvoker.cpp
|
||||
|
||||
##############################################
|
||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||
##############################################
|
||||
|
||||
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
|
||||
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
|
||||
C_GCC4_FLAGS = -fvisibility=hidden
|
||||
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
|
||||
CPP = gcc
|
||||
|
||||
override ENGSET = false
|
||||
|
||||
ifneq (,$(filter original orangebox css orangeboxvalve left4dead left4dead2 csgo,$(ENGINE)))
|
||||
override ENGSET = true
|
||||
endif
|
||||
|
||||
ifeq "$(ENGINE)" "original"
|
||||
HL2SDK = $(HL2SDK_ORIG)
|
||||
HL2PUB = $(HL2SDK_ORIG)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
METAMOD = $(SOURCEMM14)
|
||||
INCLUDE += -I$(HL2PUB)/dlls
|
||||
SRCDS = $(SRCDS_BASE)
|
||||
CFLAGS += -DSOURCE_ENGINE=1
|
||||
METAMOD = $(MMSOURCE)/core-legacy
|
||||
INCLUDE += -I$(HL2SDK)/public/dlls
|
||||
BINARY = sourcemod.1.ep1.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangebox"
|
||||
HL2SDK = $(HL2SDK_OB)
|
||||
HL2PUB = $(HL2SDK_OB)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
CFLAGS += -DORANGEBOX_BUILD
|
||||
METAMOD = $(SOURCEMM16)
|
||||
INCLUDE += -I$(HL2PUB)/game/server
|
||||
SRCDS = $(SRCDS_BASE)/orangebox
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=3
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.ep2.so
|
||||
endif
|
||||
ifeq "$(BINARY)" ""
|
||||
echo "You must supply ENGINE=orangebox or ENGINE=original"
|
||||
false
|
||||
ifeq "$(ENGINE)" "css"
|
||||
HL2SDK = $(HL2SDK_CSS)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=6
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.css.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "orangeboxvalve"
|
||||
HL2SDK = $(HL2SDK_OB_VALVE)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=7
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.ep2v.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "left4dead"
|
||||
HL2SDK = $(HL2SDK_L4D)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=8
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.l4d.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "left4dead2"
|
||||
HL2SDK = $(HL2SDK_L4D2)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=9
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.l4d2.so
|
||||
endif
|
||||
ifeq "$(ENGINE)" "csgo"
|
||||
HL2SDK = $(HL2SDK_CSGO)
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
CFLAGS += -DSOURCE_ENGINE=12
|
||||
METAMOD = $(MMSOURCE)/core
|
||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||
BINARY = sourcemod.2.csgo.so
|
||||
endif
|
||||
|
||||
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
|
||||
tier0_i486.so -lpthread -static-libgcc
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
|
||||
INCLUDE_SMSDK = -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions
|
||||
OS := $(shell uname -s)
|
||||
|
||||
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)
|
||||
ifeq "$(OS)" "Darwin"
|
||||
LIB_EXT = dylib
|
||||
HL2LIB = $(HL2SDK)/lib/mac
|
||||
else
|
||||
LIB_EXT = so
|
||||
ifeq "$(ENGINE)" "original"
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
else
|
||||
HL2LIB = $(HL2SDK)/lib/linux
|
||||
endif
|
||||
endif
|
||||
|
||||
SM16_INCLUDE = -I. -I.. -I$(SOURCEMM16)/sourcehook $(INCLUDE_SMSDK)
|
||||
ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
|
||||
LIB_SUFFIX = _i486.$(LIB_EXT)
|
||||
else
|
||||
LIB_PREFIX = lib
|
||||
ifneq (,$(filter orangeboxvalve css,$(ENGINE)))
|
||||
ifneq "$(OS)" "Darwin"
|
||||
LIB_SUFFIX = _srv.$(LIB_EXT)
|
||||
else
|
||||
LIB_SUFFIX = .$(LIB_EXT)
|
||||
endif
|
||||
else
|
||||
LIB_SUFFIX = .$(LIB_EXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_BLOODYGOODTIME=4 -DSE_EYE=5 \
|
||||
-DSE_CSS=6 -DSE_ORANGEBOXVALVE=7 -DSE_LEFT4DEAD=8 -DSE_LEFT4DEAD2=9 -DSE_ALIENSWARM=10 \
|
||||
-DSE_PORTAL2=11 -DSE_CSGO=12
|
||||
|
||||
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a $(LIB_PREFIX)vstdlib$(LIB_SUFFIX) \
|
||||
$(LIB_PREFIX)tier0$(LIB_SUFFIX) -static-libgcc
|
||||
|
||||
ifeq "$(ENGINE)" "csgo"
|
||||
LINK += $(HL2LIB)/interfaces_i486.a
|
||||
endif
|
||||
|
||||
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/mathlib -I$(HL2PUB)/vstdlib \
|
||||
-I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook \
|
||||
-I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
||||
|
||||
CFLAGS += -D_LINUX -DPOSIX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||
-Wno-uninitialized -Wno-unused -Wno-switch -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H \
|
||||
-DSM_DEFAULT_THREADER -m32 -DCOMPILER_GCC
|
||||
CPPFLAGS += -Wno-non-virtual-dtor -Wno-overloaded-virtual -fno-threadsafe-statics -fno-exceptions -fno-rtti
|
||||
|
||||
################################################
|
||||
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||
################################################
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug.$(ENGINE)
|
||||
CFLAGS += $(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:
|
||||
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
|
||||
all: check
|
||||
mkdir -p $(BIN_DIR)
|
||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX)
|
||||
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX)
|
||||
$(MAKE) -f Makefile sourcemod
|
||||
|
||||
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 one of the following values for ENGINE:"; \
|
||||
echo "csgo, left4dead2, left4dead, orangeboxvalve, css, orangebox, or original"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
sourcemod: check $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) -f Makefile all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
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)/$(BINARY)
|
||||
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "MemoryUtils.h"
|
||||
#include "ShareSys.h"
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
#endif
|
||||
|
||||
MemoryUtils g_MemUtils;
|
||||
|
||||
#if 0
|
||||
MemoryUtils::MemoryUtils()
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
|
||||
m_PageSize = info.dwPageSize;
|
||||
|
||||
#elif defined PLATFORM_POSIX
|
||||
|
||||
m_PageSize = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryUtils::OnSourceModAllInitialized()
|
||||
{
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||
{
|
||||
DynLibInfo lib;
|
||||
bool found;
|
||||
char *ptr, *end;
|
||||
|
||||
memset(&lib, 0, sizeof(DynLibInfo));
|
||||
|
||||
if (!GetLibraryInfo(libPtr, lib))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
||||
end = ptr + lib.memorySize;
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
found = true;
|
||||
for (register size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
|
||||
{
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return ptr;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
{
|
||||
unsigned long baseAddr;
|
||||
|
||||
if (libPtr == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
IMAGE_DOS_HEADER *dos;
|
||||
IMAGE_NT_HEADERS *pe;
|
||||
IMAGE_FILE_HEADER *file;
|
||||
IMAGE_OPTIONAL_HEADER *opt;
|
||||
|
||||
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
|
||||
|
||||
/* All this is for our insane sanity checks :o */
|
||||
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
|
||||
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
|
||||
file = &pe->FileHeader;
|
||||
opt = &pe->OptionalHeader;
|
||||
|
||||
/* Check PE magic and signature */
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check architecture, which is 32-bit/x86 right now
|
||||
* Should change this for 64-bit if Valve gets their act together
|
||||
*/
|
||||
if (file->Machine != IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library */
|
||||
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Finally, we can do this */
|
||||
lib.memorySize = opt->SizeOfImage;
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
|
||||
Dl_info info;
|
||||
Elf32_Ehdr *file;
|
||||
Elf32_Phdr *phdr;
|
||||
uint16_t phdrCount;
|
||||
|
||||
if (!dladdr(libPtr, &info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This is for our insane sanity checks :o */
|
||||
baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
|
||||
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
|
||||
|
||||
/* Check ELF magic */
|
||||
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ELF version */
|
||||
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ELF architecture, which is 32-bit/x86 right now
|
||||
* Should change this for 64-bit if Valve gets their act together
|
||||
*/
|
||||
if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library/shared object */
|
||||
if (file->e_type != ET_DYN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
phdrCount = file->e_phnum;
|
||||
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
|
||||
|
||||
/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
|
||||
for (uint16_t i = 0; i < phdrCount; i++)
|
||||
{
|
||||
Elf32_Phdr &hdr = phdr[i];
|
||||
|
||||
if (hdr.p_type == PT_LOAD)
|
||||
{
|
||||
lib.memorySize += hdr.p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
+54
-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 "logic_bridge.h"
|
||||
|
||||
MenuManager g_Menus;
|
||||
VoteMenuHandler s_VoteHandler;
|
||||
@@ -230,6 +231,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
unsigned int pgn = menu->GetPagination();
|
||||
unsigned int maxItems = style->GetMaxPageItems();
|
||||
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
|
||||
bool novoteButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_NOVOTE) == MENUFLAG_BUTTON_NOVOTE;
|
||||
|
||||
if (pgn != MENU_NO_PAGINATION)
|
||||
{
|
||||
@@ -240,6 +242,11 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
||||
maxItems--;
|
||||
}
|
||||
|
||||
if (novoteButton)
|
||||
{
|
||||
maxItems--;
|
||||
}
|
||||
|
||||
/* This is very not allowed! */
|
||||
if (maxItems < 2)
|
||||
{
|
||||
@@ -435,6 +442,20 @@ skip_search:
|
||||
/* Draw the item according to the order */
|
||||
menu_slots_t *slots = md.slots;
|
||||
unsigned int position = 0; /* Keep track of the last position */
|
||||
|
||||
if (novoteButton)
|
||||
{
|
||||
char text[50];
|
||||
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
|
||||
{
|
||||
UTIL_Format(text, sizeof(text), "No Vote");
|
||||
}
|
||||
ItemDrawInfo dr(text, 0);
|
||||
position = panel->DrawItem(dr);
|
||||
slots[position].type = ItemSel_Exit;
|
||||
position++;
|
||||
}
|
||||
|
||||
if (order == ItemOrder_Ascending)
|
||||
{
|
||||
md.item_on_page = drawItems[0].position;
|
||||
@@ -585,14 +606,20 @@ skip_search:
|
||||
{
|
||||
if (exitBackButton)
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Back", NULL);
|
||||
if (!logicore.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 (!logicore.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 +637,10 @@ skip_search:
|
||||
/* NEXT */
|
||||
if (displayNext || canDrawDisabled)
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Next", NULL);
|
||||
if (!logicore.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 +668,10 @@ skip_search:
|
||||
/* EXIT */
|
||||
if (exitButton)
|
||||
{
|
||||
CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL);
|
||||
if (!logicore.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 +810,19 @@ unsigned int MenuManager::GetRemainingVoteDelay()
|
||||
{
|
||||
return s_VoteHandler.GetRemainingVoteDelay();
|
||||
}
|
||||
|
||||
bool MenuManager::IsClientInVotePool(int client)
|
||||
{
|
||||
return s_VoteHandler.IsClientInVotePool(client);
|
||||
}
|
||||
|
||||
bool MenuManager::RedrawClientVoteMenu(int client)
|
||||
{
|
||||
return RedrawClientVoteMenu2(client, true);
|
||||
}
|
||||
|
||||
bool MenuManager::RedrawClientVoteMenu2(int client, bool revote)
|
||||
{
|
||||
return s_VoteHandler.RedrawToClient(client, revote);
|
||||
}
|
||||
|
||||
|
||||
+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
|
||||
@@ -89,6 +89,9 @@ public:
|
||||
bool IsVoteInProgress();
|
||||
void CancelVoting();
|
||||
unsigned int GetRemainingVoteDelay();
|
||||
bool IsClientInVotePool(int client);
|
||||
bool RedrawClientVoteMenu(int client);
|
||||
bool RedrawClientVoteMenu2(int client, bool revote);
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
||||
|
||||
+15
-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
|
||||
@@ -314,7 +314,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
|
||||
if (sound != NULL)
|
||||
{
|
||||
edict_t *pEdict = engine->PEntityOfEntIndex(client);
|
||||
edict_t *pEdict = PEntityOfEntIndex(client);
|
||||
if (pEdict)
|
||||
{
|
||||
ICollideable *pCollideable = pEdict->GetCollideable();
|
||||
@@ -322,15 +322,24 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
if (pCollideable)
|
||||
{
|
||||
const Vector & pos = pCollideable->GetCollisionOrigin();
|
||||
|
||||
enginesound->EmitSound(filter,
|
||||
client,
|
||||
CHAN_AUTO,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
sound,
|
||||
-1,
|
||||
#endif
|
||||
sound,
|
||||
VOL_NORM,
|
||||
ATTN_NORM,
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
0,
|
||||
#endif
|
||||
0,
|
||||
PITCH_NORM,
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
|
||||
0,
|
||||
#endif
|
||||
&pos);
|
||||
}
|
||||
}
|
||||
@@ -377,6 +386,9 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||
RemoveClientFromWatch(client);
|
||||
}
|
||||
|
||||
Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
|
||||
AutoHandleRooter ahr(hndl);
|
||||
|
||||
if (cancel)
|
||||
{
|
||||
mh->OnMenuCancel(menu, client, reason);
|
||||
|
||||
@@ -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
|
||||
@@ -32,11 +32,20 @@
|
||||
#include "MenuStyle_Radio.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "UserMessages.h"
|
||||
#include "GameConfigs.h"
|
||||
#include <IGameConfigs.h>
|
||||
#include "PlayerManager.h"
|
||||
#if defined MENU_DEBUG
|
||||
#include "Logger.h"
|
||||
#endif
|
||||
#include "logic_bridge.h"
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
|
||||
#endif
|
||||
|
||||
extern const char *g_RadioNumTable[];
|
||||
CRadioStyle g_RadioMenuStyle;
|
||||
@@ -44,6 +53,14 @@ int g_ShowMenuId = -1;
|
||||
bool g_bRadioInit = false;
|
||||
unsigned int g_RadioMenuTimeout = 0;
|
||||
|
||||
// back, next, exit
|
||||
#define MAX_PAGINATION_OPTIONS 3
|
||||
|
||||
#define MAX_MENUSLOT_KEYS 10
|
||||
|
||||
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
||||
|
||||
|
||||
CRadioStyle::CRadioStyle()
|
||||
{
|
||||
m_players = new CRadioMenuPlayer[256+1];
|
||||
@@ -89,6 +106,18 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
||||
g_RadioMenuTimeout = 0;
|
||||
}
|
||||
|
||||
const char *items = g_pGameConf->GetKeyValue("RadioMenuMaxPageItems");
|
||||
if (items != NULL)
|
||||
{
|
||||
int value = atoi(items);
|
||||
|
||||
// Only override the mostly-safe default if it's a sane value
|
||||
if (value > MAX_PAGINATION_OPTIONS && value <= MAX_MENUSLOT_KEYS)
|
||||
{
|
||||
s_RadioMaxPageItems = value;
|
||||
}
|
||||
}
|
||||
|
||||
g_Menus.AddStyle(this);
|
||||
g_Menus.SetDefaultStyle(this);
|
||||
|
||||
@@ -134,13 +163,22 @@ static unsigned int g_last_holdtime = 0;
|
||||
static unsigned int g_last_client_count = 0;
|
||||
static int g_last_clients[256];
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter)
|
||||
#else
|
||||
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
||||
#endif
|
||||
{
|
||||
int count = pFilter->GetRecipientCount();
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||
#else
|
||||
bf_read br(bf->GetBasePointer(), 3);
|
||||
|
||||
br.ReadWord();
|
||||
int c = br.ReadChar();
|
||||
#endif
|
||||
|
||||
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
|
||||
|
||||
@@ -188,7 +226,7 @@ IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwn
|
||||
|
||||
unsigned int CRadioStyle::GetMaxPageItems()
|
||||
{
|
||||
return 10;
|
||||
return s_RadioMaxPageItems;
|
||||
}
|
||||
|
||||
const char *CRadioStyle::GetStyleName()
|
||||
@@ -306,7 +344,7 @@ unsigned int CRadioDisplay::GetCurrentKey()
|
||||
|
||||
bool CRadioDisplay::SetCurrentKey(unsigned int key)
|
||||
{
|
||||
if (key < m_NextPos || m_NextPos > 10)
|
||||
if (key < m_NextPos || m_NextPos > s_RadioMaxPageItems)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -342,7 +380,7 @@ void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
|
||||
|
||||
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
|
||||
{
|
||||
if (m_NextPos > 10 || !CanDrawItem(item.style))
|
||||
if (m_NextPos > s_RadioMaxPageItems || !CanDrawItem(item.style))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -451,6 +489,15 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||
}
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
// If or when we need to support multiple games per engine with this, we can switch to reflection
|
||||
// TODO: find what happens past 240 on CS:GO
|
||||
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
msg->set_bits_valid_slots(display_keys);
|
||||
msg->set_display_time(time);
|
||||
msg->set_menu_string(ptr);
|
||||
g_UserMsgs.EndMessage();
|
||||
#else
|
||||
while (true)
|
||||
{
|
||||
if (len > 240)
|
||||
@@ -458,7 +505,8 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
save = ptr[240];
|
||||
ptr[240] = '\0';
|
||||
}
|
||||
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
|
||||
bf_write *buffer = g_UserMsgs.StartBitBufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
buffer->WriteWord(display_keys);
|
||||
buffer->WriteChar(time ? time : -1);
|
||||
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
||||
@@ -475,6 +523,7 @@ void CRadioMenuPlayer::Radio_Refresh()
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
display_last_refresh = gpGlobals->curtime;
|
||||
}
|
||||
@@ -510,6 +559,7 @@ unsigned int CRadioDisplay::GetApproxMemUsage()
|
||||
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
|
||||
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
|
||||
{
|
||||
m_Pagination = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
|
||||
}
|
||||
|
||||
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
||||
@@ -550,6 +600,17 @@ bool CRadioMenu::DisplayAtItem(int client,
|
||||
time);
|
||||
}
|
||||
|
||||
bool CRadioMenu::SetPagination(unsigned int itemsPerPage)
|
||||
{
|
||||
const unsigned int maxPerPage = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
|
||||
if (itemsPerPage > maxPerPage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CBaseMenu::SetPagination(itemsPerPage);
|
||||
}
|
||||
|
||||
void CRadioMenu::Cancel_Finally()
|
||||
{
|
||||
g_RadioMenuStyle.CancelMenu(this);
|
||||
|
||||
+12
-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
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "MenuStyle_Base.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <IUserMessages.h>
|
||||
#include "UserMessages.h"
|
||||
#include "sm_fastlink.h"
|
||||
#include <sh_stack.h>
|
||||
#include <compat_wrappers.h>
|
||||
@@ -65,7 +65,11 @@ private:
|
||||
class CRadioStyle :
|
||||
public BaseMenuStyle,
|
||||
public SMGlobalClass,
|
||||
public IUserMessageListener
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
public IProtobufUserMessageListener
|
||||
#else
|
||||
public IBitBufUserMessageListener
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
CRadioStyle();
|
||||
@@ -84,7 +88,11 @@ public: //IMenuStyle
|
||||
unsigned int GetMaxPageItems();
|
||||
unsigned int GetApproxMemUsage();
|
||||
public: //IUserMessageListener
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
void OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter);
|
||||
#else
|
||||
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
|
||||
#endif
|
||||
void OnUserMessageSent(int msg_id);
|
||||
public:
|
||||
bool IsSupported();
|
||||
@@ -142,6 +150,7 @@ public:
|
||||
unsigned int time,
|
||||
unsigned int start_item,
|
||||
IMenuHandler *alt_handler/* =NULL */);
|
||||
bool SetPagination(unsigned int itemsPerPage);
|
||||
void Cancel_Finally();
|
||||
unsigned int GetApproxMemUsage();
|
||||
};
|
||||
|
||||
@@ -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,7 +32,6 @@
|
||||
#include "sm_stringutil.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include "Translator.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "ConCmdManager.h"
|
||||
|
||||
@@ -88,7 +87,7 @@ void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
|
||||
return;
|
||||
}
|
||||
|
||||
int client = engine->IndexOfEdict(pEdict);
|
||||
int client = IndexOfEdict(pEdict);
|
||||
if (client < 1 || client > 256)
|
||||
{
|
||||
return;
|
||||
@@ -325,7 +324,7 @@ void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int ti
|
||||
m_pKv->SetInt("time", time ? time : 200);
|
||||
|
||||
SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)(
|
||||
engine->PEntityOfEntIndex(client),
|
||||
PEntityOfEntIndex(client),
|
||||
DIALOG_MENU,
|
||||
m_pKv,
|
||||
vsp_interface);
|
||||
|
||||
@@ -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
|
||||
|
||||
+305
-17
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -34,10 +34,57 @@
|
||||
#include "MenuVoting.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <sourcemod.h>
|
||||
#include <Logger.h>
|
||||
#include <HalfLife2.h>
|
||||
#include <mathlib.h>
|
||||
#include <const.h>
|
||||
#include <ITranslator.h>
|
||||
#include "logic_bridge.h"
|
||||
|
||||
float g_next_vote = 0.0f;
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#define VOTE_NOT_VOTING -2
|
||||
#define VOTE_PENDING -1
|
||||
|
||||
ConVar sm_vote_hintbox("sm_vote_progress_hintbox",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress in a hint box",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
ConVar sm_vote_chat("sm_vote_progress_chat",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress as chat messages",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
ConVar sm_vote_console("sm_vote_progress_console",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress as console messages",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
ConVar sm_vote_client_console("sm_vote_progress_client_console",
|
||||
"0",
|
||||
0,
|
||||
"Show current vote progress as console messages to clients",
|
||||
true,
|
||||
0.0,
|
||||
true,
|
||||
1.0);
|
||||
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
|
||||
#else
|
||||
void OnVoteDelayChange(ConVar *cvar, const char *value);
|
||||
@@ -52,7 +99,7 @@ ConVar sm_vote_delay("sm_vote_delay",
|
||||
0.0,
|
||||
OnVoteDelayChange);
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue)
|
||||
#else
|
||||
void OnVoteDelayChange(ConVar *cvar, const char *value)
|
||||
@@ -113,14 +160,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]) >= VOTE_PENDING)
|
||||
{
|
||||
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] = VOTE_NOT_VOTING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,18 +181,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 +210,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 +227,72 @@ 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] > VOTE_NOT_VOTING);
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
|
||||
{
|
||||
if (!IsClientInVotePool(client)
|
||||
|| m_ClientVotes[client] == VOTE_PENDING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*pItem = m_ClientVotes[client];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::RedrawToClient(int client, bool revotes)
|
||||
{
|
||||
unsigned int time_limit;
|
||||
|
||||
if (!IsClientInVotePool(client))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_ClientVotes[client] >= 0)
|
||||
{
|
||||
if ((m_VoteFlags & VOTEFLAG_NO_REVOTES) == VOTEFLAG_NO_REVOTES || !revotes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
assert((unsigned)m_ClientVotes[client] < m_Items);
|
||||
assert(m_Votes[m_ClientVotes[client]] > 0);
|
||||
m_Votes[m_ClientVotes[client]]--;
|
||||
m_ClientVotes[client] = VOTE_PENDING;
|
||||
m_Revoting[client] = true;
|
||||
m_NumVotes--;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -173,7 +308,8 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
|
||||
/* Mark all clients as not voting */
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
m_ClientVotes[i] = -2;
|
||||
m_ClientVotes[i] = VOTE_NOT_VOTING;
|
||||
m_Revoting[i] = false;
|
||||
}
|
||||
|
||||
m_Items = menu->GetItemCount();
|
||||
@@ -187,7 +323,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;
|
||||
@@ -215,6 +353,8 @@ void VoteMenuHandler::StartVoting()
|
||||
|
||||
m_pHandler->OnMenuVoteStart(m_pCurMenu);
|
||||
|
||||
m_displayTimer = g_Timers.CreateTimer(this, 1.0, NULL, TIMER_FLAG_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
|
||||
|
||||
/* By now we know how many clients were set.
|
||||
* If there are none, we should end IMMEDIATELY.
|
||||
*/
|
||||
@@ -222,6 +362,8 @@ void VoteMenuHandler::StartVoting()
|
||||
{
|
||||
EndVoting();
|
||||
}
|
||||
|
||||
m_TotalClients = m_Clients;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::DecrementPlayerCount()
|
||||
@@ -252,10 +394,17 @@ void VoteMenuHandler::EndVoting()
|
||||
if (fVoteDelay < 1.0)
|
||||
{
|
||||
g_next_vote = 0.0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
g_next_vote = gpGlobals->curtime + fVoteDelay;
|
||||
}
|
||||
|
||||
if (m_displayTimer)
|
||||
{
|
||||
g_Timers.KillTimer(m_displayTimer);
|
||||
}
|
||||
|
||||
if (m_bCancelled)
|
||||
{
|
||||
/* If we were cancelled, don't bother tabulating anything.
|
||||
@@ -302,7 +451,7 @@ void VoteMenuHandler::EndVoting()
|
||||
/* Build the client list */
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
if (m_ClientVotes[i] >= -1)
|
||||
if (m_ClientVotes[i] >= VOTE_PENDING)
|
||||
{
|
||||
client_vote[vote.num_clients].client = i;
|
||||
client_vote[vote.num_clients].item = m_ClientVotes[i];
|
||||
@@ -346,7 +495,7 @@ void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason
|
||||
|
||||
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
|
||||
{
|
||||
m_ClientVotes[client] = -1;
|
||||
m_ClientVotes[client] = VOTE_PENDING;
|
||||
m_pHandler->OnMenuDisplay(menu, client, display);
|
||||
}
|
||||
|
||||
@@ -368,6 +517,58 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
|
||||
m_ClientVotes[client] = item;
|
||||
m_Votes[item]++;
|
||||
m_NumVotes++;
|
||||
|
||||
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
|
||||
{
|
||||
static char buffer[1024];
|
||||
ItemDrawInfo dr;
|
||||
menu->GetItemInfo(item, &dr);
|
||||
|
||||
if (sm_vote_console.GetBool())
|
||||
{
|
||||
int target = SOURCEMOD_SERVER_LANGUAGE;
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
|
||||
&target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
|
||||
Engine_LogPrintWrapper(buffer);
|
||||
}
|
||||
|
||||
if (sm_vote_chat.GetBool() || sm_vote_client_console.GetBool())
|
||||
{
|
||||
int maxclients = g_Players.GetMaxClients();
|
||||
for (int i=1; i<=maxclients; i++)
|
||||
{
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
|
||||
assert(pPlayer);
|
||||
|
||||
if (pPlayer->IsInGame() && !pPlayer->IsFakeClient())
|
||||
{
|
||||
if (m_Revoting[client])
|
||||
{
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote",
|
||||
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
|
||||
}
|
||||
else
|
||||
{
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
|
||||
&i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
|
||||
}
|
||||
|
||||
if (sm_vote_chat.GetBool())
|
||||
{
|
||||
g_HL2.TextMsg(i, HUD_PRINTTALK, buffer);
|
||||
}
|
||||
|
||||
if (sm_vote_client_console.GetBool())
|
||||
{
|
||||
ClientConsolePrint(pPlayer->GetEdict(), buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuildVoteLeaders();
|
||||
DrawHintProgress();
|
||||
}
|
||||
|
||||
m_pHandler->OnMenuSelect(menu, client, item);
|
||||
@@ -390,6 +591,9 @@ void VoteMenuHandler::InternalReset()
|
||||
m_NumVotes = 0;
|
||||
m_bCancelled = false;
|
||||
m_pHandler = NULL;
|
||||
m_leaderList[0] = '\0';
|
||||
m_displayTimer = NULL;
|
||||
m_TotalClients = 0;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::CancelVoting()
|
||||
@@ -411,3 +615,87 @@ bool VoteMenuHandler::IsCancelling()
|
||||
{
|
||||
return m_bCancelled;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::DrawHintProgress()
|
||||
{
|
||||
if (!sm_vote_hintbox.GetBool())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static char buffer[1024];
|
||||
|
||||
float timeRemaining = (m_fStartTime + m_nMenuTime) - gpGlobals->curtime;
|
||||
if (timeRemaining < 0)
|
||||
{
|
||||
timeRemaining = 0.0;
|
||||
}
|
||||
|
||||
int iTimeRemaining = RoundFloatToInt(timeRemaining);
|
||||
|
||||
int maxclients = g_Players.GetMaxClients();
|
||||
for (int i=1; i<=maxclients; i++)
|
||||
{
|
||||
if (g_Players.GetPlayerByIndex(i)->IsInGame())
|
||||
{
|
||||
logicore.CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count",
|
||||
&i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList);
|
||||
g_HL2.HintTextMsg(i, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoteMenuHandler::BuildVoteLeaders()
|
||||
{
|
||||
if (m_NumVotes == 0 || !sm_vote_hintbox.GetBool())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
menu_vote_result_t vote;
|
||||
menu_vote_result_t::menu_item_vote_t item_vote[256];
|
||||
|
||||
memset(&vote, 0, sizeof(vote));
|
||||
|
||||
/* Build the item list */
|
||||
for (unsigned int i=0; i<m_Items; i++)
|
||||
{
|
||||
if (m_Votes[i] > 0)
|
||||
{
|
||||
item_vote[vote.num_items].count = m_Votes[i];
|
||||
item_vote[vote.num_items].item = i;
|
||||
vote.num_votes += m_Votes[i];
|
||||
vote.num_items++;
|
||||
}
|
||||
}
|
||||
vote.item_list = item_vote;
|
||||
assert(vote.num_votes);
|
||||
|
||||
/* Sort the item list descending */
|
||||
qsort(item_vote,
|
||||
vote.num_items,
|
||||
sizeof(menu_vote_result_t::menu_item_vote_t),
|
||||
SortVoteItems);
|
||||
|
||||
/* Take the top 3 (if applicable) and draw them */
|
||||
int len = 0;
|
||||
for (unsigned int i=0; i<vote.num_items && i<3; i++)
|
||||
{
|
||||
int curItem = vote.item_list[i].item;
|
||||
ItemDrawInfo dr;
|
||||
m_pCurMenu->GetItemInfo(curItem, &dr);
|
||||
len += g_SourceMod.Format(m_leaderList + len, sizeof(m_leaderList) - len, "\n%i. %s: (%i)", i+1, dr.display, vote.item_list[i].count);
|
||||
}
|
||||
}
|
||||
|
||||
SourceMod::ResultType VoteMenuHandler::OnTimer(ITimer *pTimer, void *pData)
|
||||
{
|
||||
DrawHintProgress();
|
||||
|
||||
return Pl_Continue;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnTimerEnd(ITimer *pTimer, void *pData)
|
||||
{
|
||||
m_displayTimer = NULL;
|
||||
}
|
||||
|
||||
+19
-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
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <sh_vector.h>
|
||||
#include "sm_globals.h"
|
||||
#include <TimerSys.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
@@ -43,7 +44,8 @@ using namespace SourceMod;
|
||||
class VoteMenuHandler :
|
||||
public IMenuHandler,
|
||||
public SMGlobalClass,
|
||||
public IClientListener
|
||||
public IClientListener,
|
||||
public ITimedEvent
|
||||
{
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
@@ -61,6 +63,9 @@ public: //IMenuHandler
|
||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||
public: //ITimedEvent
|
||||
ResultType OnTimer(ITimer *pTimer, void *pData);
|
||||
void OnTimerEnd(ITimer *pTimer, void *pData);
|
||||
public:
|
||||
bool StartVote(IBaseMenu *menu,
|
||||
unsigned int num_clients,
|
||||
@@ -72,6 +77,9 @@ public:
|
||||
IBaseMenu *GetCurrentMenu();
|
||||
bool IsCancelling();
|
||||
unsigned int GetRemainingVoteDelay();
|
||||
bool IsClientInVotePool(int client);
|
||||
bool GetClientVoteChoice(int client, unsigned int *pItem);
|
||||
bool RedrawToClient(int client, bool revote);
|
||||
private:
|
||||
void Reset(IMenuHandler *mh);
|
||||
void DecrementPlayerCount();
|
||||
@@ -82,9 +90,12 @@ private:
|
||||
unsigned int time,
|
||||
unsigned int flags);
|
||||
void StartVoting();
|
||||
void DrawHintProgress();
|
||||
void BuildVoteLeaders();
|
||||
private:
|
||||
IMenuHandler *m_pHandler;
|
||||
unsigned int m_Clients;
|
||||
unsigned int m_TotalClients;
|
||||
unsigned int m_Items;
|
||||
CVector<unsigned int> m_Votes;
|
||||
IBaseMenu *m_pCurMenu;
|
||||
@@ -93,7 +104,13 @@ 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];
|
||||
bool m_Revoting[256+1];
|
||||
char m_leaderList[1024];
|
||||
ITimer *m_displayTimer;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "NativeInvoker.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
NativeInterface g_NInvoke;
|
||||
|
||||
NativeInvoker::NativeInvoker()
|
||||
{
|
||||
}
|
||||
|
||||
NativeInvoker::~NativeInvoker()
|
||||
{
|
||||
}
|
||||
|
||||
const char *NativeInterface::GetInterfaceName()
|
||||
{
|
||||
return SMINTERFACE_NINVOKE_NAME;
|
||||
}
|
||||
|
||||
unsigned int NativeInterface::GetInterfaceVersion()
|
||||
{
|
||||
return SMINTERFACE_NINVOKE_VERSION;
|
||||
}
|
||||
|
||||
void NativeInterface::OnSourceModAllInitialized()
|
||||
{
|
||||
g_ShareSys.AddInterface(NULL, &g_NInvoke);
|
||||
}
|
||||
|
||||
IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
|
||||
{
|
||||
return g_pSourcePawn2->CreateEmptyRuntime(name, bytes);
|
||||
}
|
||||
|
||||
INativeInvoker *NativeInterface::CreateInvoker()
|
||||
{
|
||||
return new NativeInvoker();
|
||||
}
|
||||
|
||||
bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
|
||||
{
|
||||
NativeEntry *entry;
|
||||
|
||||
entry = g_ShareSys.FindNative(name);
|
||||
if (entry == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
native = NULL;
|
||||
if (entry->replacement.owner != NULL)
|
||||
{
|
||||
native = entry->replacement.func;
|
||||
}
|
||||
else if (entry->owner != NULL)
|
||||
{
|
||||
native = entry->func;
|
||||
}
|
||||
|
||||
if (native == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->pContext = pContext;
|
||||
|
||||
m_curparam = 0;
|
||||
m_errorstate = SP_ERROR_NONE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cell_t NativeInvoker::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
m_info[m_curparam].marked = false;
|
||||
m_params[m_curparam] = cell;
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int NativeInvoker::PushCellByRef(cell_t *cell, int flags)
|
||||
{
|
||||
return PushArray(cell, 1, flags);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushFloat(float number)
|
||||
{
|
||||
cell_t val = *(cell_t *)&number;
|
||||
|
||||
return PushCell(val);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushFloatByRef(float *number, int flags)
|
||||
{
|
||||
return PushCellByRef((cell_t *)number, flags);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
|
||||
info->flags = inarray ? copyback : 0;
|
||||
info->marked = true;
|
||||
info->size = cells;
|
||||
info->str.is_sz = false;
|
||||
info->orig_addr = inarray;
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int NativeInvoker::PushString(const char *string)
|
||||
{
|
||||
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
|
||||
}
|
||||
|
||||
int NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||
{
|
||||
return _PushString(buffer, sz_flags, cp_flags, length);
|
||||
}
|
||||
|
||||
int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
|
||||
info->marked = true;
|
||||
info->orig_addr = (cell_t *)string;
|
||||
info->flags = cp_flags;
|
||||
info->size = len;
|
||||
info->str.sz_flags = sz_flags;
|
||||
info->str.is_sz = true;
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void NativeInvoker::Cancel()
|
||||
{
|
||||
if (pContext == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_errorstate = SP_ERROR_NONE;
|
||||
m_curparam = 0;
|
||||
pContext = NULL;
|
||||
native = NULL;
|
||||
}
|
||||
|
||||
int NativeInvoker::SetError(int err)
|
||||
{
|
||||
m_errorstate = err;
|
||||
return err;
|
||||
}
|
||||
|
||||
int NativeInvoker::Invoke(cell_t *result)
|
||||
{
|
||||
int err = SP_ERROR_NONE;
|
||||
|
||||
if (pContext == NULL)
|
||||
{
|
||||
return SP_ERROR_INVALID_NATIVE;
|
||||
}
|
||||
|
||||
if (m_errorstate != SP_ERROR_NONE)
|
||||
{
|
||||
err = m_errorstate;
|
||||
Cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
cell_t tresult;
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
result = &tresult;
|
||||
}
|
||||
|
||||
//This is for re-entrancy!
|
||||
IPluginContext *ctx = pContext;
|
||||
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
|
||||
cell_t *temp_params = &_temp_params[1];
|
||||
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int numparams = m_curparam;
|
||||
unsigned int i;
|
||||
bool docopies = true;
|
||||
|
||||
if (numparams)
|
||||
{
|
||||
//Save the info locally, then reset it for re-entrant calls.
|
||||
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
||||
}
|
||||
m_curparam = 0;
|
||||
pContext = NULL;
|
||||
|
||||
/* Initialize 0th parameter */
|
||||
_temp_params[0] = numparams;
|
||||
|
||||
/* Browse the parameters and build arrays */
|
||||
for (i = 0; i < numparams; i++)
|
||||
{
|
||||
/* Is this marked as an array? */
|
||||
if (temp_info[i].marked)
|
||||
{
|
||||
if (!temp_info[i].str.is_sz)
|
||||
{
|
||||
/* Allocate a normal/generic array */
|
||||
if ((err = ctx->HeapAlloc(temp_info[i].size,
|
||||
&temp_info[i].local_addr,
|
||||
&temp_info[i].phys_addr))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (temp_info[i].orig_addr)
|
||||
{
|
||||
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate cells required for the string */
|
||||
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
|
||||
|
||||
/* Allocate the buffer */
|
||||
if ((err = ctx->HeapAlloc(cells,
|
||||
&temp_info[i].local_addr,
|
||||
&temp_info[i].phys_addr))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* Copy original string if necessary */
|
||||
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
|
||||
{
|
||||
/* Cut off UTF-8 properly */
|
||||
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
|
||||
{
|
||||
if ((err = ctx->StringToLocalUTF8(temp_info[i].local_addr,
|
||||
temp_info[i].size,
|
||||
(const char *)temp_info[i].orig_addr,
|
||||
NULL))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Copy a binary blob */
|
||||
else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
|
||||
{
|
||||
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
|
||||
}
|
||||
/* Copy ASCII characters */
|
||||
else
|
||||
{
|
||||
if ((err = ctx->StringToLocal(temp_info[i].local_addr,
|
||||
temp_info[i].size,
|
||||
(const char *)temp_info[i].orig_addr))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* End array/string calculation */
|
||||
/* Update the pushed parameter with the byref local address */
|
||||
temp_params[i] = temp_info[i].local_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just copy the value normally */
|
||||
temp_params[i] = m_params[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the call if we can */
|
||||
if (err == SP_ERROR_NONE)
|
||||
{
|
||||
*result = native(ctx, _temp_params);
|
||||
if (ctx->GetLastNativeError() != SP_ERROR_NONE)
|
||||
{
|
||||
docopies = false;
|
||||
ctx->ClearLastNativeError();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
docopies = false;
|
||||
}
|
||||
|
||||
/* i should be equal to the last valid parameter + 1 */
|
||||
while (i--)
|
||||
{
|
||||
if (!temp_info[i].marked)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
|
||||
{
|
||||
if (temp_info[i].orig_addr)
|
||||
{
|
||||
if (temp_info[i].str.is_sz)
|
||||
{
|
||||
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (temp_info[i].size == 1)
|
||||
{
|
||||
*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(temp_info[i].orig_addr,
|
||||
temp_info[i].phys_addr,
|
||||
temp_info[i].size * sizeof(cell_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include <INativeInvoker.h>
|
||||
|
||||
struct ParamInfo
|
||||
{
|
||||
int flags; /* Copy-back flags */
|
||||
bool marked; /* Whether this is marked as being used */
|
||||
cell_t local_addr; /* Local address to free */
|
||||
cell_t *phys_addr; /* Physical address of our copy */
|
||||
cell_t *orig_addr; /* Original address to copy back to */
|
||||
ucell_t size; /* Size of array in bytes */
|
||||
struct
|
||||
{
|
||||
bool is_sz; /* is a string */
|
||||
int sz_flags; /* has sz flags */
|
||||
} str;
|
||||
};
|
||||
|
||||
class NativeInvoker : public INativeInvoker
|
||||
{
|
||||
public:
|
||||
NativeInvoker();
|
||||
~NativeInvoker();
|
||||
public: /* ICallable */
|
||||
int PushCell(cell_t cell);
|
||||
int PushCellByRef(cell_t *cell, int flags=SM_PARAM_COPYBACK);
|
||||
int PushFloat(float number);
|
||||
int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK);
|
||||
int PushArray(cell_t *inarray, unsigned int cells, int flags=0);
|
||||
int PushString(const char *string);
|
||||
int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
|
||||
void Cancel();
|
||||
public: /* INativeInvoker */
|
||||
bool Start(IPluginContext *pContext, const char *name);
|
||||
int Invoke(cell_t *result);
|
||||
private:
|
||||
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
||||
int SetError(int err);
|
||||
private:
|
||||
IPluginContext *pContext;
|
||||
SPVM_NATIVE_FUNC native;
|
||||
cell_t m_params[SP_MAX_EXEC_PARAMS];
|
||||
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int m_curparam;
|
||||
int m_errorstate;
|
||||
};
|
||||
|
||||
class NativeInterface :
|
||||
public INativeInterface,
|
||||
public SMGlobalClass
|
||||
{
|
||||
public: /* SMGlobalClass */
|
||||
void OnSourceModAllInitialized();
|
||||
public: /* SMInterface */
|
||||
unsigned int GetInterfaceVersion();
|
||||
const char *GetInterfaceName();
|
||||
public: /* INativeInvoker */
|
||||
IPluginRuntime *CreateRuntime(const char *name, size_t bytes);
|
||||
INativeInvoker *CreateInvoker();
|
||||
};
|
||||
|
||||
extern NativeInterface g_NInvoke;
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ */
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
#include "PluginSys.h"
|
||||
|
||||
CNativeOwner::CNativeOwner() : m_nMarkSerial(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CNativeOwner::SetMarkSerial(unsigned int serial)
|
||||
{
|
||||
m_nMarkSerial = serial;
|
||||
}
|
||||
|
||||
unsigned int CNativeOwner::GetMarkSerial()
|
||||
{
|
||||
return m_nMarkSerial;
|
||||
}
|
||||
|
||||
void CNativeOwner::AddDependent(CPlugin *pPlugin)
|
||||
{
|
||||
m_Dependents.push_back(pPlugin);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddWeakRef(const WeakNative & ref)
|
||||
{
|
||||
m_WeakRefs.push_back(ref);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((pEntry = g_ShareSys.AddNativeToCache(this, &natives[i])) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Natives.push_back(pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::PropogateMarkSerial(unsigned int serial)
|
||||
{
|
||||
CNativeOwner *pOwner;
|
||||
List<CPlugin *>::iterator iter;
|
||||
|
||||
for (iter = m_Dependents.begin();
|
||||
iter != m_Dependents.end();
|
||||
iter++)
|
||||
{
|
||||
pOwner = (*iter);
|
||||
pOwner->SetMarkSerial(serial);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::UnbindWeakRef(const WeakNative & ref)
|
||||
{
|
||||
sp_native_t *native;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = ref.pl->GetBaseContext();
|
||||
if ((pContext->GetNativeByIndex(ref.idx, &native)) == SP_ERROR_NONE)
|
||||
{
|
||||
/* If there is no reference, the native must be unbound */
|
||||
if (ref.entry == NULL)
|
||||
{
|
||||
native->status = SP_NATIVE_UNBOUND;
|
||||
native->pfn = NULL;
|
||||
}
|
||||
/* If we've cached a reference, it's a core native we can
|
||||
* rebind back to its original (this was a replacement).
|
||||
*/
|
||||
else
|
||||
{
|
||||
native->pfn = ref.entry->func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropEverything()
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
List<WeakNative>::iterator iter;
|
||||
List<NativeEntry *>::iterator ntv_iter;
|
||||
|
||||
/* Unbind and remove all weak references to us */
|
||||
iter = m_WeakRefs.begin();
|
||||
while (iter != m_WeakRefs.end())
|
||||
{
|
||||
UnbindWeakRef((*iter));
|
||||
iter = m_WeakRefs.erase(iter);
|
||||
}
|
||||
|
||||
/* Unmark our replacement natives */
|
||||
ntv_iter = m_ReplacedNatives.begin();
|
||||
while (ntv_iter != m_ReplacedNatives.end())
|
||||
{
|
||||
pEntry = (*ntv_iter);
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
ntv_iter = m_ReplacedNatives.erase(ntv_iter);
|
||||
}
|
||||
|
||||
/* Strip all of our natives from the cache */
|
||||
ntv_iter = m_Natives.begin();
|
||||
while (ntv_iter != m_Natives.end())
|
||||
{
|
||||
g_ShareSys.ClearNativeFromCache(this, (*ntv_iter)->name);
|
||||
ntv_iter = m_Natives.erase(ntv_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropWeakRefsTo(CPlugin *pPlugin)
|
||||
{
|
||||
List<WeakNative>::iterator iter;
|
||||
|
||||
iter = m_WeakRefs.begin();
|
||||
while (iter != m_WeakRefs.end())
|
||||
{
|
||||
WeakNative & ref = (*iter);
|
||||
|
||||
if (ref.pl == pPlugin)
|
||||
{
|
||||
iter = m_WeakRefs.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNativeOwner::DropRefsTo(CPlugin *pPlugin)
|
||||
{
|
||||
m_Dependents.remove(pPlugin);
|
||||
DropWeakRefsTo(pPlugin);
|
||||
}
|
||||
|
||||
void CNativeOwner::AddReplacedNative(NativeEntry *pEntry)
|
||||
{
|
||||
m_ReplacedNatives.push_back(pEntry);
|
||||
}
|
||||
@@ -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,227 @@
|
||||
/**
|
||||
* 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 "HalfLife2.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcehook.h"
|
||||
#include "sm_srvcmds.h"
|
||||
|
||||
NextMapManager g_NextMap;
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *);
|
||||
#else
|
||||
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
#else
|
||||
# if SH_IMPL_VERSION >= 4
|
||||
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
# else
|
||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||
#endif
|
||||
|
||||
ConCommand *changeLevelCmd = NULL;
|
||||
|
||||
ConVar sm_nextmap("sm_nextmap", "", FCVAR_NOTIFY);
|
||||
|
||||
bool g_forcedChange = false;
|
||||
|
||||
void NextMapManager::OnSourceModAllInitialized_Post()
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||
#else
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
||||
#endif
|
||||
|
||||
ConCommand *pCmd = FindCommand("changelevel");
|
||||
if (pCmd != NULL)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdChangeLevelCallback, false);
|
||||
changeLevelCmd = pCmd;
|
||||
}
|
||||
}
|
||||
|
||||
void NextMapManager::OnSourceModShutdown()
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
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 (!g_HL2.IsMapValid(map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sm_nextmap.SetValue(map);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
||||
#else
|
||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const char *video, bool bLongLoading)
|
||||
#endif
|
||||
{
|
||||
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 || !g_HL2.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");
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown));
|
||||
#else
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::ChangeLevel, (newmap, unknown, video, bLongLoading));
|
||||
#endif
|
||||
}
|
||||
|
||||
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), "%s", 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), "%s", mapName);
|
||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "%s", 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 SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
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");
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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[PLATFORM_MAX_PATH];
|
||||
char m_changeReason[100];
|
||||
time_t startTime;
|
||||
};
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CmdChangeLevelCallback(const CCommand &command);
|
||||
#else
|
||||
void CmdChangeLevelCallback();
|
||||
#endif
|
||||
|
||||
class NextMapManager : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
NextMapManager();
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
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);
|
||||
|
||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||
void HookChangeLevel(const char *map, const char *unknown);
|
||||
#else
|
||||
void HookChangeLevel(const char *map, const char *unknown, const char *video, bool bLongLoading);
|
||||
#endif
|
||||
|
||||
public:
|
||||
SourceHook::List<MapChangeData *> m_mapHistory;
|
||||
|
||||
private:
|
||||
MapChangeData m_tempChangeInfo;
|
||||
char lastMap[32];
|
||||
};
|
||||
|
||||
extern NextMapManager g_NextMap;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_NEXTMAP_H_
|
||||
+604
-116
File diff suppressed because it is too large
Load Diff
+53
-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 <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_vector.h>
|
||||
#include "ConVarManager.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@@ -50,6 +51,16 @@ using namespace SourceHook;
|
||||
|
||||
#define MIN_API_FOR_ADMINCALLS 7
|
||||
|
||||
union serial_t
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t index : 8;
|
||||
uint32_t serial : 24;
|
||||
} bits;
|
||||
};
|
||||
|
||||
class CPlayer : public IGamePlayer
|
||||
{
|
||||
friend class PlayerManager;
|
||||
@@ -58,24 +69,29 @@ public:
|
||||
public:
|
||||
const char *GetName();
|
||||
const char *GetIPAddress();
|
||||
const char *GetAuthString();
|
||||
const char *GetAuthString(bool validated = true);
|
||||
unsigned int GetSteamAccountID(bool validated = true);
|
||||
edict_t *GetEdict();
|
||||
bool IsInGame();
|
||||
bool WasCountedAsInGame();
|
||||
bool IsConnected();
|
||||
bool IsAuthorized();
|
||||
bool IsFakeClient();
|
||||
bool IsSourceTV() const;
|
||||
bool IsReplay() const;
|
||||
void SetAdminId(AdminId id, bool temporary);
|
||||
AdminId GetAdminId();
|
||||
void Kick(const char *str);
|
||||
bool IsInKickQueue();
|
||||
IPlayerInfo *GetPlayerInfo();
|
||||
unsigned int GetLanguageId();
|
||||
void SetLanguageId(unsigned int id);
|
||||
int GetUserId();
|
||||
bool RunAdminCacheChecks();
|
||||
void NotifyPostAdminChecks();
|
||||
unsigned int GetSerial();
|
||||
public:
|
||||
void DoBasicAdminChecks();
|
||||
bool IsInKickQueue();
|
||||
void MarkAsBeingKicked();
|
||||
int GetLifeState();
|
||||
private:
|
||||
@@ -84,9 +100,11 @@ private:
|
||||
void Disconnect();
|
||||
void SetName(const char *name);
|
||||
void DumpAdmin(bool deleting);
|
||||
void Authorize(const char *auth);
|
||||
void SetAuthString(const char *auth);
|
||||
void Authorize();
|
||||
void Authorize_Post();
|
||||
void DoPostConnectAuthorization();
|
||||
bool IsAuthStringValidated();
|
||||
private:
|
||||
bool m_IsConnected;
|
||||
bool m_IsInGame;
|
||||
@@ -105,6 +123,11 @@ private:
|
||||
int m_iIndex;
|
||||
unsigned int m_LangId;
|
||||
int m_UserId;
|
||||
bool m_bFakeClient;
|
||||
bool m_bIsSourceTV;
|
||||
bool m_bIsReplay;
|
||||
serial_t m_Serial;
|
||||
unsigned int m_SteamAccountID;
|
||||
};
|
||||
|
||||
class PlayerManager :
|
||||
@@ -120,6 +143,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();
|
||||
@@ -131,7 +155,7 @@ public:
|
||||
void OnClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
void OnClientDisconnect(edict_t *pEntity);
|
||||
void OnClientDisconnect_Post(edict_t *pEntity);
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void OnClientCommand(edict_t *pEntity, const CCommand &args);
|
||||
#else
|
||||
void OnClientCommand(edict_t *pEntity);
|
||||
@@ -152,6 +176,7 @@ public: //IPlayerManager
|
||||
void RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||
void ProcessCommandTarget(cmd_target_info_t *info);
|
||||
int GetClientFromSerial(unsigned int serial);
|
||||
public:
|
||||
inline int MaxClients()
|
||||
{
|
||||
@@ -161,17 +186,24 @@ 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;
|
||||
IForward *m_clconnect_post;
|
||||
IForward *m_cldisconnect;
|
||||
IForward *m_cldisconnect_post;
|
||||
IForward *m_clputinserver;
|
||||
@@ -184,12 +216,28 @@ private:
|
||||
int *m_UserIdLookUp;
|
||||
int m_maxClients;
|
||||
int m_PlayerCount;
|
||||
int m_PlayersSinceActive;
|
||||
bool m_FirstPass;
|
||||
unsigned int *m_AuthQueue;
|
||||
String m_PassInfoVar;
|
||||
bool m_QueryLang;
|
||||
bool m_bAuthstringValidation; // are we validating admins with steam before authorizing?
|
||||
bool m_bIsListenServer;
|
||||
int m_ListenClient;
|
||||
bool m_bIsSourceTVActive;
|
||||
bool m_bIsReplayActive;
|
||||
int m_SourceTVUserId;
|
||||
int m_ReplayUserId;
|
||||
};
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
void CmdMaxplayersCallback(const CCommand &command);
|
||||
#else
|
||||
void CmdMaxplayersCallback();
|
||||
#endif
|
||||
|
||||
extern void ClientConsolePrint(edict_t *e, const char *fmt, ...);
|
||||
|
||||
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
|
||||
@@ -276,7 +276,7 @@ SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
{
|
||||
m_infodb_size *= 2;
|
||||
}
|
||||
int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
|
||||
int newidx = memtab->CreateMem(m_infodb_size * sizeof(int), (void **)&table);
|
||||
if (m_infodb != -1)
|
||||
{
|
||||
void *oldtable = (int *)memtab->GetAddress(m_infodb);
|
||||
@@ -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-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -43,16 +43,25 @@
|
||||
#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"
|
||||
#include <IRootConsoleMenu.h>
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ALIENSWARM
|
||||
#include "convar_sm_swarm.h"
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
#include "convar_sm_l4d.h"
|
||||
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
#include "convar_sm_ob.h"
|
||||
#else
|
||||
#include "convar_sm.h"
|
||||
#endif
|
||||
#include "ITranslator.h"
|
||||
#include "IGameConfigs.h"
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
class CPlayer;
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@@ -106,35 +115,28 @@ 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,
|
||||
LoadRes_AlreadyLoaded,
|
||||
LoadRes_Failure,
|
||||
LoadRes_SilentFailure,
|
||||
LoadRes_NeverLoad
|
||||
};
|
||||
|
||||
enum APLRes
|
||||
{
|
||||
APLRes_Success,
|
||||
APLRes_Failure,
|
||||
APLRes_SilentFailure
|
||||
};
|
||||
|
||||
enum LibraryAction
|
||||
{
|
||||
LibraryAction_Removed,
|
||||
LibraryAction_Added
|
||||
};
|
||||
|
||||
struct AutoConfig
|
||||
{
|
||||
String autocfg;
|
||||
@@ -143,18 +145,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 +159,21 @@ public:
|
||||
PluginType GetType();
|
||||
SourcePawn::IPluginContext *GetBaseContext();
|
||||
sp_context_t *GetContext();
|
||||
const sm_plugininfo_t *GetPublicInfo();
|
||||
void *GetPluginStructure();
|
||||
const char *GetFilename();
|
||||
bool IsDebugging();
|
||||
PluginStatus GetStatus();
|
||||
bool IsSilentlyFailed();
|
||||
void SetSilentlyFailed(bool sf);
|
||||
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 +184,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
|
||||
@@ -214,7 +202,7 @@ public:
|
||||
*
|
||||
* If the error buffer is NULL, the error message is cached locally.
|
||||
*/
|
||||
bool Call_AskPluginLoad(char *error, size_t maxlength);
|
||||
APLRes Call_AskPluginLoad(char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Calls the OnPluginStart function.
|
||||
@@ -233,30 +221,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 +248,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);
|
||||
@@ -282,29 +256,25 @@ public:
|
||||
{
|
||||
m_Libraries.push_back(name);
|
||||
}
|
||||
void LibraryActions(bool dropping);
|
||||
void LibraryActions(LibraryAction action);
|
||||
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;
|
||||
bool m_bSilentlyFailed;
|
||||
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 +282,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 +333,8 @@ public: //IPluginManager
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
|
||||
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 +367,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 +382,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
|
||||
@@ -440,7 +409,7 @@ public:
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
|
||||
void OnLibraryAction(const char *lib, LibraryAction action);
|
||||
|
||||
bool LibraryExists(const char *lib);
|
||||
|
||||
@@ -449,6 +418,10 @@ public:
|
||||
void UnloadAll();
|
||||
|
||||
CPlugin *FindPluginByConsoleArg(const char *arg);
|
||||
|
||||
void SyncMaxClients(int max_clients);
|
||||
|
||||
void ListPluginsToClient(CPlayer *player, const CCommand &args);
|
||||
private:
|
||||
LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
|
||||
|
||||
@@ -469,11 +442,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 +463,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,15 +473,21 @@ 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;
|
||||
|
||||
// Config
|
||||
bool m_bBlockBadPlugins;
|
||||
|
||||
// Forwards
|
||||
IForward *m_pOnLibraryAdded;
|
||||
IForward *m_pOnLibraryRemoved;
|
||||
};
|
||||
|
||||
extern CPluginManager g_PluginSys;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||
|
||||
@@ -0,0 +1,611 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||
const char *name)
|
||||
{
|
||||
if (m_caps.retrieve(name) != NULL)
|
||||
return;
|
||||
|
||||
Capability cap;
|
||||
cap.ext = myself;
|
||||
cap.provider = provider;
|
||||
|
||||
m_caps.insert(name, cap);
|
||||
}
|
||||
|
||||
void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||
const char *name)
|
||||
{
|
||||
Capability *pCap = m_caps.retrieve(name);
|
||||
if (pCap == NULL)
|
||||
return;
|
||||
|
||||
if (pCap->ext != myself || pCap->provider != provider)
|
||||
return;
|
||||
|
||||
m_caps.remove(name);
|
||||
}
|
||||
|
||||
FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature,
|
||||
const char *name)
|
||||
{
|
||||
switch (feature)
|
||||
{
|
||||
case FeatureType_Native:
|
||||
return TestNative(pRuntime, name);
|
||||
case FeatureType_Capability:
|
||||
return TestCap(name);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FeatureStatus_Unknown;
|
||||
}
|
||||
|
||||
FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name)
|
||||
{
|
||||
uint32_t index;
|
||||
|
||||
if (pRuntime->FindNativeByName(name, &index) == SP_ERROR_NONE)
|
||||
{
|
||||
sp_native_t *native;
|
||||
if (pRuntime->GetNativeByIndex(index, &native) == SP_ERROR_NONE)
|
||||
{
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
return FeatureStatus_Available;
|
||||
else
|
||||
return FeatureStatus_Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
NativeEntry *entry = FindNative(name);
|
||||
if (entry == NULL)
|
||||
return FeatureStatus_Unknown;
|
||||
|
||||
if ((entry->replacement.owner != NULL || entry->owner != NULL) &&
|
||||
(entry->replacement.func != NULL || entry->func != NULL))
|
||||
{
|
||||
return FeatureStatus_Available;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FeatureStatus_Unavailable;
|
||||
}
|
||||
}
|
||||
|
||||
FeatureStatus ShareSystem::TestCap(const char *name)
|
||||
{
|
||||
Capability *cap = m_caps.retrieve(name);
|
||||
if (cap == NULL)
|
||||
return FeatureStatus_Unknown;
|
||||
|
||||
return cap->provider->GetFeatureStatus(FeatureType_Capability, name);
|
||||
}
|
||||
@@ -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,44 @@ struct IfaceInfo
|
||||
IExtension *owner;
|
||||
};
|
||||
|
||||
class ShareSystem :
|
||||
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;
|
||||
};
|
||||
|
||||
struct Capability
|
||||
{
|
||||
IExtension *ext;
|
||||
IFeatureProvider *provider;
|
||||
};
|
||||
|
||||
class ShareSystem :
|
||||
public IShareSys,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
{
|
||||
friend class CNativeOwner;
|
||||
public:
|
||||
ShareSystem();
|
||||
public: //IShareSys
|
||||
@@ -82,6 +116,10 @@ public: //IShareSys
|
||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||
void RegisterLibrary(IExtension *myself, const char *name);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
void AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||
const char *name);
|
||||
void DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||
const char *name);
|
||||
public: //SMGlobalClass
|
||||
/* Pre-empt in case anything tries to register idents early */
|
||||
void Initialize();
|
||||
@@ -91,17 +129,34 @@ public: //IHandleTypeDispatch
|
||||
public:
|
||||
IdentityToken_t *CreateCoreIdentity();
|
||||
void RemoveInterfaces(IExtension *pExtension);
|
||||
FeatureStatus TestFeature(IPluginRuntime *pRuntime, FeatureType feature, const char *name);
|
||||
FeatureStatus TestNative(IPluginRuntime *pRuntime, const char *name);
|
||||
FeatureStatus TestCap(const char *name);
|
||||
public:
|
||||
inline IdentityToken_t *GetIdentRoot()
|
||||
{
|
||||
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);
|
||||
NativeEntry *FindNative(const char *name);
|
||||
private:
|
||||
NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
|
||||
void ClearNativeFromCache(CNativeOwner *pOwner, 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;
|
||||
KTrie<Capability> m_caps;
|
||||
};
|
||||
|
||||
extern ShareSystem g_ShareSys;
|
||||
+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
-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
|
||||
@@ -78,11 +78,11 @@ public: //ITimerSystem
|
||||
float GetTickedTime();
|
||||
void NotifyOfGameStart(float offset /* = 0.0f */);
|
||||
bool GetMapTimeLeft(float *pTime);
|
||||
IMapTimer *GetMapTimer();
|
||||
public:
|
||||
void RunFrame();
|
||||
void RemoveMapChangeTimers();
|
||||
void GameFrame(bool simulating);
|
||||
IMapTimer *GetMapTimer();
|
||||
private:
|
||||
List<ITimer *> m_SingleTimers;
|
||||
List<ITimer *> m_LoopTimers;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+363
-38
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -32,14 +32,32 @@
|
||||
#include "UserMessages.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#include <cstrike15_usermessage_helpers.h>
|
||||
#endif
|
||||
|
||||
UserMessages g_UserMsgs;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||
#else
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
|
||||
#else
|
||||
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
||||
#endif
|
||||
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
||||
#endif // ==SE_CSGO
|
||||
|
||||
UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
|
||||
UserMessages::UserMessages()
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
: m_InterceptBuffer(m_pBase, 2500)
|
||||
{
|
||||
m_Names = sm_trie_create();
|
||||
#else
|
||||
: m_InterceptBuffer(NULL)
|
||||
{
|
||||
#endif
|
||||
m_HookCount = 0;
|
||||
m_InExec = false;
|
||||
m_InHook = false;
|
||||
@@ -49,7 +67,9 @@ UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
|
||||
|
||||
UserMessages::~UserMessages()
|
||||
{
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
sm_trie_destroy(m_Names);
|
||||
#endif
|
||||
|
||||
CStack<ListenerInfo *>::iterator iter;
|
||||
for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
|
||||
@@ -61,8 +81,10 @@ UserMessages::~UserMessages()
|
||||
|
||||
void UserMessages::OnSourceModStartup(bool late)
|
||||
{
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
/* -1 means SourceMM was unable to get the user message list */
|
||||
m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UserMessages::OnSourceModAllInitialized()
|
||||
@@ -74,16 +96,25 @@ void UserMessages::OnSourceModAllShutdown()
|
||||
{
|
||||
if (m_HookCount)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
|
||||
#else
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
|
||||
#endif
|
||||
}
|
||||
m_HookCount = 0;
|
||||
}
|
||||
|
||||
int UserMessages::GetMessageIndex(const char *msg)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
// Can split this per engine and/or game later
|
||||
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
||||
#else
|
||||
int msgid;
|
||||
|
||||
if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
|
||||
@@ -114,10 +145,19 @@ int UserMessages::GetMessageIndex(const char *msg)
|
||||
}
|
||||
|
||||
return msgid;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
||||
if (!pszName)
|
||||
return false;
|
||||
|
||||
strncopy(buffer, pszName, maxlength);
|
||||
return true;
|
||||
#else
|
||||
if (m_FallbackSearch)
|
||||
{
|
||||
int size;
|
||||
@@ -133,10 +173,14 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
|
||||
bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
return NULL;
|
||||
#else
|
||||
bf_write *buffer;
|
||||
|
||||
if (m_InExec || m_InHook)
|
||||
@@ -164,12 +208,89 @@ bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigne
|
||||
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
|
||||
#else
|
||||
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
||||
#endif
|
||||
} else {
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
|
||||
#else
|
||||
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
return buffer;
|
||||
#endif // USE_PROTOBUF_USERMESSAGES
|
||||
}
|
||||
|
||||
google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
|
||||
{
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
return NULL;
|
||||
#else
|
||||
protobuf::Message *buffer;
|
||||
|
||||
if (m_InExec || m_InHook)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (msg_id < 0 || msg_id >= 255)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_CurId = msg_id;
|
||||
m_CellRecFilter.Initialize(players, playersNum);
|
||||
|
||||
m_CurFlags = flags;
|
||||
if (m_CurFlags & USERMSG_INITMSG)
|
||||
{
|
||||
m_CellRecFilter.SetToInit(true);
|
||||
}
|
||||
if (m_CurFlags & USERMSG_RELIABLE)
|
||||
{
|
||||
m_CellRecFilter.SetToReliable(true);
|
||||
}
|
||||
|
||||
m_InExec = true;
|
||||
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
// direct message creation, return buffer "from engine". keep track
|
||||
m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
|
||||
buffer = m_FakeEngineBuffer;
|
||||
} else {
|
||||
char messageName[32];
|
||||
if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
|
||||
{
|
||||
m_InExec = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
switch (m_FakeMetaRes)
|
||||
{
|
||||
case MRES_IGNORED:
|
||||
case MRES_HANDLED:
|
||||
m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
|
||||
buffer = m_FakeEngineBuffer;
|
||||
break;
|
||||
|
||||
case MRES_OVERRIDE:
|
||||
m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
|
||||
// fallthrough
|
||||
case MRES_SUPERCEDE:
|
||||
buffer = msg;
|
||||
break;
|
||||
}
|
||||
|
||||
OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
#endif // USE_PROTOBUF_USERMESSAGES
|
||||
}
|
||||
|
||||
bool UserMessages::EndMessage()
|
||||
@@ -179,12 +300,37 @@ bool UserMessages::EndMessage()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
delete m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer = NULL;
|
||||
} else {
|
||||
OnMessageEnd_Pre();
|
||||
|
||||
switch (m_FakeMetaRes)
|
||||
{
|
||||
case MRES_IGNORED:
|
||||
case MRES_HANDLED:
|
||||
case MRES_OVERRIDE:
|
||||
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
delete m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer = NULL;
|
||||
break;
|
||||
//case MRES_SUPERCEDE:
|
||||
}
|
||||
|
||||
OnMessageEnd_Post();
|
||||
}
|
||||
#else
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
ENGINE_CALL(MessageEnd)();
|
||||
} else {
|
||||
engine->MessageEnd();
|
||||
}
|
||||
#endif // SE_CSGO
|
||||
|
||||
m_InExec = false;
|
||||
m_CurFlags = 0;
|
||||
@@ -193,7 +339,60 @@ bool UserMessages::EndMessage()
|
||||
return true;
|
||||
}
|
||||
|
||||
UserMessageType UserMessages::GetUserMessageType() const
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
return UM_Protobuf;
|
||||
#else
|
||||
return UM_BitBuf;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UserMessages::HookUserMessage2(int msg_id,
|
||||
IUserMessageListener *pListener,
|
||||
bool intercept)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
|
||||
#else
|
||||
return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UserMessages::UnhookUserMessage2(int msg_id,
|
||||
IUserMessageListener *pListener,
|
||||
bool intercept)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
|
||||
#else
|
||||
return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
|
||||
#else
|
||||
return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
|
||||
#else
|
||||
return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
|
||||
#else
|
||||
bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
|
||||
#endif
|
||||
{
|
||||
if (msg_id < 0 || msg_id >= 255)
|
||||
{
|
||||
@@ -212,13 +411,19 @@ bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener,
|
||||
pInfo->Callback = pListener;
|
||||
pInfo->IsHooked = false;
|
||||
pInfo->KillMe = false;
|
||||
pInfo->IsNew = isNew;
|
||||
|
||||
if (!m_HookCount++)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
|
||||
#else
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
|
||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (intercept)
|
||||
@@ -231,8 +436,12 @@ bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
|
||||
#else
|
||||
bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
|
||||
#endif
|
||||
{
|
||||
MsgList *pList;
|
||||
MsgIter iter;
|
||||
ListenerInfo *pInfo;
|
||||
@@ -247,7 +456,7 @@ bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener
|
||||
for (iter=pList->begin(); iter!=pList->end(); iter++)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
if (pInfo->Callback == pListener)
|
||||
if (pInfo->Callback == pListener && pInfo->IsNew == isNew)
|
||||
{
|
||||
if (pInfo->IsHooked)
|
||||
{
|
||||
@@ -272,14 +481,73 @@ void UserMessages::_DecRefCounter()
|
||||
{
|
||||
if (--m_HookCount == 0)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
|
||||
#else
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
||||
{
|
||||
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
{
|
||||
int size = msg.ByteSize();
|
||||
uint8 *data = (uint8 *)stackalloc(size);
|
||||
msg.SerializePartialToArray(data, size);
|
||||
m_InterceptBuffer->ParsePartialFromArray(data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
||||
}
|
||||
|
||||
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
||||
|
||||
OnMessageEnd_Pre();
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
||||
{
|
||||
OnMessageEnd_Post();
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
#define UM_RETURN_META_VALUE(res, val) \
|
||||
m_FakeMetaRes = res; \
|
||||
return val;
|
||||
|
||||
#define UM_RETURN_META(res) \
|
||||
m_FakeMetaRes = res; \
|
||||
return;
|
||||
#else
|
||||
#define UM_RETURN_META_VALUE(res, val) \
|
||||
RETURN_META_VALUE(res, val)
|
||||
|
||||
#define UM_RETURN_META(res) \
|
||||
RETURN_META(res)
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#else
|
||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
|
||||
#endif
|
||||
{
|
||||
bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
|
||||
bool is_hook_empty = m_msgHooks[msg_type].empty();
|
||||
@@ -288,7 +556,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
|
||||
{
|
||||
m_InHook = false;
|
||||
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
m_CurId = msg_type;
|
||||
@@ -298,42 +566,72 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
|
||||
if (!is_intercept_empty)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
if (m_InterceptBuffer)
|
||||
delete m_InterceptBuffer;
|
||||
m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
|
||||
#else
|
||||
m_InterceptBuffer.Reset();
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#else
|
||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
|
||||
#endif
|
||||
{
|
||||
if (!m_InHook)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
m_OrigBuffer = m_InterceptBuffer;
|
||||
else
|
||||
m_OrigBuffer = m_FakeEngineBuffer;
|
||||
#else
|
||||
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
|
||||
#endif
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
}
|
||||
|
||||
void UserMessages::OnMessageEnd_Post()
|
||||
{
|
||||
if (!m_InHook || m_BlockEndPost)
|
||||
if (!m_InHook)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
UM_RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
MsgList *pList;
|
||||
MsgIter iter;
|
||||
ListenerInfo *pInfo;
|
||||
|
||||
m_InHook = false;
|
||||
|
||||
pList = &m_msgIntercepts[m_CurId];
|
||||
for (iter=pList->begin(); iter!=pList->end(); )
|
||||
{
|
||||
pInfo = (*iter);
|
||||
if (m_BlockEndPost && !pInfo->IsNew)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pInfo->IsHooked = true;
|
||||
pInfo->Callback->OnUserMessageSent(m_CurId);
|
||||
if (pInfo->IsNew)
|
||||
{
|
||||
pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
|
||||
}
|
||||
|
||||
if (pInfo->KillMe)
|
||||
{
|
||||
@@ -347,14 +645,20 @@ void UserMessages::OnMessageEnd_Post()
|
||||
iter++;
|
||||
}
|
||||
|
||||
m_InHook = false;
|
||||
|
||||
pList = &m_msgHooks[m_CurId];
|
||||
for (iter=pList->begin(); iter!=pList->end(); )
|
||||
{
|
||||
pInfo = (*iter);
|
||||
if (m_BlockEndPost && !pInfo->IsNew)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pInfo->IsHooked = true;
|
||||
pInfo->Callback->OnUserMessageSent(m_CurId);
|
||||
if (pInfo->IsNew)
|
||||
{
|
||||
pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
|
||||
}
|
||||
|
||||
if (pInfo->KillMe)
|
||||
{
|
||||
@@ -373,7 +677,7 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
{
|
||||
if (!m_InHook)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
UM_RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
MsgList *pList;
|
||||
@@ -389,7 +693,11 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
{
|
||||
pInfo = (*iter);
|
||||
pInfo->IsHooked = true;
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
|
||||
#else
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
|
||||
#endif
|
||||
|
||||
intercepted = true;
|
||||
|
||||
@@ -435,43 +743,60 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
iter++;
|
||||
}
|
||||
|
||||
if (handled)
|
||||
{
|
||||
goto supercede;
|
||||
}
|
||||
|
||||
if (intercepted)
|
||||
if (!handled && intercepted)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||
#else
|
||||
bf_write *engine_bfw;
|
||||
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
|
||||
#else
|
||||
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
|
||||
#endif
|
||||
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
||||
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
||||
ENGINE_CALL(MessageEnd)();
|
||||
#endif // SE_CSGO
|
||||
}
|
||||
|
||||
pList = &m_msgHooks[m_CurId];
|
||||
for (iter=pList->begin(); iter!=pList->end(); )
|
||||
{
|
||||
pInfo = (*iter);
|
||||
pInfo->IsHooked = true;
|
||||
pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
int size = m_OrigBuffer->ByteSize();
|
||||
uint8 *data = (uint8 *)stackalloc(size);
|
||||
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||
protobuf::Message *pTempMsg = g_Cstrike15UsermessageHelpers.GetPrototype(m_CurId)->New();
|
||||
pTempMsg->ParsePartialFromArray(data, size);
|
||||
#else
|
||||
bf_write *pTempMsg = m_OrigBuffer;
|
||||
#endif
|
||||
|
||||
if (pInfo->KillMe)
|
||||
pList = &m_msgHooks[m_CurId];
|
||||
for (iter=pList->begin(); iter!=pList->end(); )
|
||||
{
|
||||
iter = pList->erase(iter);
|
||||
m_FreeListeners.push(pInfo);
|
||||
_DecRefCounter();
|
||||
continue;
|
||||
pInfo = (*iter);
|
||||
pInfo->IsHooked = true;
|
||||
pInfo->Callback->OnUserMessage(m_CurId, pTempMsg, m_CurRecFilter);
|
||||
|
||||
if (pInfo->KillMe)
|
||||
{
|
||||
iter = pList->erase(iter);
|
||||
m_FreeListeners.push(pInfo);
|
||||
_DecRefCounter();
|
||||
continue;
|
||||
}
|
||||
|
||||
pInfo->IsHooked = false;
|
||||
iter++;
|
||||
}
|
||||
|
||||
pInfo->IsHooked = false;
|
||||
iter++;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
delete pTempMsg;
|
||||
#endif
|
||||
}
|
||||
|
||||
RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
|
||||
UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
|
||||
supercede:
|
||||
m_InHook = false;
|
||||
m_BlockEndPost = true;
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
UM_RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
+63
-4
@@ -2,7 +2,7 @@
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -36,18 +36,38 @@
|
||||
#include <IUserMessages.h>
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_trie.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "CellRecipientFilter.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#define USE_PROTOBUF_USERMESSAGES
|
||||
#endif
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <netmessages.pb.h>
|
||||
|
||||
using namespace google;
|
||||
#else
|
||||
#include <bitbuf.h>
|
||||
#endif
|
||||
|
||||
#define INVALID_MESSAGE_ID -1
|
||||
|
||||
struct ListenerInfo
|
||||
{
|
||||
IUserMessageListener *Callback;
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
IProtobufUserMessageListener *Callback;
|
||||
#else
|
||||
IBitBufUserMessageListener *Callback;
|
||||
#endif
|
||||
bool IsHooked;
|
||||
bool KillMe;
|
||||
bool IsNew;
|
||||
};
|
||||
|
||||
typedef List<ListenerInfo *> MsgList;
|
||||
@@ -69,30 +89,69 @@ public: //IUserMessages
|
||||
bool GetMessageName(int msgid, char *buffer, size_t maxlength) const;
|
||||
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||
bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||
bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
|
||||
bf_write *StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
|
||||
google::protobuf::Message *StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
|
||||
bool EndMessage();
|
||||
bool HookUserMessage2(int msg_id,
|
||||
IUserMessageListener *pListener,
|
||||
bool intercept=false);
|
||||
bool UnhookUserMessage2(int msg_id,
|
||||
IUserMessageListener *pListener,
|
||||
bool intercept=false);
|
||||
UserMessageType GetUserMessageType() const;
|
||||
public:
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
#else
|
||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type);
|
||||
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type);
|
||||
#endif
|
||||
void OnMessageEnd_Pre();
|
||||
void OnMessageEnd_Post();
|
||||
private:
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
#else
|
||||
bool InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
bool InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
#endif
|
||||
void _DecRefCounter();
|
||||
private:
|
||||
List<ListenerInfo *> m_msgHooks[255];
|
||||
List<ListenerInfo *> m_msgIntercepts[255];
|
||||
CStack<ListenerInfo *> m_FreeListeners;
|
||||
unsigned char m_pBase[2500];
|
||||
IRecipientFilter *m_CurRecFilter;
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
unsigned char m_pBase[2500];
|
||||
bf_write m_InterceptBuffer;
|
||||
bf_write *m_OrigBuffer;
|
||||
bf_read m_ReadBuffer;
|
||||
#else
|
||||
// The engine used to provide this. Now we track it.
|
||||
protobuf::Message *m_OrigBuffer;
|
||||
protobuf::Message *m_FakeEngineBuffer;
|
||||
META_RES m_FakeMetaRes;
|
||||
|
||||
protobuf::Message *m_InterceptBuffer;
|
||||
#endif
|
||||
size_t m_HookCount;
|
||||
bool m_InHook;
|
||||
bool m_BlockEndPost;
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
bool m_FallbackSearch;
|
||||
|
||||
Trie *m_Names;
|
||||
#endif
|
||||
CellRecipientFilter m_CellRecFilter;
|
||||
bool m_InExec;
|
||||
int m_CurFlags;
|
||||
|
||||
+35
-21
@@ -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,9 +35,13 @@
|
||||
#include "concmd_cleaner.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "compat_wrappers.h"
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#else
|
||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#endif
|
||||
|
||||
using namespace SourceHook;
|
||||
@@ -50,29 +54,55 @@ struct ConCommandInfo
|
||||
};
|
||||
|
||||
List<ConCommandInfo *> tracked_bases;
|
||||
IConCommandLinkListener *IConCommandLinkListener::head = NULL;
|
||||
|
||||
ConCommandBase *FindConCommandBase(const char *name);
|
||||
|
||||
class ConCommandCleaner : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void OnSourceModAllInitialized()
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, RegisterConCommand, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||
#else
|
||||
SH_ADD_HOOK_MEMFUNC(ICvar, RegisterConCommandBase, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnSourceModShutdown()
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
||||
}
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, RegisterConCommand, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||
#else
|
||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, RegisterConCommandBase, icvar, this, &ConCommandCleaner::LinkConCommandBase, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LinkConCommandBase(ConCommandBase *pBase)
|
||||
{
|
||||
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||
while (listener)
|
||||
{
|
||||
listener->OnLinkConCommand(pBase);
|
||||
listener = listener->next;
|
||||
}
|
||||
}
|
||||
|
||||
void UnlinkConCommandBase(ConCommandBase *pBase)
|
||||
{
|
||||
ConCommandInfo *pInfo;
|
||||
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
|
||||
|
||||
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||
while (listener)
|
||||
{
|
||||
listener->OnUnlinkConCommand(pBase);
|
||||
listener = listener->next;
|
||||
}
|
||||
|
||||
if (pBase)
|
||||
{
|
||||
while (iter != tracked_bases.end())
|
||||
@@ -95,7 +125,7 @@ public:
|
||||
while (iter != tracked_bases.end())
|
||||
{
|
||||
/* This is just god-awful! */
|
||||
if (FindConCommandBase((*iter)->name) != (*iter)->pBase)
|
||||
if (FindCommandBase((*iter)->name) != (*iter)->pBase)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
iter = tracked_bases.erase(iter);
|
||||
@@ -143,22 +173,6 @@ public:
|
||||
}
|
||||
} s_ConCmdTracker;
|
||||
|
||||
ConCommandBase *FindConCommandBase(const char *name)
|
||||
{
|
||||
const ConCommandBase *pBase = icvar->GetCommands();
|
||||
|
||||
while (pBase != NULL)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), name) == 0)
|
||||
{
|
||||
return const_cast<ConCommandBase *>(pBase);
|
||||
}
|
||||
pBase = pBase->GetNext();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
|
||||
{
|
||||
s_ConCmdTracker.AddTarget(pBase, me);
|
||||
|
||||
+23
-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
|
||||
@@ -38,9 +38,30 @@ public:
|
||||
virtual void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe) = 0;
|
||||
};
|
||||
|
||||
ConCommandBase *FindConCommandBase(const char *name);
|
||||
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
|
||||
|
||||
class IConCommandLinkListener
|
||||
{
|
||||
friend class ConCommandCleaner;
|
||||
|
||||
static IConCommandLinkListener *head;
|
||||
IConCommandLinkListener *next;
|
||||
public:
|
||||
IConCommandLinkListener()
|
||||
{
|
||||
next = head;
|
||||
head = this;
|
||||
}
|
||||
|
||||
virtual void OnLinkConCommand(ConCommandBase *pBase)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnUnlinkConCommand(ConCommandBase *pBase)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_CONCMD_TRACKER_H_
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef CONVAR_H
|
||||
#define CONVAR_H
|
||||
|
||||
#if _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/iconvar.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utlstring.h"
|
||||
#include "icvar.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FORCEINLINE_CVAR FORCEINLINE
|
||||
#elif defined _LINUX || defined __APPLE__
|
||||
#define FORCEINLINE_CVAR inline
|
||||
#else
|
||||
#error "implement me"
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar;
|
||||
class CCommand;
|
||||
class ConCommand;
|
||||
class ConCommandBase;
|
||||
struct characterset_t;
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Any executable that wants to use ConVars need to implement one of
|
||||
// these to hook up access to console variables.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IConCommandBaseAccessor
|
||||
{
|
||||
public:
|
||||
// Flags is a combination of FCVAR flags in cvar.h.
|
||||
// hOut is filled in with a handle to the variable.
|
||||
virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method for console development
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined( _X360 ) && !defined( _RETAIL )
|
||||
void ConVar_PublishToVXConsole();
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called when a ConCommand needs to execute
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef void ( *FnCommandCallbackV1_t )( void );
|
||||
typedef void ( *FnCommandCallback_t )( const CCommand &command );
|
||||
|
||||
#define COMMAND_COMPLETION_MAXITEMS 64
|
||||
#define COMMAND_COMPLETION_ITEM_LENGTH 64
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Interface version
|
||||
//-----------------------------------------------------------------------------
|
||||
class ICommandCallback
|
||||
{
|
||||
public:
|
||||
virtual void CommandCallback( const CCommand &command ) = 0;
|
||||
};
|
||||
|
||||
class ICommandCompletionCallback
|
||||
{
|
||||
public:
|
||||
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The base console invoked command/cvar interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommandBase
|
||||
{
|
||||
friend class CCvar;
|
||||
friend class ConVar;
|
||||
friend class ConCommand;
|
||||
friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor );
|
||||
friend void ConVar_PublishToVXConsole();
|
||||
|
||||
// FIXME: Remove when ConVar changes are done
|
||||
friend class CDefaultCvar;
|
||||
|
||||
public:
|
||||
ConCommandBase( void );
|
||||
ConCommandBase( const char *pName, const char *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
virtual ~ConCommandBase( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
// Check flag
|
||||
virtual bool IsFlagSet( int flag ) const;
|
||||
// Set flag
|
||||
virtual void AddFlags( int flags );
|
||||
// Remove flag
|
||||
virtual void RemoveFlags( int flags );
|
||||
// Get flags
|
||||
virtual int GetFlags( void ) const;
|
||||
|
||||
// Return name of cvar
|
||||
virtual const char *GetName( void ) const;
|
||||
|
||||
// Return help text for cvar
|
||||
virtual const char *GetHelpText( void ) const;
|
||||
|
||||
// Deal with next pointer
|
||||
const ConCommandBase *GetNext( void ) const;
|
||||
ConCommandBase *GetNext( void );
|
||||
|
||||
inline void SetNext(ConCommandBase *pBase)
|
||||
{
|
||||
m_pNext = pBase;
|
||||
}
|
||||
|
||||
virtual bool IsRegistered( void ) const;
|
||||
|
||||
// Returns the DLL identifier
|
||||
virtual CVarDLLIdentifier_t GetDLLIdentifier() const;
|
||||
|
||||
protected:
|
||||
virtual void Create( const char *pName, const char *pHelpString = 0,
|
||||
int flags = 0 );
|
||||
|
||||
// Used internally by OneTimeInit to initialize/shutdown
|
||||
virtual void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Internal copy routine ( uses new operator from correct module )
|
||||
char *CopyString( const char *from );
|
||||
|
||||
private:
|
||||
// Next ConVar in chain
|
||||
// Prior to register, it points to the next convar in the DLL.
|
||||
// Once registered, though, m_pNext is reset to point to the next
|
||||
// convar in the global list
|
||||
ConCommandBase *m_pNext;
|
||||
|
||||
// Has the cvar been added to the global list?
|
||||
bool m_bRegistered;
|
||||
|
||||
// Static data
|
||||
const char *m_pszName;
|
||||
const char *m_pszHelpString;
|
||||
|
||||
// ConVar flags
|
||||
int m_nFlags;
|
||||
|
||||
protected:
|
||||
// ConVars add themselves to this list for the executable.
|
||||
// Then ConVar_Register runs through all the console variables
|
||||
// and registers them into a global list stored in vstdlib.dll
|
||||
static ConCommandBase *s_pConCommandBases;
|
||||
|
||||
// ConVars in this executable use this 'global' to access values.
|
||||
static IConCommandBaseAccessor *s_pAccessor;
|
||||
public:
|
||||
inline void SetFlags(int flags)
|
||||
{
|
||||
m_nFlags = flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command tokenizer
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCommand
|
||||
{
|
||||
public:
|
||||
CCommand();
|
||||
CCommand( int nArgC, const char **ppArgV );
|
||||
bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL );
|
||||
void Reset();
|
||||
|
||||
int ArgC() const;
|
||||
const char **ArgV() const;
|
||||
const char *ArgS() const; // All args that occur after the 0th arg, in string form
|
||||
const char *GetCommandString() const; // The entire command in string form, including the 0th arg
|
||||
const char *operator[]( int nIndex ) const; // Gets at arguments
|
||||
const char *Arg( int nIndex ) const; // Gets at arguments
|
||||
|
||||
// Helper functions to parse arguments to commands.
|
||||
const char* FindArg( const char *pName ) const;
|
||||
int FindArgInt( const char *pName, int nDefaultVal ) const;
|
||||
|
||||
static int MaxCommandLength();
|
||||
static characterset_t* DefaultBreakSet();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
COMMAND_MAX_ARGC = 64,
|
||||
COMMAND_MAX_LENGTH = 512,
|
||||
};
|
||||
|
||||
int m_nArgc;
|
||||
int m_nArgv0Size;
|
||||
char m_pArgSBuffer[ COMMAND_MAX_LENGTH ];
|
||||
char m_pArgvBuffer[ COMMAND_MAX_LENGTH ];
|
||||
const char* m_ppArgv[ COMMAND_MAX_ARGC ];
|
||||
};
|
||||
|
||||
inline int CCommand::MaxCommandLength()
|
||||
{
|
||||
return COMMAND_MAX_LENGTH - 1;
|
||||
}
|
||||
|
||||
inline int CCommand::ArgC() const
|
||||
{
|
||||
return m_nArgc;
|
||||
}
|
||||
|
||||
inline const char **CCommand::ArgV() const
|
||||
{
|
||||
return m_nArgc ? (const char**)m_ppArgv : NULL;
|
||||
}
|
||||
|
||||
inline const char *CCommand::ArgS() const
|
||||
{
|
||||
return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : "";
|
||||
}
|
||||
|
||||
inline const char *CCommand::GetCommandString() const
|
||||
{
|
||||
return m_nArgc ? m_pArgSBuffer : "";
|
||||
}
|
||||
|
||||
inline const char *CCommand::Arg( int nIndex ) const
|
||||
{
|
||||
// FIXME: Many command handlers appear to not be particularly careful
|
||||
// about checking for valid argc range. For now, we're going to
|
||||
// do the extra check and return an empty string if it's out of range
|
||||
if ( nIndex < 0 || nIndex >= m_nArgc )
|
||||
return "";
|
||||
return m_ppArgv[nIndex];
|
||||
}
|
||||
|
||||
inline const char *CCommand::operator[]( int nIndex ) const
|
||||
{
|
||||
return Arg( nIndex );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The console invoked command
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConCommand : public ConCommandBase
|
||||
{
|
||||
friend class CCvar;
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConCommand( const char *pName, FnCommandCallbackV1_t callback,
|
||||
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
ConCommand( const char *pName, FnCommandCallback_t callback,
|
||||
const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 );
|
||||
ConCommand( const char *pName, ICommandCallback *pCallback,
|
||||
const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 );
|
||||
|
||||
virtual ~ConCommand( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
|
||||
virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands );
|
||||
|
||||
virtual bool CanAutoComplete( void );
|
||||
|
||||
// Invoke the function
|
||||
virtual void Dispatch( const CCommand &command );
|
||||
|
||||
private:
|
||||
// NOTE: To maintain backward compat, we have to be very careful:
|
||||
// All public virtual methods must appear in the same order always
|
||||
// since engine code will be calling into this code, which *does not match*
|
||||
// in the mod code; it's using slightly different, but compatible versions
|
||||
// of this class. Also: Be very careful about adding new fields to this class.
|
||||
// Those fields will not exist in the version of this class that is instanced
|
||||
// in mod code.
|
||||
|
||||
// Call this function when executing the command
|
||||
union
|
||||
{
|
||||
FnCommandCallbackV1_t m_fnCommandCallbackV1;
|
||||
FnCommandCallback_t m_fnCommandCallback;
|
||||
ICommandCallback *m_pCommandCallback;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
FnCommandCompletionCallback m_fnCompletionCallback;
|
||||
ICommandCompletionCallback *m_pCommandCompletionCallback;
|
||||
};
|
||||
|
||||
bool m_bHasCompletionCallback : 1;
|
||||
bool m_bUsingNewCommandCallback : 1;
|
||||
bool m_bUsingCommandCallbackInterface : 1;
|
||||
public:
|
||||
inline FnCommandCallback_t GetCallback() const
|
||||
{
|
||||
return m_fnCommandCallback;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A console variable
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVar : public ConCommandBase, public IConVar
|
||||
{
|
||||
friend class CCvar;
|
||||
friend class ConVarRef;
|
||||
|
||||
public:
|
||||
typedef ConCommandBase BaseClass;
|
||||
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags = 0);
|
||||
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, FnChangeCallback_t callback );
|
||||
ConVar( const char *pName, const char *pDefaultValue, int flags,
|
||||
const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax,
|
||||
FnChangeCallback_t callback );
|
||||
|
||||
virtual ~ConVar( void );
|
||||
|
||||
virtual bool IsCommand( void ) const;
|
||||
virtual bool IsFlagSet( int flag ) const;
|
||||
virtual void AddFlags( int flags );
|
||||
virtual int GetFlags( void ) const;
|
||||
virtual const char *GetName( void ) const;
|
||||
virtual const char* GetHelpText( void ) const;
|
||||
virtual bool IsRegistered( void ) const;
|
||||
|
||||
// Install a change callback (there shouldn't already be one....)
|
||||
void InstallChangeCallback( FnChangeCallback_t callback );
|
||||
|
||||
// Retrieve value
|
||||
FORCEINLINE_CVAR float GetFloat( void ) const;
|
||||
FORCEINLINE_CVAR int GetInt( void ) const;
|
||||
FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); }
|
||||
FORCEINLINE_CVAR char const *GetString( void ) const;
|
||||
|
||||
// Used internally by OneTimeInit to initialize.
|
||||
virtual void Init();
|
||||
|
||||
virtual const char *GetBaseName( void ) const;
|
||||
virtual int GetSplitScreenPlayerSlot ( void ) const;
|
||||
|
||||
// Any function that allocates/frees memory needs to be virtual or else you'll have crashes
|
||||
// from alloc/free across dll/exe boundaries.
|
||||
|
||||
// These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue).
|
||||
virtual void SetValue( const char *value );
|
||||
virtual void SetValue( float value );
|
||||
virtual void SetValue( int value );
|
||||
#if SOURCE_ENGINE >= SE_NUCLEARDAWN
|
||||
virtual void SetValue( Color value );
|
||||
#endif
|
||||
|
||||
// Reset to default value
|
||||
void Revert( void );
|
||||
|
||||
// True if it has a min/max setting
|
||||
bool GetMin( float& minVal ) const;
|
||||
bool GetMax( float& maxVal ) const;
|
||||
const char *GetDefault( void ) const;
|
||||
|
||||
private:
|
||||
// Called by CCvar when the value of a var is changing.
|
||||
virtual void InternalSetValue(const char *value);
|
||||
// For CVARs marked FCVAR_NEVER_AS_STRING
|
||||
virtual void InternalSetFloatValue( float fNewValue );
|
||||
virtual void InternalSetIntValue( int nValue );
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD2
|
||||
virtual void InternalSetColorValue( Color value );
|
||||
#endif
|
||||
|
||||
virtual bool ClampValue( float& value );
|
||||
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
|
||||
|
||||
virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0,
|
||||
const char *pHelpString = 0, bool bMin = false, float fMin = 0.0,
|
||||
bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 );
|
||||
|
||||
private:
|
||||
|
||||
// This either points to "this" or it points to the original declaration of a ConVar.
|
||||
// This allows ConVars to exist in separate modules, and they all use the first one to be declared.
|
||||
// m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar).
|
||||
ConVar *m_pParent;
|
||||
|
||||
// Static data
|
||||
const char *m_pszDefaultValue;
|
||||
|
||||
// Value
|
||||
// Dynamically allocated
|
||||
char *m_pszString;
|
||||
int m_StringLength;
|
||||
|
||||
// Values
|
||||
float m_fValue;
|
||||
int m_nValue;
|
||||
|
||||
// Min/Max values
|
||||
bool m_bHasMin;
|
||||
float m_fMinVal;
|
||||
bool m_bHasMax;
|
||||
float m_fMaxVal;
|
||||
|
||||
// Call this function when ConVar changes
|
||||
FnChangeCallback_t m_fnChangeCallback;
|
||||
public:
|
||||
inline FnChangeCallback_t GetCallback() const
|
||||
{
|
||||
return m_fnChangeCallback;
|
||||
}
|
||||
inline void SetMin(bool set, float min=0.0)
|
||||
{
|
||||
m_bHasMin = set;
|
||||
m_fMinVal = min;
|
||||
}
|
||||
inline void SetMax(bool set, float max=0.0)
|
||||
{
|
||||
m_bHasMax = set;
|
||||
m_fMaxVal = max;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVar::GetFloat( void ) const
|
||||
{
|
||||
return m_pParent->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVar::GetInt( void ) const
|
||||
{
|
||||
return m_pParent->m_nValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
// Output : const char *
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR const char *ConVar::GetString( void ) const
|
||||
{
|
||||
if ( m_nFlags & FCVAR_NEVER_AS_STRING )
|
||||
return "FCVAR_NEVER_AS_STRING";
|
||||
|
||||
return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : "";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to read/write convars that already exist (replaces the FindVar method)
|
||||
//-----------------------------------------------------------------------------
|
||||
class ConVarRef
|
||||
{
|
||||
public:
|
||||
ConVarRef( const char *pName );
|
||||
ConVarRef( const char *pName, bool bIgnoreMissing );
|
||||
ConVarRef( IConVar *pConVar );
|
||||
|
||||
void Init( const char *pName, bool bIgnoreMissing );
|
||||
bool IsValid() const;
|
||||
bool IsFlagSet( int nFlags ) const;
|
||||
IConVar *GetLinkedConVar();
|
||||
|
||||
// Get/Set value
|
||||
float GetFloat( void ) const;
|
||||
int GetInt( void ) const;
|
||||
bool GetBool() const { return !!GetInt(); }
|
||||
const char *GetString( void ) const;
|
||||
|
||||
void SetValue( const char *pValue );
|
||||
void SetValue( float flValue );
|
||||
void SetValue( int nValue );
|
||||
void SetValue( bool bValue );
|
||||
|
||||
const char *GetName() const;
|
||||
|
||||
const char *GetDefault() const;
|
||||
|
||||
private:
|
||||
// High-speed method to read convar data
|
||||
IConVar *m_pConVar;
|
||||
ConVar *m_pConVarState;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Did we find an existing convar of that name?
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const
|
||||
{
|
||||
return ( m_pConVar->IsFlagSet( nFlags ) != 0 );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar()
|
||||
{
|
||||
return m_pConVar;
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetName() const
|
||||
{
|
||||
return m_pConVar->GetName();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a float
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const
|
||||
{
|
||||
return m_pConVarState->m_fValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as an int
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const
|
||||
{
|
||||
return m_pConVarState->m_nValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const
|
||||
{
|
||||
Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) );
|
||||
return m_pConVarState->m_pszString;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue )
|
||||
{
|
||||
m_pConVar->SetValue( pValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue )
|
||||
{
|
||||
m_pConVar->SetValue( flValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue )
|
||||
{
|
||||
m_pConVar->SetValue( nValue );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue )
|
||||
{
|
||||
m_pConVar->SetValue( bValue ? 1 : 0 );
|
||||
}
|
||||
|
||||
FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const
|
||||
{
|
||||
return m_pConVarState->m_pszDefaultValue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called by the framework to register ConCommands with the ICVar
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL );
|
||||
void ConVar_Unregister( );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConVar_PrintFlags( const ConCommandBase *var );
|
||||
void ConVar_PrintDescription( const ConCommandBase *pVar );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility class to quickly allow ConCommands to call member methods
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable : 4355 )
|
||||
#endif
|
||||
|
||||
template< class T >
|
||||
class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback
|
||||
{
|
||||
typedef ConCommand BaseClass;
|
||||
typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command );
|
||||
typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands );
|
||||
|
||||
public:
|
||||
CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0,
|
||||
int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) :
|
||||
BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
m_Func = callback;
|
||||
m_CompletionFunc = completionFunc;
|
||||
}
|
||||
|
||||
~CConCommandMemberAccessor()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void SetOwner( T* pOwner )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
}
|
||||
|
||||
virtual void CommandCallback( const CCommand &command )
|
||||
{
|
||||
Assert( m_pOwner && m_Func );
|
||||
(m_pOwner->*m_Func)( command );
|
||||
}
|
||||
|
||||
virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands )
|
||||
{
|
||||
Assert( m_pOwner && m_CompletionFunc );
|
||||
return (m_pOwner->*m_CompletionFunc)( pPartial, commands );
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_pOwner;
|
||||
FnMemberCommandCallback_t m_Func;
|
||||
FnMemberCommandCompletionCallback_t m_CompletionFunc;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning ( default : 4355 )
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Utility macros to quicky generate a simple console command
|
||||
//-----------------------------------------------------------------------------
|
||||
#define CON_COMMAND( name, description ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_F( name, description, flags ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description, flags ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \
|
||||
static void name( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, name, description, flags, completion ); \
|
||||
static void name( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_EXTERN( name, _funcname, description ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, _funcname, description ); \
|
||||
void _funcname( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
static ConCommand name##_command( #name, _funcname, description, flags ); \
|
||||
void _funcname( const CCommand &args )
|
||||
|
||||
#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \
|
||||
void _funcname( const CCommand &args ); \
|
||||
friend class CCommandMemberInitializer_##_funcname; \
|
||||
class CCommandMemberInitializer_##_funcname \
|
||||
{ \
|
||||
public: \
|
||||
CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \
|
||||
{ \
|
||||
m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \
|
||||
} \
|
||||
private: \
|
||||
CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \
|
||||
}; \
|
||||
\
|
||||
CCommandMemberInitializer_##_funcname m_##_funcname##_register; \
|
||||
|
||||
|
||||
#endif // CONVAR_H
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FORCEINLINE_CVAR FORCEINLINE
|
||||
#elif _LINUX
|
||||
#elif defined _LINUX || defined __APPLE__
|
||||
#define FORCEINLINE_CVAR inline
|
||||
#else
|
||||
#error "implement me"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+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 <IThreader.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;
|
||||
|
||||
+17
-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,22 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
|
||||
#define _INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
|
||||
|
||||
#include <ISourceMod.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
struct FrameAction
|
||||
{
|
||||
FrameAction(FRAMEACTION a, void *d) : data(d), action(a)
|
||||
{
|
||||
}
|
||||
void *data;
|
||||
FRAMEACTION action;
|
||||
};
|
||||
|
||||
extern bool g_PendingInternalPush;
|
||||
|
||||
void AddFrameAction(const FrameAction & action);
|
||||
void RunFrameHooks(bool simulating);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_FRAME_HOOKS_H_
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# vim: set ts=2 sw=2 tw=99 noet ft=python:
|
||||
import os
|
||||
|
||||
compiler = SM.DefaultCompiler()
|
||||
base = AMBuild.sourceFolder
|
||||
compiler['CXXINCLUDES'].append(os.path.join(SM.mmsPath, 'core', 'sourcehook'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(base, 'core', 'logic'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(base, 'public'))
|
||||
compiler['CXXINCLUDES'].append(os.path.join(base, 'public', 'sourcepawn'))
|
||||
compiler['CDEFINES'].append('SM_DEFAULT_THREADER')
|
||||
compiler['CDEFINES'].append('SM_LOGIC')
|
||||
|
||||
if AMBuild.target['platform'] == 'linux':
|
||||
compiler['POSTLINKFLAGS'].append('-lpthread')
|
||||
if AMBuild.target['platform'] == 'darwin':
|
||||
compiler['CFLAGS'].extend(['-Wno-deprecated-declarations'])
|
||||
compiler['POSTLINKFLAGS'].extend(['-framework', 'CoreServices'])
|
||||
|
||||
extension = AMBuild.AddJob('sourcemod.logic')
|
||||
binary = Cpp.LibraryBuilder('sourcemod.logic', AMBuild, extension, compiler)
|
||||
files = [
|
||||
'common_logic.cpp',
|
||||
'smn_adt_array.cpp',
|
||||
'smn_sorting.cpp',
|
||||
'smn_maplists.cpp',
|
||||
'smn_adt_stack.cpp',
|
||||
'thread/ThreadWorker.cpp',
|
||||
'thread/BaseWorker.cpp',
|
||||
'ThreadSupport.cpp',
|
||||
'smn_float.cpp',
|
||||
'TextParsers.cpp',
|
||||
'smn_textparse.cpp',
|
||||
'smn_adt_trie.cpp',
|
||||
'Profiler.cpp',
|
||||
'smn_functions.cpp',
|
||||
'smn_timers.cpp',
|
||||
'smn_players.cpp',
|
||||
'MemoryUtils.cpp',
|
||||
'smn_admin.cpp',
|
||||
'smn_banning.cpp',
|
||||
'stringutil.cpp',
|
||||
'Translator.cpp',
|
||||
'PhraseCollection.cpp',
|
||||
'smn_lang.cpp',
|
||||
'smn_string.cpp',
|
||||
'smn_handles.cpp',
|
||||
'smn_datapacks.cpp',
|
||||
'smn_gameconfigs.cpp',
|
||||
'GameConfigs.cpp',
|
||||
'sm_crc32.cpp',
|
||||
'smn_profiler.cpp'
|
||||
]
|
||||
if AMBuild.target['platform'] == 'windows':
|
||||
files.append('thread/WinThreads.cpp')
|
||||
else:
|
||||
files.append('thread/PosixThreads.cpp')
|
||||
binary.AddSourceFiles('core/logic', files)
|
||||
SM.AutoVersion('core/logic', binary)
|
||||
SM.ExtractDebugInfo(extension, binary)
|
||||
binary.SendToJob()
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_
|
||||
#define _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <IHandleSys.h>
|
||||
|
||||
class AutoHandleRooter
|
||||
{
|
||||
public:
|
||||
AutoHandleRooter(Handle_t hndl)
|
||||
{
|
||||
if (hndl != BAD_HANDLE)
|
||||
this->hndl = handlesys->FastCloneHandle(hndl);
|
||||
else
|
||||
this->hndl = BAD_HANDLE;
|
||||
}
|
||||
|
||||
~AutoHandleRooter()
|
||||
{
|
||||
if (hndl != BAD_HANDLE)
|
||||
{
|
||||
HandleSecurity sec(g_pCoreIdent, g_pCoreIdent);
|
||||
handlesys->FreeHandle(hndl, &sec);
|
||||
}
|
||||
}
|
||||
|
||||
Handle_t getHandle()
|
||||
{
|
||||
return hndl;
|
||||
}
|
||||
private:
|
||||
Handle_t hndl;
|
||||
};
|
||||
|
||||
class AutoHandleCloner
|
||||
{
|
||||
Handle_t original;
|
||||
HandleSecurity sec;
|
||||
AutoHandleRooter ahr;
|
||||
public:
|
||||
AutoHandleCloner(Handle_t original, HandleSecurity sec)
|
||||
: original(original), sec(sec), ahr(original)
|
||||
{
|
||||
}
|
||||
|
||||
~AutoHandleCloner()
|
||||
{
|
||||
if (original != BAD_HANDLE)
|
||||
{
|
||||
handlesys->FreeHandle(original, &sec);
|
||||
}
|
||||
}
|
||||
|
||||
Handle_t getClone()
|
||||
{
|
||||
return ahr.getHandle();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_AUTO_HANDLE_ROOTER_H_ */
|
||||
|
||||
@@ -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,10 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#ifndef _INCLUDE_SOURCEMOD_CELLARRAY_H_
|
||||
#define _INCLUDE_SOURCEMOD_CELLARRAY_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern HandleType_t htCellArray;
|
||||
@@ -40,14 +43,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 +64,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 +100,7 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void remove(size_t index)
|
||||
{
|
||||
/* If we're at the end, take the easy way out */
|
||||
@@ -107,6 +118,7 @@ public:
|
||||
|
||||
m_Size--;
|
||||
}
|
||||
|
||||
cell_t *insert_at(size_t index)
|
||||
{
|
||||
/* Make sure it'll fit */
|
||||
@@ -124,6 +136,7 @@ public:
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
bool resize(size_t count)
|
||||
{
|
||||
if (count <= m_Size)
|
||||
@@ -132,7 +145,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!GrowIfNeeded(count - m_Size))
|
||||
if (!GrowIfNeeded(count - m_Size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -194,3 +207,6 @@ private:
|
||||
size_t m_AllocSize;
|
||||
size_t m_Size;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE_SOURCEMOD_CELLARRAY_H_ */
|
||||
|
||||
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