Compare commits
1952
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34b5caf464 | ||
|
|
ecae5b0479 | ||
|
|
1ab9dc141f | ||
|
|
6a8529460f | ||
|
|
c63e2b318f | ||
|
|
c4a3c421ff | ||
|
|
cb3d03d699 | ||
|
|
faad5ff3ea | ||
|
|
cc02c00fd4 | ||
|
|
2bedba3f2c | ||
|
|
369f96ddfb | ||
|
|
ab1fb8309e | ||
|
|
5e9f27fe6d | ||
|
|
b8e4510f7e | ||
|
|
0d69ce8b9a | ||
|
|
a66f93b64b | ||
|
|
702ac32bc0 | ||
|
|
97c9cc9b23 | ||
|
|
f38f097396 | ||
|
|
b10edfa86f | ||
|
|
cf92376962 | ||
|
|
92d8d96cd9 | ||
|
|
ce7a98dffa | ||
|
|
f3af8539d2 | ||
|
|
35e12b16ba | ||
|
|
6e9c95034e | ||
|
|
34968def58 | ||
|
|
4800732c00 | ||
|
|
7d7bf38941 | ||
|
|
5c13a0bc69 | ||
|
|
3e63e611c2 | ||
|
|
c3598d8e71 | ||
|
|
f57097651b | ||
|
|
a5450aad18 | ||
|
|
0a4a06d9e1 | ||
|
|
dd51da519d | ||
|
|
c79f52e2c9 | ||
|
|
c4279da3b2 | ||
|
|
3923177037 | ||
|
|
80a0e24b66 | ||
|
|
75d770ba0f | ||
|
|
d9e6daa006 | ||
|
|
f08b60bc98 | ||
|
|
4d98fc2a3d | ||
|
|
0b4ec459d3 | ||
|
|
65269551f9 | ||
|
|
47b0022331 | ||
|
|
7df2b28fe0 | ||
|
|
7df1069613 | ||
|
|
7585acaeef | ||
|
|
dfcf953131 | ||
|
|
cb31a65807 | ||
|
|
6123c5e013 | ||
|
|
cb73b935ec | ||
|
|
76e8e7e50c | ||
|
|
40d049e1f6 | ||
|
|
48012ccf08 | ||
|
|
80ceb149b0 | ||
|
|
1ef60a13d0 | ||
|
|
e8e40d126e | ||
|
|
c7033827f5 | ||
|
|
ff27214615 | ||
|
|
7b45e963d5 | ||
|
|
96965ef7cd | ||
|
|
8f7ce184fb | ||
|
|
4bed0a2893 | ||
|
|
6ab2e23d9d | ||
|
|
dd27de8d85 | ||
|
|
8c79a6df33 | ||
|
|
e8111f3c0a | ||
|
|
a038181193 | ||
|
|
52fe916311 | ||
|
|
d01d7b1879 | ||
|
|
d8406a3efc | ||
|
|
d74204aded | ||
|
|
77be859667 | ||
|
|
71193c67b2 | ||
|
|
cc1493aa66 | ||
|
|
43946e6b6f | ||
|
|
5776909b13 | ||
|
|
048c227fcc | ||
|
|
95ab81f0db | ||
|
|
2fb01e412e | ||
|
|
6e9b4bf276 | ||
|
|
b344e81816 | ||
|
|
fec133bee6 | ||
|
|
594cc249ef | ||
|
|
0967035dd0 | ||
|
|
7e93cf8f6b | ||
|
|
7f20a7b6bb | ||
|
|
a9de6ed52c | ||
|
|
f0f50aa7bb | ||
|
|
36fab677a0 | ||
|
|
6c0d2a3743 | ||
|
|
e71eb5f704 | ||
|
|
4532b8a38d | ||
|
|
a089235b21 | ||
|
|
9f9f2baae2 | ||
|
|
49a643f411 | ||
|
|
8d7e8b2a85 | ||
|
|
848bc927a0 | ||
|
|
18d0f2a140 | ||
|
|
91a796b24d | ||
|
|
7e7544e036 | ||
|
|
9d676ed440 | ||
|
|
bad5252ee3 | ||
|
|
a2951b9ea8 | ||
|
|
f98cd68341 | ||
|
|
45b9573348 | ||
|
|
7553106eee | ||
|
|
5cf73385c5 | ||
|
|
7a96467045 | ||
|
|
86c1660ee9 | ||
|
|
8e4836f83a | ||
|
|
00c09584c7 | ||
|
|
7677e8af79 | ||
|
|
69cb941fa4 | ||
|
|
17a7d4802d | ||
|
|
0b2610e3b3 | ||
|
|
51a02652d8 | ||
|
|
e7870da5ff | ||
|
|
a697e81427 | ||
|
|
5f8288dc70 | ||
|
|
feb5050df1 | ||
|
|
0d79b7a542 | ||
|
|
e4328f9211 | ||
|
|
70518a8e49 | ||
|
|
6ac897f9f3 | ||
|
|
ec9791b183 | ||
|
|
d5c267b291 | ||
|
|
3de533a73e | ||
|
|
f1f135adb6 | ||
|
|
91077fdc91 | ||
|
|
f250461648 | ||
|
|
6a98e40643 | ||
|
|
36c342fc7b | ||
|
|
39ff3f9993 | ||
|
|
7026e68b06 | ||
|
|
25ea80890d | ||
|
|
2379c76b03 | ||
|
|
e6d8416f0e | ||
|
|
cb16a78681 | ||
|
|
2930fb1963 | ||
|
|
d7b49f7706 | ||
|
|
695fc802a9 | ||
|
|
c37dbe131e | ||
|
|
88af898285 | ||
|
|
cd106a7eb6 | ||
|
|
975fc93e1f | ||
|
|
6c37a5d9f3 | ||
|
|
7b59b7f384 | ||
|
|
0ca218931a | ||
|
|
1d9f769a42 | ||
|
|
083edcedc7 | ||
|
|
fb5c3c86da | ||
|
|
3c89f2b1c2 | ||
|
|
4c7cf6ce06 | ||
|
|
195104487e | ||
|
|
39993c7019 | ||
|
|
897aa42135 | ||
|
|
abdf7d5b07 | ||
|
|
9f8f879590 | ||
|
|
db14d2d00a | ||
|
|
a0f3410f3b | ||
|
|
4159e1a177 | ||
|
|
4f7b0ff487 | ||
|
|
891ebe4480 | ||
|
|
859be35b34 | ||
|
|
88c452581b | ||
|
|
b0ccc87638 | ||
|
|
1e6843f8db | ||
|
|
76a589f689 | ||
|
|
e7621ad8a7 | ||
|
|
c4232510a1 | ||
|
|
e2878d3df8 | ||
|
|
5cb10441d7 | ||
|
|
6ee42dc7fe | ||
|
|
e0f6544c86 | ||
|
|
ab68e70998 | ||
|
|
8be1feadc1 | ||
|
|
beb3f8c1d4 | ||
|
|
35784c018d | ||
|
|
dc4c3f2f1a | ||
|
|
9ff6cdef8c | ||
|
|
dbc881143b | ||
|
|
556d5e0949 | ||
|
|
6456b937be | ||
|
|
05d8622ea9 | ||
|
|
f1387c892e | ||
|
|
cae5d48d31 | ||
|
|
d83d72fd88 | ||
|
|
ff42e854bb | ||
|
|
a462feee61 | ||
|
|
5eef4bccd3 | ||
|
|
609fa50763 | ||
|
|
7868767dde | ||
|
|
6ac013376f | ||
|
|
cfde247ef7 | ||
|
|
ac11eb8910 | ||
|
|
cd0d31805c | ||
|
|
cf617a4d20 | ||
|
|
84de0f6b85 | ||
|
|
914a0a7fc1 | ||
|
|
f82420b601 | ||
|
|
5193b70ada | ||
|
|
4b2b50a3df | ||
|
|
9ed3a55ade | ||
|
|
53a8d5ac30 | ||
|
|
b4144d2cff | ||
|
|
5bbcc7322c | ||
|
|
3f81397a84 | ||
|
|
c744b39c6d | ||
|
|
1a97d37215 | ||
|
|
2bc7e4736f | ||
|
|
5681b99fd8 | ||
|
|
9a5efc2de2 | ||
|
|
692af52ea7 | ||
|
|
ee51295d22 | ||
|
|
3c7a08afc2 | ||
|
|
ed9ca9e943 | ||
|
|
fbaa3a804f | ||
|
|
9f0308530c | ||
|
|
2e89d91a86 | ||
|
|
e20e4677df | ||
|
|
97c581f72c | ||
|
|
c079a3b58a | ||
|
|
c6de58aa05 | ||
|
|
4fd0e3acd8 | ||
|
|
3145daa46a | ||
|
|
3c52840dd8 | ||
|
|
8ed66980c0 | ||
|
|
365da7fef6 | ||
|
|
9af5023a8f | ||
|
|
878201c631 | ||
|
|
e65d11f4de | ||
|
|
1a89edec47 | ||
|
|
1143b3f56f | ||
|
|
1b4017c6b7 | ||
|
|
15224c6df5 | ||
|
|
e831757313 | ||
|
|
a47388ff76 | ||
|
|
71f4f36f8c | ||
|
|
a4e387331a | ||
|
|
defdc617b3 | ||
|
|
61b6a32631 | ||
|
|
1fdf1c0264 | ||
|
|
32f019c70c | ||
|
|
9c62e94239 | ||
|
|
b4ff034ac2 | ||
|
|
6b27a7fe46 | ||
|
|
adc9569e23 | ||
|
|
4cd6c37ab5 | ||
|
|
f15234e4f8 | ||
|
|
29ff05bd62 | ||
|
|
e9b4a6e96c | ||
|
|
530078b3ae | ||
|
|
5149205109 | ||
|
|
55b77a1925 | ||
|
|
bc5691c4b6 | ||
|
|
0513f93f9d | ||
|
|
b5decd8a50 | ||
|
|
b1901da79f | ||
|
|
6f47b1a89d | ||
|
|
cec703a059 | ||
|
|
217eb68455 | ||
|
|
f0d6fd1912 | ||
|
|
b0061ece62 | ||
|
|
0b6603ab2b | ||
|
|
09546b0d2a | ||
|
|
799ee7b9c6 | ||
|
|
b0b28b7a6e | ||
|
|
bbe7a9dd6a | ||
|
|
ecec7dbef3 | ||
|
|
d66a7b0ee0 | ||
|
|
61c4d2b805 | ||
|
|
73d8072693 | ||
|
|
c64edf31fc | ||
|
|
cb32e3d8f9 | ||
|
|
e69e9eddc7 | ||
|
|
aa85a1866e | ||
|
|
623925a1cf | ||
|
|
b6792a2c8c | ||
|
|
7248ad9aba | ||
|
|
d44b8aa853 | ||
|
|
f8d6ecbc02 | ||
|
|
bd76558b94 | ||
|
|
63451b7b6b | ||
|
|
edc42800ba | ||
|
|
0608d47219 | ||
|
|
5efb5068cd | ||
|
|
14f31006c1 | ||
|
|
90c8440f17 | ||
|
|
c3e9d7de41 | ||
|
|
9badb14c3a | ||
|
|
655994cd09 | ||
|
|
217ca928d5 | ||
|
|
fdae6cf1b0 | ||
|
|
e708cdf28c | ||
|
|
2d616a5995 | ||
|
|
563dd617af | ||
|
|
2c399ec441 | ||
|
|
57067d38fe | ||
|
|
2f6b64e92e | ||
|
|
00b06313c9 | ||
|
|
2b015a1d5b | ||
|
|
010220ea25 | ||
|
|
95a56972a1 | ||
|
|
a8ff00bc34 | ||
|
|
9abac06e85 | ||
|
|
ee595978f8 | ||
|
|
49d769282b | ||
|
|
451c90b932 | ||
|
|
9215ddcf8a | ||
|
|
fb0fd0c6d2 | ||
|
|
9c1902b0e3 | ||
|
|
cf8d05ae98 | ||
|
|
8c513faad5 | ||
|
|
6e8d9ff788 | ||
|
|
0e6cbf989e | ||
|
|
d6bbb765c1 | ||
|
|
b411b60ed7 | ||
|
|
692cafa784 | ||
|
|
6600a8c60b | ||
|
|
cebede3a79 | ||
|
|
db756f482b | ||
|
|
cd349946e8 | ||
|
|
b4156a19c3 | ||
|
|
b3e2647dc4 | ||
|
|
e9f0d1f513 | ||
|
|
21cae97820 | ||
|
|
74989d925e | ||
|
|
b402d77ff9 | ||
|
|
8431925577 | ||
|
|
22e8b53029 | ||
|
|
aa75fd24d8 | ||
|
|
f8f4cebe9e | ||
|
|
7d7db6d5bb | ||
|
|
38bbb8580f | ||
|
|
8a7af5ba0d | ||
|
|
a98d277cf3 | ||
|
|
3c6dd2cb79 | ||
|
|
5b96047ce8 | ||
|
|
692f597808 | ||
|
|
10f878d8c7 | ||
|
|
8987a34078 | ||
|
|
ba99d0154b | ||
|
|
977bf4d583 | ||
|
|
06efa7c52b | ||
|
|
84d58ff421 | ||
|
|
c679b97e5f | ||
|
|
b99ab3d1d2 | ||
|
|
ce6b993954 | ||
|
|
e95c2ba0b9 | ||
|
|
ab6971656b | ||
|
|
01fc010719 | ||
|
|
37c84448a9 | ||
|
|
d259be7b1f | ||
|
|
9be71eea2f | ||
|
|
a4d841655b | ||
|
|
162c69bfda | ||
|
|
c5f496670d | ||
|
|
53a0acc2e3 | ||
|
|
75d950e4b0 | ||
|
|
5abd9edf62 | ||
|
|
e00e879af5 | ||
|
|
8476832dc2 | ||
|
|
0ab8f4a1bd | ||
|
|
79f825cc44 | ||
|
|
f351e20de3 | ||
|
|
925d514224 | ||
|
|
36cc7610a1 | ||
|
|
06d2017a95 | ||
|
|
0da68844a5 | ||
|
|
1f6733562d | ||
|
|
4093fa0588 | ||
|
|
39c82d6ea0 | ||
|
|
03c7a9d5f3 | ||
|
|
65b32b8ced | ||
|
|
41f74d1a5c | ||
|
|
13e65a73a4 | ||
|
|
dc1234ddfb | ||
|
|
5d8f5c890d | ||
|
|
e2eabc7a96 | ||
|
|
a33977c71c | ||
|
|
9de1a1ddfa | ||
|
|
7dcdaf0319 | ||
|
|
b3d64d1121 | ||
|
|
52ff6fd5f8 | ||
|
|
af7b8cd9a3 | ||
|
|
b0ee5ce485 | ||
|
|
4a65e38d54 | ||
|
|
097d2d902c | ||
|
|
9d15512f3b | ||
|
|
3bbb48ce9e | ||
|
|
a709307fab | ||
|
|
06c73813ca | ||
|
|
5acc7209b2 | ||
|
|
9fe11f9c36 | ||
|
|
fb734e4124 | ||
|
|
7c1fb6e5b9 | ||
|
|
40d03f78cf | ||
|
|
7f8c6a9fd6 | ||
|
|
832187be31 | ||
|
|
a2f8f1e70d | ||
|
|
3f3343e945 | ||
|
|
4e077402e5 | ||
|
|
ad5740f8a7 | ||
|
|
310f77d96a | ||
|
|
121c3973d6 | ||
|
|
17212616d7 | ||
|
|
876ba3bef5 | ||
|
|
9a0918a354 | ||
|
|
cfad3b26ca | ||
|
|
a55b000273 | ||
|
|
b69b0de234 | ||
|
|
6d320163a1 | ||
|
|
ae21f29ad9 | ||
|
|
f82224eba0 | ||
|
|
c2cfe60102 | ||
|
|
75e622e879 | ||
|
|
9c19f6efb7 | ||
|
|
58995fc829 | ||
|
|
54ed1807c0 | ||
|
|
e1a820dcf9 | ||
|
|
b749bbf42b | ||
|
|
bdbc3c3b58 | ||
|
|
b83810b986 | ||
|
|
462b543816 | ||
|
|
29ddb9f4d9 | ||
|
|
398b05afed | ||
|
|
f0e4fe66ba | ||
|
|
fa057e76f3 | ||
|
|
47906fbcb7 | ||
|
|
5df8c9290f | ||
|
|
1938be9e28 | ||
|
|
839e292819 | ||
|
|
056f64ad40 | ||
|
|
c13a0a2e7a | ||
|
|
1cf12085fc | ||
|
|
d9946b49c4 | ||
|
|
c5ca58a95b | ||
|
|
591255c793 | ||
|
|
2ea5e6d090 | ||
|
|
e01fc5e697 | ||
|
|
0775976165 | ||
|
|
d2f719171d | ||
|
|
c9c147a814 | ||
|
|
31aa230cba | ||
|
|
880be015ae | ||
|
|
96d6cf8def | ||
|
|
66dd3f08b1 | ||
|
|
2175e561cc | ||
|
|
35191745ca | ||
|
|
661af1c5e2 | ||
|
|
bd1ee1f805 | ||
|
|
9e926bdb1d | ||
|
|
edab49c4ef | ||
|
|
bbbbc8b311 | ||
|
|
d5c1111fda | ||
|
|
26a76365f4 | ||
|
|
3a20ae16e1 | ||
|
|
e0746e1ab8 | ||
|
|
24c623c2fa | ||
|
|
5e1d207eae | ||
|
|
3e15966c3e | ||
|
|
ff54fb431f | ||
|
|
1ba6b2653a | ||
|
|
1d1b5d1c6d | ||
|
|
9027d15211 | ||
|
|
5bde264c43 | ||
|
|
67a2fe3751 | ||
|
|
e3cb33bbda | ||
|
|
3174fb7d19 | ||
|
|
1836f69cf0 | ||
|
|
985b7831cf | ||
|
|
fbc851ceae | ||
|
|
55bf8ec095 | ||
|
|
39e955c412 | ||
|
|
f8c065c182 | ||
|
|
ed6fe7519a | ||
|
|
d808d6d8a5 | ||
|
|
b471109c08 | ||
|
|
9978b07956 | ||
|
|
1b3ff094fa | ||
|
|
75ce4c395a | ||
|
|
427e93c573 | ||
|
|
46327563f2 | ||
|
|
3308f0644c | ||
|
|
cb128162e6 | ||
|
|
f9f4c7dcd6 | ||
|
|
2dae228f10 | ||
|
|
b917c540aa | ||
|
|
67ce8aff61 | ||
|
|
ba927964c8 | ||
|
|
435f2b8e39 | ||
|
|
a25f9010cc | ||
|
|
4500964394 | ||
|
|
3da646f913 | ||
|
|
140436c2cb | ||
|
|
0e677fb3a2 | ||
|
|
4dc5d0e12f | ||
|
|
a260e92266 | ||
|
|
9a86be24a7 | ||
|
|
e620d973f4 | ||
|
|
7ad43a5b11 | ||
|
|
124ede82b3 | ||
|
|
da9debda67 | ||
|
|
1c40d77b14 | ||
|
|
f1b0c29815 | ||
|
|
b261dde858 | ||
|
|
88fdec6dd5 | ||
|
|
e8ce238eb7 | ||
|
|
404b1c5ed0 | ||
|
|
dde1deb6bc | ||
|
|
c80e0a964f | ||
|
|
d9f23a8af2 | ||
|
|
fd9e657196 | ||
|
|
693c4024d6 | ||
|
|
d7eee4191f | ||
|
|
b8c61f89fa | ||
|
|
d05feabcd6 | ||
|
|
c30b7c111f | ||
|
|
f6255c72d1 | ||
|
|
cd68567ce3 | ||
|
|
e6f39eb9b6 | ||
|
|
2c1a398292 | ||
|
|
0f52f6931b | ||
|
|
51dc097266 | ||
|
|
8e99b342a4 | ||
|
|
bc51c3e5b1 | ||
|
|
d5177fdc74 | ||
|
|
80eba57e6b | ||
|
|
3985dd639a | ||
|
|
3000445af9 | ||
|
|
0235d57625 | ||
|
|
77c7b312ea | ||
|
|
3850765759 | ||
|
|
0b8e2fd5c9 | ||
|
|
ebe9ee8114 | ||
|
|
a8ab617ee9 | ||
|
|
414440589e | ||
|
|
544b6d94aa | ||
|
|
0144062126 | ||
|
|
db1b7a8067 | ||
|
|
a9905ec95e | ||
|
|
7e2afacf34 | ||
|
|
2b6257e94e | ||
|
|
d14b5fe00b | ||
|
|
04bb2d1066 | ||
|
|
3b9037397a | ||
|
|
ea3e602835 | ||
|
|
96e971084a | ||
|
|
9bf78a96cc | ||
|
|
ba55ef0b2e | ||
|
|
0c00f7393c | ||
|
|
1824826474 | ||
|
|
57e1c7d55f | ||
|
|
e489b4a570 | ||
|
|
83dc7f0855 | ||
|
|
90a2d1bb39 | ||
|
|
da650606e3 | ||
|
|
bc789d7c1a | ||
|
|
5999b50e10 | ||
|
|
e5428a3c27 | ||
|
|
cf39bc97a5 | ||
|
|
4d43374fde | ||
|
|
dac42ee272 | ||
|
|
f7991185ba | ||
|
|
5954f15989 | ||
|
|
4d2eb7af30 | ||
|
|
50083048f6 | ||
|
|
dab2932550 | ||
|
|
a8cebbe3fd | ||
|
|
d6a6194e68 | ||
|
|
c373527851 | ||
|
|
de8726ab73 | ||
|
|
94d33a4ef1 | ||
|
|
d79b41e4a7 | ||
|
|
754a6e1177 | ||
|
|
b972ea4781 | ||
|
|
45856816c1 | ||
|
|
582162460f | ||
|
|
e970c36419 | ||
|
|
c48cc0afdc | ||
|
|
3d6d4f5464 | ||
|
|
61bc6ec825 | ||
|
|
6f0f6676db | ||
|
|
fc240d4dfa | ||
|
|
6dc0861740 | ||
|
|
45cabd756c | ||
|
|
5fc854ab4f | ||
|
|
caa3343dea | ||
|
|
3ac43497b9 | ||
|
|
74f1b800c2 | ||
|
|
7d431e55df | ||
|
|
575962569f | ||
|
|
01ef0e93aa | ||
|
|
439f4f6f0e | ||
|
|
00b1f33725 | ||
|
|
1204eec8ac | ||
|
|
f3ac8f6649 | ||
|
|
7db280a666 | ||
|
|
a4b7ad0d42 | ||
|
|
2b88905b40 | ||
|
|
ef5263ef9e | ||
|
|
9206512c38 | ||
|
|
82e16db275 | ||
|
|
97fc093eef | ||
|
|
b9cd424186 | ||
|
|
6af85409f1 | ||
|
|
86c699dd36 | ||
|
|
3d4e1ffd64 | ||
|
|
b39fcebe65 | ||
|
|
04129a0841 | ||
|
|
a7658f013e | ||
|
|
2822bf7a65 | ||
|
|
87ccd272ee | ||
|
|
18275ce2c9 | ||
|
|
5935070dfa | ||
|
|
8391c83121 | ||
|
|
4255ee105f | ||
|
|
e3c45bd1f7 | ||
|
|
449617474b | ||
|
|
ce542ac5f6 | ||
|
|
d0e18ed0ba | ||
|
|
70952282f0 | ||
|
|
bf325b72f1 | ||
|
|
f031ad23f6 | ||
|
|
9e56725406 | ||
|
|
ad543c909c | ||
|
|
36b8b81914 | ||
|
|
5d76ffef88 | ||
|
|
37316fed84 | ||
|
|
ecd568510d | ||
|
|
5ec9cf7089 | ||
|
|
aad1b5dc9f | ||
|
|
1b13f0a2ec | ||
|
|
29108ea8ad | ||
|
|
0e167ee85b | ||
|
|
8fe6d09613 | ||
|
|
fa0df413f4 | ||
|
|
1a8be6344a | ||
|
|
fff8455903 | ||
|
|
80d94e1aa3 | ||
|
|
a36c266e7d | ||
|
|
636c100b6b | ||
|
|
28f85aae7f | ||
|
|
dfa11f64ef | ||
|
|
3f92d2f300 | ||
|
|
cc0bf88a5f | ||
|
|
b3c0b964b5 | ||
|
|
4661e5a10b | ||
|
|
220a35b492 | ||
|
|
351142f93f | ||
|
|
29bc273e58 | ||
|
|
b96e0c8713 | ||
|
|
7e0c0d79bc | ||
|
|
1f88f1f3f6 | ||
|
|
69d8b1c30d | ||
|
|
5a5d8d2d07 | ||
|
|
0e25540a89 | ||
|
|
21169f4e9a | ||
|
|
1fbed9f7d0 | ||
|
|
c230cf5aab | ||
|
|
2d65ed352e | ||
|
|
5fa81d4273 | ||
|
|
5ec32bdd2f | ||
|
|
d39aa10da1 | ||
|
|
0d763052fb | ||
|
|
ee62e33dd0 | ||
|
|
a22de48e40 | ||
|
|
7b5708a8b4 | ||
|
|
71c1767790 | ||
|
|
5fb0115d06 | ||
|
|
c8e6128720 | ||
|
|
55583540a8 | ||
|
|
9b5d0228be | ||
|
|
325d05b59c | ||
|
|
d1500dc99b | ||
|
|
157c8d5e54 | ||
|
|
0533b5cefc | ||
|
|
7816085868 | ||
|
|
178a5f0645 | ||
|
|
dfb8527e50 | ||
|
|
0a581154d1 | ||
|
|
efabf18162 | ||
|
|
56737ac523 | ||
|
|
702885ebb2 | ||
|
|
a12b83de59 | ||
|
|
3b83356825 | ||
|
|
c2aad7a71d | ||
|
|
ef4edc6ff1 | ||
|
|
614967ccc1 | ||
|
|
e8dc1480eb | ||
|
|
8fb87df0f0 | ||
|
|
bb7cfd2493 | ||
|
|
1b19622ab8 | ||
|
|
68ab7e2e3e | ||
|
|
157a286d1b | ||
|
|
0eb199a9a8 | ||
|
|
77a928cef9 | ||
|
|
290388159a | ||
|
|
d0551a3ede | ||
|
|
1e0d0429d0 | ||
|
|
37ad913086 | ||
|
|
3755ad7515 | ||
|
|
369e141ea8 | ||
|
|
39c9e69d8a | ||
|
|
30be1ea16e | ||
|
|
a450361956 | ||
|
|
df48ad6b61 | ||
|
|
264de34c31 | ||
|
|
70444b46b9 | ||
|
|
a79e552ab4 | ||
|
|
1b5faef097 | ||
|
|
fe61f583e6 | ||
|
|
4031ad354b | ||
|
|
46b9ae4174 | ||
|
|
c0d1aaa8a0 | ||
|
|
a963427967 | ||
|
|
d5ec523584 | ||
|
|
c0c3fceaad | ||
|
|
c52d7c9126 | ||
|
|
6cb67a19e7 | ||
|
|
9b5ca124ab | ||
|
|
4a0a509dd8 | ||
|
|
6f2184901d | ||
|
|
201e5e59da | ||
|
|
2cb5778cfa | ||
|
|
006016322b | ||
|
|
4191856034 | ||
|
|
97f7b4f59f | ||
|
|
ea441b3d70 | ||
|
|
045ee262a8 | ||
|
|
502c6f0dae | ||
|
|
bc31dfbbd1 | ||
|
|
a1319f4231 | ||
|
|
ce365abab6 | ||
|
|
48a623f062 | ||
|
|
a727dfb3b0 | ||
|
|
52ba76fcb2 | ||
|
|
70e29d4f20 | ||
|
|
08d83eb8da | ||
|
|
eacff1f0b4 | ||
|
|
4806d71ca2 | ||
|
|
085b87dd02 | ||
|
|
35cd7eb2be | ||
|
|
ec716f0c58 | ||
|
|
0d97198f88 | ||
|
|
2c7537b4cd | ||
|
|
e364937353 | ||
|
|
877ef76540 | ||
|
|
519e8c5fcd | ||
|
|
305d53f094 | ||
|
|
5625ad76b9 | ||
|
|
4c722bf623 | ||
|
|
8fe22c33bf | ||
|
|
d866c061a3 | ||
|
|
f8fed31918 | ||
|
|
e487007960 | ||
|
|
b46f2d1527 | ||
|
|
e162fb0e80 | ||
|
|
91ea3ba090 | ||
|
|
e84f6e4afd | ||
|
|
9b65900df0 | ||
|
|
9659340d7f | ||
|
|
63175aa3cb | ||
|
|
986aa2a477 | ||
|
|
07d7a8eeff | ||
|
|
3c9e84d380 | ||
|
|
0f62a8ec2f | ||
|
|
4e7a9cf30b | ||
|
|
5077703400 | ||
|
|
77fef18590 | ||
|
|
6ce00034a2 | ||
|
|
ed6d8521e6 | ||
|
|
d24c751eef | ||
|
|
54012523bc | ||
|
|
5286f43133 | ||
|
|
ca1e9a2976 | ||
|
|
5951cbf7b9 | ||
|
|
e2b519a21e | ||
|
|
cf0401fea7 | ||
|
|
14a8f4a728 | ||
|
|
3e41d9b794 | ||
|
|
148867bf47 | ||
|
|
ef6c454137 | ||
|
|
093f8cb89b | ||
|
|
707e820af6 | ||
|
|
0c7696da65 | ||
|
|
9e540eb1c4 | ||
|
|
306828480f | ||
|
|
42b415952b | ||
|
|
e155e258cb | ||
|
|
6f45794574 | ||
|
|
1d30f00806 | ||
|
|
52e9ec10bf | ||
|
|
8da56ff98c | ||
|
|
d44e334524 | ||
|
|
e814e65fcb | ||
|
|
c2f7d600aa | ||
|
|
5d942265f9 | ||
|
|
6b07625192 | ||
|
|
19b56361b9 | ||
|
|
7d93eba321 | ||
|
|
7b42aba5ea | ||
|
|
be4ac7ca61 | ||
|
|
28e25ea718 | ||
|
|
b2e6e6155f | ||
|
|
f5e1ff3f1f | ||
|
|
3fda82b5f8 | ||
|
|
822a4896da | ||
|
|
7f2bf03d7e | ||
|
|
1e8a6e878d | ||
|
|
5f0a55057e | ||
|
|
7814acb9f8 | ||
|
|
b296af6fe4 | ||
|
|
14b9902f6d | ||
|
|
f2d54b7728 | ||
|
|
8950a693db | ||
|
|
fd3b9095ba | ||
|
|
030e1b9130 | ||
|
|
a040c237bc | ||
|
|
a62fafd4ed | ||
|
|
666703e8cf | ||
|
|
52cd52ca54 | ||
|
|
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 | ||
|
|
1f636bf7a9 |
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"project_id" : "sourcemod",
|
||||||
|
"conduit_uri" : "https://phabricator.alliedmods.net/",
|
||||||
|
"history.immutable" : false
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
# Binaries
|
||||||
|
*.dll
|
||||||
|
*.dylib
|
||||||
|
*.exe
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Files generated by Visual Studio
|
||||||
|
*.aps
|
||||||
|
*.ipch
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
CrazyDebug*/
|
||||||
|
Debug*/
|
||||||
|
Release*/
|
||||||
|
LIB-Release/
|
||||||
|
LIB-Debug/
|
||||||
|
|
||||||
|
# Files generated by Mac OS X Finder
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Files generated by Windows Explorer
|
||||||
|
[Dd]esktop.ini
|
||||||
|
[Tt]humbs.db
|
||||||
|
|
||||||
|
# AMBuild build directories
|
||||||
|
build/
|
||||||
|
obj-*/
|
||||||
|
*~
|
||||||
|
*.rej
|
||||||
|
*.orig
|
||||||
|
*.smx
|
||||||
|
*.swp
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Binaries
|
|
||||||
\.dll$
|
|
||||||
\.exe$
|
|
||||||
\.so$
|
|
||||||
|
|
||||||
# Files generated by Visual Studio
|
|
||||||
\.aps$
|
|
||||||
\.ncb$
|
|
||||||
\.suo$
|
|
||||||
\.user$
|
|
||||||
|
|
||||||
# Build directories
|
|
||||||
/CrazyDebug.*
|
|
||||||
/Debug.*
|
|
||||||
/Release.*
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
54539fa4e51f98d7841c853c1370dff6ccd3cdf2 sourcemod-1.0.0
|
|
||||||
e6ef5ecdf8d75740ca2685a709bf321f8873bc3b sourcemod-1.1.0
|
|
||||||
e877885fac80be71822641f7a9122cebc9812521 sourcemod-1.1.1
|
|
||||||
b3ffa8a4511c4eadaf533fc790aa6b14f7f0c6ea sourcemod-1.1.2
|
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
language: cpp
|
||||||
|
compiler:
|
||||||
|
- clang
|
||||||
|
before_script:
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get install -y g++-multilib libc6-dev-i386 lib32stdc++6 lib32z1-dev
|
||||||
|
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
|
||||||
|
script:
|
||||||
|
- mkdir build && cd build
|
||||||
|
- python ../configure.py --enable-optimize --sdks=episode1,tf2,l4d2,csgo,dota
|
||||||
|
- ambuild
|
||||||
+514
@@ -0,0 +1,514 @@
|
|||||||
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
|
import os, sys
|
||||||
|
|
||||||
|
class SDK(object):
|
||||||
|
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
||||||
|
self.folder = 'hl2sdk-' + dir
|
||||||
|
self.envvar = sdk
|
||||||
|
self.ext = ext
|
||||||
|
self.code = aDef
|
||||||
|
self.define = name
|
||||||
|
self.platform = platform
|
||||||
|
self.name = dir
|
||||||
|
self.path = None # Actual path
|
||||||
|
|
||||||
|
WinOnly = ['windows']
|
||||||
|
WinLinux = ['windows', 'linux']
|
||||||
|
WinLinuxMac = ['windows', 'linux', 'mac']
|
||||||
|
|
||||||
|
PossibleSDKs = {
|
||||||
|
'episode1': SDK('HL2SDK', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
||||||
|
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
||||||
|
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
|
||||||
|
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
|
||||||
|
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
|
||||||
|
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
|
||||||
|
'tf2': SDK('HL2SDKTF2', '2.tf2', '10', 'TF2', WinLinuxMac, 'tf2'),
|
||||||
|
'l4d': SDK('HL2SDKL4D', '2.l4d', '11', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
|
||||||
|
'nucleardawn': SDK('HL2SDKND', '2.nd', '12', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
|
||||||
|
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '14', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
|
||||||
|
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
|
||||||
|
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '15', 'ALIENSWARM', WinOnly, 'swarm'),
|
||||||
|
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
|
||||||
|
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
||||||
|
'csgo': SDK('HL2SDKCSGO', '2.csgo', '19', 'CSGO', WinLinuxMac, 'csgo'),
|
||||||
|
'dota': SDK('HL2SDKDOTA', '2.dota', '20', 'DOTA', WinLinuxMac, 'dota'),
|
||||||
|
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '16', 'PORTAL2', [], 'portal2'),
|
||||||
|
'blade': SDK('HL2SDKBLADE', '2.blade', '17', 'BLADE', WinLinux, 'blade'),
|
||||||
|
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '18', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
||||||
|
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '13', 'CONTAGION', WinOnly, 'contagion'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def ResolveEnvPath(env, folder):
|
||||||
|
if env in os.environ:
|
||||||
|
path = os.environ[env]
|
||||||
|
if os.path.isdir(path):
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
head = os.getcwd()
|
||||||
|
oldhead = None
|
||||||
|
while head != None and head != oldhead:
|
||||||
|
path = os.path.join(head, folder)
|
||||||
|
if os.path.isdir(path):
|
||||||
|
return path
|
||||||
|
oldhead = head
|
||||||
|
head, tail = os.path.split(head)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def Normalize(path):
|
||||||
|
return os.path.abspath(os.path.normpath(path))
|
||||||
|
|
||||||
|
class SMConfig(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.sdks = {}
|
||||||
|
self.binaries = []
|
||||||
|
self.extensions = []
|
||||||
|
self.generated_headers = None
|
||||||
|
self.mms_root = None
|
||||||
|
self.mysql_root = None
|
||||||
|
self.spcomp = None
|
||||||
|
self.smx_files = {}
|
||||||
|
self.versionlib = None
|
||||||
|
|
||||||
|
def use_auto_versioning(self):
|
||||||
|
return builder.backend == 'amb2'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tag(self):
|
||||||
|
if builder.options.debug == '1':
|
||||||
|
return 'Debug'
|
||||||
|
return 'Release'
|
||||||
|
|
||||||
|
def detectProductVersion(self):
|
||||||
|
builder.AddConfigureFile('product.version')
|
||||||
|
|
||||||
|
# For OS X dylib versioning
|
||||||
|
import re
|
||||||
|
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
||||||
|
productContents = fp.read()
|
||||||
|
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||||
|
if m == None:
|
||||||
|
self.productVersion = '1.0.0'
|
||||||
|
else:
|
||||||
|
major, minor, release = m.groups()
|
||||||
|
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
|
||||||
|
|
||||||
|
def detectSDKs(self):
|
||||||
|
sdk_list = builder.options.sdks.split(',')
|
||||||
|
use_all = sdk_list[0] == 'all'
|
||||||
|
use_present = sdk_list[0] == 'present'
|
||||||
|
|
||||||
|
for sdk_name in PossibleSDKs:
|
||||||
|
sdk = PossibleSDKs[sdk_name]
|
||||||
|
if builder.target_platform in sdk.platform:
|
||||||
|
if builder.options.hl2sdk_root:
|
||||||
|
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
||||||
|
else:
|
||||||
|
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
||||||
|
if sdk_path is None or not os.path.isdir(sdk_path):
|
||||||
|
if use_all or sdk_name in sdk_list:
|
||||||
|
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
||||||
|
continue
|
||||||
|
if use_all or use_present or sdk_name in sdk_list:
|
||||||
|
sdk.path = Normalize(sdk_path)
|
||||||
|
self.sdks[sdk_name] = sdk
|
||||||
|
|
||||||
|
if len(self.sdks) < 1:
|
||||||
|
raise Exception('At least one SDK must be available.')
|
||||||
|
|
||||||
|
|
||||||
|
if builder.options.mms_path:
|
||||||
|
self.mms_root = builder.options.mms_path
|
||||||
|
else:
|
||||||
|
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
||||||
|
if not self.mms_root:
|
||||||
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||||
|
if not self.mms_root:
|
||||||
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
|
||||||
|
|
||||||
|
if not self.mms_root or not os.path.isdir(self.mms_root):
|
||||||
|
raise Exception('Could not find a source copy of Metamod:Source')
|
||||||
|
self.mms_root = Normalize(self.mms_root)
|
||||||
|
|
||||||
|
if builder.options.hasMySql:
|
||||||
|
if builder.options.mysql_path:
|
||||||
|
self.mysql_root = builder.options.mysql_path
|
||||||
|
else:
|
||||||
|
for i in range(7):
|
||||||
|
self.mysql_root = ResolveEnvPath('MYSQL5', 'mysql-5.' + str(i))
|
||||||
|
if self.mysql_root:
|
||||||
|
break
|
||||||
|
if not self.mysql_root or not os.path.isdir(self.mysql_root):
|
||||||
|
raise Exception('Could not find a path to MySQL!')
|
||||||
|
self.mysql_root = Normalize(self.mysql_root)
|
||||||
|
|
||||||
|
def configure(self):
|
||||||
|
builder.AddConfigureFile('pushbuild.txt')
|
||||||
|
|
||||||
|
cxx = builder.DetectCompilers()
|
||||||
|
|
||||||
|
if cxx.like('gcc'):
|
||||||
|
cxx.defines += [
|
||||||
|
'stricmp=strcasecmp',
|
||||||
|
'_stricmp=strcasecmp',
|
||||||
|
'_snprintf=snprintf',
|
||||||
|
'_vsnprintf=vsnprintf',
|
||||||
|
'HAVE_STDINT_H',
|
||||||
|
'GNUC',
|
||||||
|
]
|
||||||
|
cxx.cflags += [
|
||||||
|
'-pipe',
|
||||||
|
'-fno-strict-aliasing',
|
||||||
|
'-Wall',
|
||||||
|
'-Werror',
|
||||||
|
'-Wno-uninitialized',
|
||||||
|
'-Wno-unused',
|
||||||
|
'-Wno-switch',
|
||||||
|
'-Wno-format',
|
||||||
|
'-Wno-format-security',
|
||||||
|
'-msse',
|
||||||
|
'-m32',
|
||||||
|
]
|
||||||
|
|
||||||
|
have_gcc = cxx.vendor == 'gcc'
|
||||||
|
have_clang = cxx.vendor == 'clang'
|
||||||
|
if have_clang or (have_gcc and cxx.version >= '4'):
|
||||||
|
cxx.cflags += ['-fvisibility=hidden']
|
||||||
|
cxx.cxxflags += ['-fvisibility-inlines-hidden']
|
||||||
|
if have_clang or (have_gcc and cxx.version >= '4.6'):
|
||||||
|
cxx.cflags += ['-Wno-narrowing']
|
||||||
|
if (have_gcc and cxx.version >= '4.7') or (have_clang and cxx.version >= '3'):
|
||||||
|
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
|
||||||
|
|
||||||
|
cxx.linkflags += ['-m32']
|
||||||
|
cxx.cxxflags += [
|
||||||
|
'-fno-exceptions',
|
||||||
|
'-fno-threadsafe-statics',
|
||||||
|
'-Wno-non-virtual-dtor',
|
||||||
|
'-Wno-overloaded-virtual',
|
||||||
|
]
|
||||||
|
|
||||||
|
if have_gcc:
|
||||||
|
cxx.cflags += ['-mfpmath=sse']
|
||||||
|
elif cxx.vendor == 'msvc':
|
||||||
|
if builder.options.debug == '1':
|
||||||
|
cxx.cflags += ['/MTd']
|
||||||
|
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||||
|
else:
|
||||||
|
cxx.cflags += ['/MT']
|
||||||
|
cxx.defines += [
|
||||||
|
'_CRT_SECURE_NO_DEPRECATE',
|
||||||
|
'_CRT_SECURE_NO_WARNINGS',
|
||||||
|
'_CRT_NONSTDC_NO_DEPRECATE',
|
||||||
|
'_ITERATOR_DEBUG_LEVEL=0',
|
||||||
|
]
|
||||||
|
cxx.cflags += [
|
||||||
|
'/W3',
|
||||||
|
]
|
||||||
|
cxx.cxxflags += [
|
||||||
|
'/EHsc',
|
||||||
|
'/GR-',
|
||||||
|
'/TP',
|
||||||
|
]
|
||||||
|
cxx.linkflags += [
|
||||||
|
'/MACHINE:X86',
|
||||||
|
'/SUBSYSTEM:WINDOWS',
|
||||||
|
'kernel32.lib',
|
||||||
|
'user32.lib',
|
||||||
|
'gdi32.lib',
|
||||||
|
'winspool.lib',
|
||||||
|
'comdlg32.lib',
|
||||||
|
'advapi32.lib',
|
||||||
|
'shell32.lib',
|
||||||
|
'ole32.lib',
|
||||||
|
'oleaut32.lib',
|
||||||
|
'uuid.lib',
|
||||||
|
'odbc32.lib',
|
||||||
|
'odbccp32.lib',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Optimization
|
||||||
|
if builder.options.opt == '1':
|
||||||
|
cxx.defines += ['NDEBUG']
|
||||||
|
if cxx.like('gcc'):
|
||||||
|
cxx.cflags += ['-O3']
|
||||||
|
elif cxx.like('msvc'):
|
||||||
|
cxx.cflags += ['/Ox']
|
||||||
|
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
|
||||||
|
|
||||||
|
# Debugging
|
||||||
|
if builder.options.debug == '1':
|
||||||
|
cxx.defines += ['DEBUG', '_DEBUG']
|
||||||
|
if cxx.like('msvc'):
|
||||||
|
cxx.cflags += ['/Od', '/RTC1']
|
||||||
|
if cxx.version >= 1600:
|
||||||
|
cxx.cflags += ['/d2Zi+']
|
||||||
|
|
||||||
|
# This needs to be after our optimization flags which could otherwise disable it.
|
||||||
|
if cxx.vendor == 'msvc':
|
||||||
|
# Don't omit the frame pointer.
|
||||||
|
cxx.cflags += ['/Oy-']
|
||||||
|
|
||||||
|
# Platform-specifics
|
||||||
|
if builder.target_platform == 'linux':
|
||||||
|
cxx.defines += ['_LINUX', 'POSIX']
|
||||||
|
if cxx.vendor == 'gcc':
|
||||||
|
cxx.linkflags += ['-static-libgcc']
|
||||||
|
elif cxx.vendor == 'clang':
|
||||||
|
cxx.linkflags += ['-lgcc_eh']
|
||||||
|
elif builder.target_platform == 'mac':
|
||||||
|
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
||||||
|
cxx.cflags += ['-mmacosx-version-min=10.5']
|
||||||
|
cxx.linkflags += [
|
||||||
|
'-mmacosx-version-min=10.5',
|
||||||
|
'-arch', 'i386',
|
||||||
|
'-lstdc++',
|
||||||
|
'-stdlib=libstdc++',
|
||||||
|
]
|
||||||
|
cxx.cxxflags += ['-stdlib=libstdc++']
|
||||||
|
elif builder.target_platform == 'windows':
|
||||||
|
cxx.defines += ['WIN32', '_WINDOWS']
|
||||||
|
|
||||||
|
# Finish up.
|
||||||
|
cxx.defines += [
|
||||||
|
'SOURCEMOD_BUILD',
|
||||||
|
'SM_USE_VERSIONLIB',
|
||||||
|
]
|
||||||
|
if self.use_auto_versioning():
|
||||||
|
cxx.defines += ['SM_GENERATED_BUILD']
|
||||||
|
cxx.includes += [os.path.join(builder.buildPath, 'includes')]
|
||||||
|
cxx.includes += [os.path.join(builder.sourcePath, 'versionlib')]
|
||||||
|
|
||||||
|
def AddVersioning(self, binary):
|
||||||
|
if builder.target_platform == 'windows':
|
||||||
|
binary.sources += ['version.rc']
|
||||||
|
binary.compiler.rcdefines += [
|
||||||
|
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
||||||
|
'RC_COMPILE',
|
||||||
|
]
|
||||||
|
if self.use_auto_versioning():
|
||||||
|
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
||||||
|
elif builder.target_platform == 'mac':
|
||||||
|
if binary.type == 'library':
|
||||||
|
binary.compiler.postlink += [
|
||||||
|
'-compatibility_version', '1.0.0',
|
||||||
|
'-current_version', self.productVersion
|
||||||
|
]
|
||||||
|
if self.use_auto_versioning():
|
||||||
|
binary.compiler.linkflags += [self.versionlib]
|
||||||
|
binary.compiler.sourcedeps += SM.generated_headers
|
||||||
|
return binary
|
||||||
|
|
||||||
|
def Library(self, context, name):
|
||||||
|
binary = context.compiler.Library(name)
|
||||||
|
return self.AddVersioning(binary)
|
||||||
|
|
||||||
|
def Program(self, context, name):
|
||||||
|
binary = context.compiler.Program(name)
|
||||||
|
return self.AddVersioning(binary)
|
||||||
|
|
||||||
|
def ConfigureForExtension(self, context, compiler):
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(context.currentSourcePath),
|
||||||
|
os.path.join(context.currentSourcePath, 'sdk'),
|
||||||
|
os.path.join(builder.sourcePath, 'public'),
|
||||||
|
os.path.join(builder.sourcePath, 'public', 'extensions'),
|
||||||
|
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
|
||||||
|
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||||
|
]
|
||||||
|
return compiler
|
||||||
|
|
||||||
|
def ExtLibrary(self, context, name):
|
||||||
|
binary = context.compiler.Library(name)
|
||||||
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
|
return self.AddVersioning(binary)
|
||||||
|
|
||||||
|
def ConfigureForHL2(self, binary, sdk):
|
||||||
|
compiler = binary.compiler
|
||||||
|
|
||||||
|
if sdk.name == 'episode1':
|
||||||
|
mms_path = os.path.join(self.mms_root, 'core-legacy')
|
||||||
|
else:
|
||||||
|
mms_path = os.path.join(self.mms_root, 'core')
|
||||||
|
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(mms_path),
|
||||||
|
os.path.join(mms_path, 'sourcehook'),
|
||||||
|
]
|
||||||
|
|
||||||
|
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
||||||
|
compiler.defines += defines
|
||||||
|
|
||||||
|
paths = [
|
||||||
|
['public'],
|
||||||
|
['public', 'engine'],
|
||||||
|
['public', 'mathlib'],
|
||||||
|
['public', 'vstdlib'],
|
||||||
|
['public', 'tier0'],
|
||||||
|
['public', 'tier1']
|
||||||
|
]
|
||||||
|
if sdk.name == 'episode1' or sdk.name == 'darkm':
|
||||||
|
paths.append(['public', 'dlls'])
|
||||||
|
paths.append(['game_shared'])
|
||||||
|
else:
|
||||||
|
paths.append(['public', 'game', 'server'])
|
||||||
|
paths.append(['public', 'toolframework'])
|
||||||
|
paths.append(['game', 'shared'])
|
||||||
|
paths.append(['common'])
|
||||||
|
|
||||||
|
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
|
||||||
|
|
||||||
|
if sdk.name == 'sdk2013' and compiler.like('gcc'):
|
||||||
|
# The 2013 SDK already has these in public/tier0/basetypes.h
|
||||||
|
compiler.defines.remove('stricmp=strcasecmp')
|
||||||
|
compiler.defines.remove('_stricmp=strcasecmp')
|
||||||
|
compiler.defines.remove('_snprintf=snprintf')
|
||||||
|
compiler.defines.remove('_vsnprintf=vsnprintf')
|
||||||
|
|
||||||
|
if compiler.like('msvc'):
|
||||||
|
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
|
||||||
|
else:
|
||||||
|
compiler.defines += ['COMPILER_GCC']
|
||||||
|
|
||||||
|
# For everything after Swarm, this needs to be defined for entity networking
|
||||||
|
# to work properly with sendprop value changes.
|
||||||
|
if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']:
|
||||||
|
compiler.defines += ['NETWORK_VARS_ENABLED']
|
||||||
|
|
||||||
|
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']:
|
||||||
|
if builder.target_platform in ['linux', 'mac']:
|
||||||
|
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||||
|
|
||||||
|
if sdk.name == 'csgo' and builder.target_platform == 'linux':
|
||||||
|
compiler.linkflags += ['-lstdc++']
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||||
|
|
||||||
|
if builder.target_platform == 'linux':
|
||||||
|
if sdk.name == 'episode1':
|
||||||
|
lib_folder = os.path.join(sdk.path, 'linux_sdk')
|
||||||
|
elif sdk.name == 'sdk2013':
|
||||||
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
||||||
|
else:
|
||||||
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
||||||
|
elif builder.target_platform == 'mac':
|
||||||
|
if sdk.name == 'sdk2013':
|
||||||
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
||||||
|
else:
|
||||||
|
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
||||||
|
|
||||||
|
if builder.target_platform in ['linux', 'mac']:
|
||||||
|
if sdk.name == 'sdk2013':
|
||||||
|
compiler.postlink += [
|
||||||
|
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
|
||||||
|
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
compiler.postlink += [
|
||||||
|
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
|
||||||
|
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
|
||||||
|
]
|
||||||
|
|
||||||
|
if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']:
|
||||||
|
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
|
||||||
|
|
||||||
|
self.AddVersioning(binary)
|
||||||
|
|
||||||
|
dynamic_libs = []
|
||||||
|
if builder.target_platform == 'linux':
|
||||||
|
compiler.linkflags[0:0] = ['-lm']
|
||||||
|
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'nucleardawn', 'l4d2']:
|
||||||
|
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
||||||
|
elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota']:
|
||||||
|
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
||||||
|
else:
|
||||||
|
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
||||||
|
elif builder.target_platform == 'mac':
|
||||||
|
compiler.linkflags.append('-liconv')
|
||||||
|
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
||||||
|
elif builder.target_platform == 'windows':
|
||||||
|
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
||||||
|
if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']:
|
||||||
|
libs.append('interfaces')
|
||||||
|
for lib in libs:
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
|
||||||
|
compiler.linkflags.append(compiler.Dep(lib_path))
|
||||||
|
|
||||||
|
for library in dynamic_libs:
|
||||||
|
source_path = os.path.join(lib_folder, library)
|
||||||
|
output_path = os.path.join(binary.localFolder, library)
|
||||||
|
|
||||||
|
def make_linker(source_path, output_path):
|
||||||
|
def link(context, binary):
|
||||||
|
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
|
||||||
|
return output
|
||||||
|
return link
|
||||||
|
|
||||||
|
linker = make_linker(source_path, output_path)
|
||||||
|
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
|
||||||
|
|
||||||
|
return binary
|
||||||
|
|
||||||
|
def HL2Library(self, context, name, sdk):
|
||||||
|
binary = context.compiler.Library(name)
|
||||||
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
|
return self.ConfigureForHL2(binary, sdk)
|
||||||
|
|
||||||
|
def HL2Project(self, context, name):
|
||||||
|
project = context.compiler.LibraryProject(name)
|
||||||
|
self.ConfigureForExtension(context, project.compiler)
|
||||||
|
return project
|
||||||
|
|
||||||
|
def HL2Config(self, project, name, sdk):
|
||||||
|
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
|
||||||
|
return self.ConfigureForHL2(binary, sdk)
|
||||||
|
|
||||||
|
SM = SMConfig()
|
||||||
|
SM.detectProductVersion()
|
||||||
|
SM.detectSDKs()
|
||||||
|
SM.configure()
|
||||||
|
|
||||||
|
if SM.use_auto_versioning():
|
||||||
|
SM.generated_headers = builder.RunScript(
|
||||||
|
'tools/buildbot/Versioning',
|
||||||
|
{ 'SM': SM }
|
||||||
|
)
|
||||||
|
SM.versionlib = builder.RunScript(
|
||||||
|
'versionlib/AMBuilder',
|
||||||
|
{ 'SM': SM }
|
||||||
|
)
|
||||||
|
|
||||||
|
BuildScripts = [
|
||||||
|
'loader/AMBuilder',
|
||||||
|
'core/AMBuilder',
|
||||||
|
'core/logic/AMBuilder',
|
||||||
|
'extensions/bintools/AMBuilder',
|
||||||
|
'extensions/clientprefs/AMBuilder',
|
||||||
|
'extensions/curl/AMBuilder',
|
||||||
|
'extensions/cstrike/AMBuilder',
|
||||||
|
'extensions/geoip/AMBuilder',
|
||||||
|
'extensions/mysql/AMBuilder',
|
||||||
|
'extensions/regex/AMBuilder',
|
||||||
|
'extensions/sdkhooks/AMBuilder',
|
||||||
|
'extensions/sdktools/AMBuilder',
|
||||||
|
'extensions/sqlite/AMBuilder',
|
||||||
|
'extensions/tf2/AMBuilder',
|
||||||
|
'extensions/topmenus/AMBuilder',
|
||||||
|
'extensions/updater/AMBuilder',
|
||||||
|
'sourcepawn/compiler/AMBuilder',
|
||||||
|
'sourcepawn/jit/AMBuilder',
|
||||||
|
]
|
||||||
|
|
||||||
|
if builder.backend == 'amb2':
|
||||||
|
BuildScripts += [
|
||||||
|
'plugins/AMBuilder',
|
||||||
|
'tools/buildbot/PackageScript',
|
||||||
|
]
|
||||||
|
|
||||||
|
builder.RunBuildScripts(BuildScripts, { 'SM': SM })
|
||||||
|
|
||||||
|
if builder.options.breakpad_dump:
|
||||||
|
builder.RunScript('tools/buildbot/BreakpadSymbols', { 'SM': SM })
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
Please visit [our wiki](https://wiki.alliedmods.net/Contributing_to_SourceMod) for information on how to contribute to Sourcemod.
|
||||||
|
|
||||||
|
As a sidenote, [Travis](https://travis-ci.org/alliedmodders/sourcemod) will automatically build your PR to make sure it compiles on Linux.
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
|
|
||||||
CONFIGURE YOUR IDENTITY FOR MERCURIAL!
|
|
||||||
IF YOU ARE A DEVELOPER WITH PUSH ACCESS, DO IT NOW KPLZTHX.
|
|
||||||
|
|
||||||
http://wiki.alliedmods.net/Mercurial_Tutorial#Identity
|
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
SourceMod
|
||||||
|
=========
|
||||||
|
|
||||||
|
General
|
||||||
|
-------
|
||||||
|
- [SourceMod website](http://www.sourcemod.net): Source Engine scripting and server administration
|
||||||
|
- [Forum](https://forums.alliedmods.net/forumdisplay.php?f=52): Discussion forum including plugin/extension development
|
||||||
|
- [General documentation](https://wiki.alliedmods.net/Category:SourceMod_Documentation): Miscellaneous information about SourceMod
|
||||||
|
- [Latest release](http://www.sourcemod.net/downloads.php): The latest stable SourceMod release
|
||||||
|
- [Build snapshots](http://www.sourcemod.net/snapshots.php): Builds of recent development versions
|
||||||
|
|
||||||
|
Development
|
||||||
|
-----------
|
||||||
|
- [Issue tracker](https://bugs.alliedmods.net): Issues that require back and forth communication
|
||||||
|
- [Building SourceMod](https://wiki.alliedmods.net/Building_SourceMod): Instructions on how to build SourceMod itself using [AMBuild](https://github.com/alliedmodders/ambuild)
|
||||||
|
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
|
||||||
|
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
|
||||||
+885
@@ -1,5 +1,890 @@
|
|||||||
SourceMod Changelog
|
SourceMod Changelog
|
||||||
|
|
||||||
|
SourceMod 1.6.3 [2014-11-25]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.6.3_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated game support for TF2, CS:GO, No More Room in Hell, Insurgency, PVK2 and Fistful of Frags.
|
||||||
|
- Made changes to make TF2, CSS, DoDS, HL2DM, and SDK 2013 mods less likely to break on game update (PR 174, PR 192).
|
||||||
|
- Added support for longer key names in languages.cfg (to fix Portuguese) (bug 6282, PR 208).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Updated TF2 player condition and holiday enums (Ross "Powerlord" Bemrose) (PR 183, PR 181).
|
||||||
|
- Add support for TF2 player conditions >= 96 for condition functions/forwards (PR 205).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.6.2 [2014-09-20]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.6.2_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated game support for TF2, CS:GO, No More Room in Hell and Fistful of Frags.
|
||||||
|
- Added compatibility shim to force Steam player auth strings to be in "Steam2" rendered format (PR 136).
|
||||||
|
- Fixed possible performance regression in DBI handling.
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Added new GetClientAuthId native to retrieve player auth strings in desired format (PR 159).
|
||||||
|
- Updated TF2 weapon and player condition enums (FlaminSarge).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.6.1 [2014-08-17]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.6.1_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated game support for CS:GO and Fistful of Frags.
|
||||||
|
- Added support for Romanian language.
|
||||||
|
- Re-added languages.cfg, missing from 1.6.0, causing all clients to use server language.
|
||||||
|
- Fixed a regression in version 1.6.0 that caused certain SDKHooks usage patterns to cause a server crash (PR 107).
|
||||||
|
- Improved error reporting in basebans plugin when banreasons.txt is missing (PR 115).
|
||||||
|
- Fixed incorrect logged gravity value for sm_gravity command (Ryan "VoiDeD" Stecker) (PR 116).
|
||||||
|
- Fixed a regression in version 1.6.0 causing SDKHook_ReloadPost hooks to not fire in plugins (Peace-Maker) (PR 96).
|
||||||
|
- Added workaround for game bug in TF2_RemoveWeaponSlot to avoid wearable entities left on map (Ryan "VoiDeD" Stecker) (bug 6206, PR 121).
|
||||||
|
- Removed DisableJIT option from core.cfg. (It was never meant for normal use.)
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Added new TF2_RemoveWearable native (Ryan "VoiDeD" Stecker, WildCard65) (PR 114).
|
||||||
|
- Added new functions for interacting with and playing scripted game sounds (Ross "Powerlord" Bemrose) (bug 5942, PR 65).
|
||||||
|
- Added new StringToKeyValues natives (Ryan "VoiDeD" Stecker) (PR 74).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.6.0 [2014-07-03]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.6.0_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Added support for Dota 2 (bug 5656, bug 6068).
|
||||||
|
- Added support for Source SDK 2013 mods (bug 5917).
|
||||||
|
- Added support for Insurgency (bug 5951).
|
||||||
|
- Added support for Contagion (bug 6007).
|
||||||
|
- Added support for Blade Symphony (bug 5949).
|
||||||
|
- Updated support for some mods that moved to SDK 2013 - No More Room In Hell, Fistful of Frags, Empires, Synergy.
|
||||||
|
- Updated gamedata and other support for TF2, DoD:S, HL2:DM, CS:S, CS:GO, Left 4 Dead, and Nuclear Dawn.
|
||||||
|
- Added support for customizing ban reasons in basebans.sp (bug 5762) (Matthias "House" Kollek).
|
||||||
|
- Added support for searching all gameinfo search paths when seeking mapcycle file (bug 5839).
|
||||||
|
- Added sm_reload_translations command (bug 5750).
|
||||||
|
- Added support for single-file gamedata custom overrides (bug 5386) (Ondrej "RavuAlHemio" Hošek).
|
||||||
|
- Re-enabled SteamAuthstringValidation config option by default (bug 5791, PR 20).
|
||||||
|
- Fixed plugins not reaching ext dep lists, making dependent plugin not unload on ext unload (bug 5851) (Peace-Maker).
|
||||||
|
- Added printing of SendProp flags to netprop dumps (bug 6082).
|
||||||
|
- Removed support for obsolete plugin_settings.cfg (bug 5605).
|
||||||
|
- Fixed topmenu sorting not getting refreshed after reloading sorting config (bug 6032) (Peace-Maker).
|
||||||
|
- Fixed error log filename date sometimes being incorrect (bug 5761) (Matheus "M28" Valadares).
|
||||||
|
- Dump handle information when a plugin is forcefully unloaded. (bug 5666).
|
||||||
|
- Fixed sm_cancelvote not resetting rtv state. (bug 5808) (Peace-Maker).
|
||||||
|
- Fixed Mapchooser dying on single map rotation servers (bug 5179).
|
||||||
|
- Fixed various problems with unloading ClientPrefs and SourceMod (bug 5874).
|
||||||
|
- Fixed "sm version" command reporting incorrect compile time in many cases (bug 6078) (SystematicMania).
|
||||||
|
- Clear default database driver reference if backing extension is unloaded (bug 5934) (Peace-Maker).
|
||||||
|
- Moved funcommands material and sound definitions to gamedata for easier cross-game support (bug 6085).
|
||||||
|
- Implement a watchdog timer for scripts that take too long to execute (bug 5837).
|
||||||
|
- Use Linux game data for offsets and signatures/symbols on OS X if Mac-specific data is not available (bug 6056).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Added an API for off-thread SQL transactions. (bug 3775, PR 26).
|
||||||
|
- Added string literal concatenation using ellipses "..." (bug 4261, PR 5) (Peace-Maker).
|
||||||
|
- Added support for nested datatables. (bug 5446).
|
||||||
|
- Added PbRemoveRepeatedFieldValue native (bug 6066).
|
||||||
|
- Added support for getting/setting protobuf enum values with PbGetInt, PbSetInt, and PbAddInt natives.
|
||||||
|
- Removed deprecated PbReadRepeated natives that existed briefly in 1.5.0-dev prerelease versions.
|
||||||
|
- Added RequestFrame native for one-off next-frame actions (bug 5965).
|
||||||
|
- Added CS_DMG_HEADSHOT define for CS:S and CS:GO (PR 7) (Bara20).
|
||||||
|
- Added CS_SLOT_KNIFE define for CS:S and CS:GO (bug 6131).
|
||||||
|
- Updated TF_WEAPON enum (PR 37) (FlaminSarge).
|
||||||
|
- Added TFHoliday_AprilFools to TFHoliday enum (bug 6092) (Ross "Powerlord" Bemrose).
|
||||||
|
- Added new TF2_IsHolidayActive native to TF2 Ext (bug 6095) (Ross "Powerlord" Bemrose).
|
||||||
|
- Switch TF2 extension to hook CTFGameRules::IsHolidayActive for holiday forward (bug 6137, PR 42).
|
||||||
|
- Added GetPlayerJingleFile native. (bug 5690) (FlaminSarge).
|
||||||
|
- Added PrepSDKCall_SetAddress and Address support to PrepSDKCall_SetFromConf (bug 5261).
|
||||||
|
- Added ability to disable TopMenu Title Caching (bug 6034) (Peace-Maker).
|
||||||
|
- Added DisplayTopMenuCategory native (bug 6033) (Peace-Maker).
|
||||||
|
- Added support for Valve search paths to GetFileSize native (bug 5931).
|
||||||
|
- Fixed invalid entities sometimes passed to OnEntityCreated and OnEntityDestroyed (bug 6119).
|
||||||
|
- Fixed inconsistencies with OnClientDisconnected foward calls (bug 5988, PR 16).
|
||||||
|
- Changed OnClientSayCommand to now pass non-silent chat triggers onward (bug 5926) (SystematicMania).
|
||||||
|
- Changed OnClientSayCommand forwards to strip quotes from chat (bug 5986) (SystematicMania).
|
||||||
|
- Fixed FindStringIndex native not returning INVALID_STRING_INDEX when string not found (bug 6144, PR 40).
|
||||||
|
- Fixed GroundEntChanged hooks not being called (bug 6050) (Peace-Maker).
|
||||||
|
- Fixed INetChannelInfo natives to no longer require clients to be ingame (bug 5775) (SystematicMania).
|
||||||
|
- Fixed replace param being respected inconsistently in SetTrieArray (bug 6113).
|
||||||
|
- Fixed crash creating a timer when there are no handles available. (bug 5317) (Peace-Maker).
|
||||||
|
- Fixed crash in ReconnectClient and InactivateClient natives when IServer ptr is null (bug 6122).
|
||||||
|
- Fixed StoreFromAddress and LoadFromAddress continuing with bad values, usually crashing after error (bug 6080).
|
||||||
|
- Fixed compiler bug with multidimensional array variable release (bug 6100).
|
||||||
|
- Changed float comparison operators to return false for NaN (bug 6107).
|
||||||
|
- Added support in spcomp for sp/inc files > 32767 lines (bug 5959).
|
||||||
|
- Fixed FindFlagChar returning '?' for Admin_Custom6.
|
||||||
|
- Fixed AllPluginsLoaded activities happening before SM is loaded.
|
||||||
|
- Deduplicated a number of files used by extensions by moving them to the public directory (bug 5341).
|
||||||
|
- Removed 'state' keyword from compiler (bug 4572) (Ryan "VoiDeD" Stecker).
|
||||||
|
- Removed LogMessageEx definition from logging.inc because it never existed (bug 5897) (Peace-Maker).
|
||||||
|
- Removed native override API (bug 5852).
|
||||||
|
- Call OnLibraryAdded for all available libraries (bug 5925, PR 4).
|
||||||
|
- Made IGameConfig::GetMemSig return value clearer (bug 6081).
|
||||||
|
- Switched StringToInt(Ex) from using strtol to strtoul internally (bug 5939).
|
||||||
|
- Added an spcomp option to print #included files (bug 5997).
|
||||||
|
- Recompiled Regex extension libpcre against v8.32, enabling utf8, unicode props, and jit (bug 5593).
|
||||||
|
- Optimized native calls if statically bound (bug 5842).
|
||||||
|
|
||||||
|
Internal Changes:
|
||||||
|
- Now using new AlliedModders Template Library (AMTL) in many places, https://github.com/alliedmodders/amtl
|
||||||
|
- Ported buildscripts to new AMBuild2 platform, https://github.com/alliedmodders/ambuild
|
||||||
|
- Moved much logic from core to logic binary to reduce file sizes and compile times (bug 5606, bug 5607, bug 5680, bug 5953, PR 12, PR 13).
|
||||||
|
- Refactored the JIT to use a newer, simpler macro assembler. (bug 5827).
|
||||||
|
- Added sourcepawn interpreter (bug 5902).
|
||||||
|
- Added support for compiling spcomp with emscripten.
|
||||||
|
- Rewrite IThreader implementation around new synchronization primitives (bug 5862).
|
||||||
|
- Rewrite DBManager to use the new synchronization primitives (bug 5870).
|
||||||
|
- Overhauled internals of ClientPrefs extension for improved stability (bug 5538).
|
||||||
|
- Changed ShareSys to store C++ native lists more optimally (bug 5852).
|
||||||
|
- Simplified NativeEntry state (bug 5852).
|
||||||
|
- Changed NativeEntry to use Refcounted to manage (bug 5852).
|
||||||
|
- Switched Translator and GameConfigs to hash tables (bug 5878).
|
||||||
|
- Switched numerous subsystems from KTrie to AMTL NameHashSet (bug 5884).
|
||||||
|
- Refactored Trie natives to use AMTL HashMap instead of KTrie (bug 5892).
|
||||||
|
- Removed usages of memtables from many subsystems (bug 5899).
|
||||||
|
- Changed EventHook name storage to use AMTL AString (bug 6188).
|
||||||
|
- Replaced SH List usages in game extensions with AMTL variants (PR 23).
|
||||||
|
- Replaced SourceHook list usages in clientprefs with AMTL (PR 25).
|
||||||
|
- Changed floating-point operations to use SSE when available (bug 5841).
|
||||||
|
- Moved tracker related opcodes entirely to C++.
|
||||||
|
- Statically align the stack at function boundaries (bug 5842).
|
||||||
|
- Removed InfoVars, reassigned DAT from EBP to ESI to preserve C++ stacktraces in JIT code (5844).
|
||||||
|
- Fixed dereferencing potential null pointer in CPlugin::GetProperty (bug 5725).
|
||||||
|
- Fixed memory corruption when parsing natives. (bug 5840).
|
||||||
|
- Fixed some memory errors (bug 5904).
|
||||||
|
- Fixed unaligned memory access in spcomp.
|
||||||
|
- Move versioning to a static library to improve trivial build speed (bug 5997).
|
||||||
|
- Added many missing handle security checks (bug 5595).
|
||||||
|
- Made GetEntityClassname get and cache m_iClassname offset from worldspawn for ents not having it in datadesc (bug 5654).
|
||||||
|
- Cache m_iEFlags offset for datamaps dump instead of getting for each ent (bug 5657).
|
||||||
|
- Fixed mismatched delete [] on thunks in JIT CompData dtor (bug 5639).
|
||||||
|
- Fixed various memory issues. (bug 5766).
|
||||||
|
- Added reference counting and use it for CGameConfig and IDatabase (bug 5876).
|
||||||
|
- Added atomic reference counting and port DBI (bug 5876).
|
||||||
|
- Replaced usages of deprecated Sourcehook Add/Remove macros (bug 5631).
|
||||||
|
- Fixed SDKHooks hook ent validation missing first datatable name (bug 5881).
|
||||||
|
- Fixed case where bots leave server without disconnect notice (hibernation) (PR 20).
|
||||||
|
- Changed FindConVar to utilize convar cache for improved performance (PR 27) (VoiDeD).
|
||||||
|
- Gave define value (of 1) to PLATFORM defs to match the same-name defs in some SDKs (PR 10).
|
||||||
|
- Wrapped ClientPrintf into IGamePlayer (bug 6021).
|
||||||
|
- Consolidated FileExists usage in logic bin (bug 5931).
|
||||||
|
- Removed hardcoded paths to tier0/vstdlib in ICommandLine lookup.
|
||||||
|
- Use updated IServerTools iface on TF2 for getting tempent list and FindEntityByClassname (PR 33).
|
||||||
|
- Added early exit in entity output detour if entity has no classname to prevent crash.
|
||||||
|
- Updated SDKTools entity output functions to use core's GetEntityClassname instead of own (PR 39).
|
||||||
|
- Consolidated SDKTools entity factory lookups.
|
||||||
|
- Changed SDKTools PlayerRunCmd to a global vtable hook to improve performance (bug 6051).
|
||||||
|
- Changed SDKHooks to use global vtable hooks to improve performance (bug 6070).
|
||||||
|
- Added client validation checks to EmitSound SoundsHooks (bug 5873).
|
||||||
|
- Added missing meta results to some pre-hooks in SDKHooks.
|
||||||
|
- Replaced magic numbers for sm_show_activity with named constants (PR 14).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.5.3 [2014-03-22]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.5.3_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated support for CS:GO after multiple breaking game updates.
|
||||||
|
- Updated gamedata support for GoldenEye: Source (Peace-Maker).
|
||||||
|
- Fixed crash on SDKHooks extension load in Alien Swarm (bug 6059).
|
||||||
|
- Fixed memory leak from unmanaged forwards never being freed (bug 6025).
|
||||||
|
- Fixed possible crash when unloading the CStrike extension.
|
||||||
|
- Fixed crash in SDKHooks Reload post-hook (Peace-Maker).
|
||||||
|
- Fixed FakeClientCommandEx always leaking memory (bug 5678).
|
||||||
|
- Fixed extra entity networking occuring with SetEntProp natives on some games.
|
||||||
|
- Fixed being able to nominate same map multiple times (bug 5109).
|
||||||
|
- Fixed spurious FindEntityByClassname error being logged on some games and platforms.
|
||||||
|
- Fixed an Anti-Flood bypass exploit (bug 5394).
|
||||||
|
- Removed part of Addresses gamedata error handling which could cause false errors to be logged (bug 6044).
|
||||||
|
- Fixed mapchooser not resetting nominations count when clearing nominations list (bug 5359).
|
||||||
|
- Improved performances of client convar query handling (bug 6003).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Added GiveAmmo native to SDKTools (bug 6039) (Peace-Maker).
|
||||||
|
- Added SQL_SetCharset native to (re)set charset even after reconnect (bug 5786) (Peace-Maker).
|
||||||
|
- Added support for entity references in SDKHooks natives (bug 6069).
|
||||||
|
- Added support for server passwords to DisplayAskConnectBox stock (bug 5984) (FlaminSarge).
|
||||||
|
- Renamed SortFunc2D parameters to match documentation (bug 6014) (Peace-Maker).
|
||||||
|
- Fixed param order in AddToTopMenu function doc (bug 6035) (Peace-Maker).
|
||||||
|
- Added |any| tag to WritePackCell and ReadPackCell native param/return values (bug 6001).
|
||||||
|
- Updated SDKHook_TakeDamage native for game updates.
|
||||||
|
- Added default infinite value for TF2_AddCondition duration.
|
||||||
|
- Added support for conditions >= 64 in TF2_OnConditionAdded/Removed (bug 5565, bug 5976) (FlaminSarge).
|
||||||
|
- Updated TFCond and TF customkill enum values (bug 6012) (FlaminSarge).
|
||||||
|
- Fixed regression causing incorrect return and inability to block in TF2_OnCalcIsAttackCritical forward.
|
||||||
|
- Fixed TE_* natives operating on incorrect data for some tempents (bug 6072).
|
||||||
|
- Fixed CS_AliasToWeaponID not returning a valid weaponID for cz75a.
|
||||||
|
- Fixed CS_GetWeaponPrice returning incorrect value for M4A1 in CS:GO (bug 6045).
|
||||||
|
- Increased max gamedata byte signature length.
|
||||||
|
- Ported SM build scripts to AMBuild2 (bug 5997).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.5.2 [2013-10-29]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.5.2_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated gamedata support for TF2, CS:S, CS:GO, and HL2:DM.
|
||||||
|
- Fixed crash from regression in SDKTools SetClientListening hook refcounting (bug 5956) (KyleS).
|
||||||
|
- Fixed potential crash when having maps with format characters in name.
|
||||||
|
- Fixed some nextmap issues with long map names.
|
||||||
|
- SDKTools no longer requires gamedata for sm_dump_datamaps on TF2, CS:S, HL2:DM, and DoD:S (bug 5968).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Updated TFCond and TF custom dmg enums.
|
||||||
|
- Updated TF2 critical hit detection logic in TF2_OnCalcIsAttackCritical to handle more cases, including when criticals are disabled (bug 5894).
|
||||||
|
- Fixed GetEngineVersion native returning a bad value when running on MM:S 1.9.x or earlier (bug 5697).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.5.1 [2013-09-10]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.5.1_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated gamedata support for TF2.
|
||||||
|
- Added missing DispatchKeyValue gamedata for HL2 CTF (bug 5114) (peace-maker).
|
||||||
|
- Fixed translations not being loaded if identifier was not two or three characters (fixes Portuguese) (bug 5888).
|
||||||
|
- Fixed runoff voting occurring when receiving the exact number of required votes (bug 5890).
|
||||||
|
- Fixed reserve slot plugin hiding too many slots on Orangebox gamesif SourceTV and/or Replay are present (bug 5499).
|
||||||
|
- Fixed some crashes in TF2 and unexpected behavior in all games with SDKHook_TakeDamage due to uninitialized var.
|
||||||
|
- Fixed attempted triggers from gagged users displaying in chat (bug 5918).
|
||||||
|
- Fixed errors in Italian translation (Oktober).
|
||||||
|
- Added Norwegian translation (checkster).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Added CS_UpdateClientModel native to CStrike extension for CS:S and CS:GO (bug 5905) (Drifter).
|
||||||
|
- Fixed setting weapon param in SDKHook_TakeDamage overwriting attacker instead of setting weapon (bug 5911) (KyleS)
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.5.0 [2013-08-25]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.5.0_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Added support for Counter-Strike: Global Offensive (bug 5299, bug 5579).
|
||||||
|
- Split CS:S, TF2, DoD:S, HL2:DM, and ND to separate binaries (bug 5370, bug 5813).
|
||||||
|
- Added support for runoff voting in mapchooser (bug 4218).
|
||||||
|
- Added option to require Steam validation before granting admin access (bug 4837) (VoiDeD).
|
||||||
|
- Added localization support for many more core and base plugin messages (bug 5120, bug 5146).
|
||||||
|
- Added the ability to override RegConsoleCommand-created commands (bug 5199).
|
||||||
|
- Added support for "fuzzy" (partial) map names in map-related natives and cmds for L4D and later (bug 5599).
|
||||||
|
- Updated Reserved Slots to use max humans as max count (bug 5444).
|
||||||
|
- Added support for custom maxitems on radio menus (bug 5371).
|
||||||
|
- Improved console config editing (bug 5470).
|
||||||
|
- Increased map name buffer sizes in mapchooser to better account for nested maps (bug 5609) (Peace-Maker).
|
||||||
|
- Fixed JIT conflicts with SELinux (bug 5581).
|
||||||
|
- Added logged error when PlayerRunCommand offset lookup fails (bug 5535) (GoD-Tony).
|
||||||
|
- Fixed double print when sending psay to self (bug 5649) (Peace-Maker).
|
||||||
|
- Fixed check against uninitialized string in extension loader (bug 5546) (KyleS).
|
||||||
|
- Fixed possible runtime errors in basetriggers for not-ingame clients (bug 5191) (Peace-Maker).
|
||||||
|
- Check all possible mapcycle paths on newer orangebox games (bug 5719).
|
||||||
|
- Fixed ReadMapList not seeing maps in all valve search paths (bug 5715) (VoiDeD).
|
||||||
|
- Fixed typo in too-many-params native error message (Peace-Maker).
|
||||||
|
- Fixed various issues in clientprefs (bug 5538) (KyleS).
|
||||||
|
- Removed debug printout from PerformGravity (bug 5679) (KyleS).
|
||||||
|
- Fixed broken translating in some plugins and natives (bug 5612) (KyleS).
|
||||||
|
- Fixed issues with COMMAND_FILTER_NO_BOTS and @bots multi-target.
|
||||||
|
- Fixed crash in SDKHooks when throwing bad ent type error on logical ent (KyleS).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Added support for CS:GO to the CStrike extension (bug 5299) (Drifter).
|
||||||
|
- Added support for new protobuf usermessages used in newer games (bug 5579, bug 5588, bug 5590, bug 5633).
|
||||||
|
- Added latest SDKHooks version as first-party extension.
|
||||||
|
- Updated SQLite to version 3.7.15.1 (bug 5235).
|
||||||
|
- Added natives for changing team score and mvp stars on CSS/CSGO (bug 5295) (Drifter).
|
||||||
|
- Added global pre and post forwards for client chat (bug 5394) (KyleS).
|
||||||
|
- Added TF2_CanPlayerTeleport forward to the TF2 game extension (bug 5283) (VoiDeD).
|
||||||
|
- Added GetEntityAddress native (bug 5269) (ProdigySim).
|
||||||
|
- Added more parameters to PlayerRunCommand forward (bug 5346) (GoD-Tony).
|
||||||
|
- Added forwards to basecomm plugin (bug 5466) (Drifter).
|
||||||
|
- Added symbol lookup support to gamedata on Windows (bug 5511) (GoD-Tony).
|
||||||
|
- Exposed GetLanguageInfo in ITranslator interface (bug 5249) (VoiDeD).
|
||||||
|
- Increase maximum .sp line length to 4095 characters. (bug 5347) (theY4Kman).
|
||||||
|
- Improved netprop dump output (bug 5471).
|
||||||
|
- Added int64 typename to netprop dumps (bug 5655).
|
||||||
|
- Added GetMaxHumanPlayers native exposing IServerGameClients func (bug 5551).
|
||||||
|
- Added WeaponIDToAlias native to CStrike extension (bug 5460) (KyleS).
|
||||||
|
- Fixed OnLibraryAdded/Removed not being called in all plugins (bug 5431).
|
||||||
|
- Made thread worker processing limits configurable at runtime (bug 5326).
|
||||||
|
- Added support in TF2 ext for detection of player conds >= 64 (bug 5565).
|
||||||
|
- Updated button defines in entity_prop_stocks (bug 5564).
|
||||||
|
- Added GetPlayerResourceEntity to SDKTools to replace old, semi-broken TF2-only version (bug 5491).
|
||||||
|
- Exposed third parameter of TF2's AddCond in TF2_AddCondition (bug 5641) (FlaminSarge).
|
||||||
|
- Added GetSteamAccountID function to IPlayerHelpers and native for sp (bug 5548) (KyleS).
|
||||||
|
- Added ISDKHooks interface with entity listeners (bug 5602) (GoD-Tony).
|
||||||
|
- Added file upload support to webternet extension.
|
||||||
|
- Added more alternative names for TFClass_Heavy (bug 5338) (Afronanny).
|
||||||
|
- Throw error instead of crash when calling SetTeamScore between maps (bug 5718) (KyleS).
|
||||||
|
- Fixed clients not being marked as in kick queue in some cases (bug 5746) (SystematicMania).
|
||||||
|
- Made compile.sh set working dir to own dir (bug 5710) (KyleS).
|
||||||
|
- Added CS_IsValidWeaponID native and validity checks to other natives (bug 5566) (Drifter).
|
||||||
|
- Numerous code documentation fixups (bug 5720) (Tsunami).
|
||||||
|
- Fixed cmd listener callback return behavior to match func doc (bug 5882).
|
||||||
|
|
||||||
|
Internal Changes:
|
||||||
|
|
||||||
|
- Fixed handle misuse in clientprefs plugin (bug 5805) (KyleS).
|
||||||
|
- Removed call to getchar() in debug build of compiler (bug 5626) (KyleS).
|
||||||
|
- Fixed instability issues with cloned handles (bug 5245, bug 5240) (KyleS).
|
||||||
|
- Changed extension unload order to avoid exposing finalization window (bug 5556) (KyleS).
|
||||||
|
- Call OnPluginEnd before finalizer hooks have run (bug 4519).
|
||||||
|
- Fixed potential for reading out of library bounds in MemoryUtils::FindPattern.
|
||||||
|
- Fixed typo in TF2 ext asm.c causing accidental assignment instead of compare.
|
||||||
|
- Overhauled versioning information (bug 5453).
|
||||||
|
- Changed from RemoveEdict to using the Kill input for TF2_RemoveWeapon.
|
||||||
|
- Fixed accidental assignment in each of SDKTools and sp compiler (bug 5745) (KyleS).
|
||||||
|
- Fixed potential deadlock in HandleSystem::TryAndFreeSomeHandles (bug 5665) (KyleS).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.4.7 [2013-02-06]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.7_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM).
|
||||||
|
- Updated gamedata for Left 4 Dead 2, Nuclear Dawn, No More Room in Hell, Zombie Panic Source, CSPromod, GoldenEye Source, Synergy, The Hidden, and PVKII.
|
||||||
|
- Added system to block malware or illegal plugins (bug 5289).
|
||||||
|
- Fixed a potential crash when a bad entity index is passed to certain functions (bug 5539) (KyleS).
|
||||||
|
- Added an error message for when auto plugin configs fail to be created due to write error (bug 5465) (Drifter).
|
||||||
|
- Fixed an issue where a malformed plugin could cause crashes (bug 5478).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Added new values to the TFCond TF2 conditions enum (bug 5537) (FlaminSarge).
|
||||||
|
- Updated TFHoliday TF2 holidays enum (bug 5526) (Powerlord).
|
||||||
|
- Fixed regression in SourceMod 1.3.0 causing GetEntPropEnt, GetEntDataEnt2, and GameRules_GetPropEnt to possibly return stale (incorrect) entity indexes in place of -1.
|
||||||
|
- Added support for < 32-bit unsigned sign extension to GameRules_GetProp lookup (already in GetEntProp since SM 1.4.0).
|
||||||
|
- Fixed < 32-bit unsigned sign extension in GetEntProp not being applied for array prop elements (bug 5591).
|
||||||
|
- Fixed value size auto-detection in GetEntProp and GameRules_GetProp for ep2v's new SPROP_VARINT sendprops.
|
||||||
|
- Fixed Sort_Random sort type not including first value in array sorting functions (bug 4292) (Peace-Maker).
|
||||||
|
- Fixed GameRules_SetPropVector writing data to unexpected addresses instead of to the gamerules proxy entity (bug 5592) (ProdigySim).
|
||||||
|
- Fixed VoteMenuToAll stock adding bots to list (bug 5253 (VoiDeD).
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
SourceMod 1.4.6 [2012-09-04]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.6_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Fixed extraneous errors resulting from a bug in 1.4.5.
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
SourceMod 1.4.5 [2012-09-03]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.5_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Updated Nuclear Dawn, Dino D-Day, and Zombie Panic gamedata.
|
||||||
|
- Added compatibility for running on Metamod:Source 1.9.0.
|
||||||
|
- Fixed very minor memory leaks in CStrike extension (bug 5456) (KyleS).
|
||||||
|
- Fixed crash from plugins accessing netprops too early (bug 5297) (KyleS).
|
||||||
|
- Fixed crash from plugins trying to access nested datadesc members (bug 5446).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Added new TF2 weapon and custom dmg defines.
|
||||||
|
- Added new TF2 TFHoliday value (bug 5436) (Powerlord).
|
||||||
|
- Fixed IClientListener::InterceptClientConnect not being able to properly block connections (bug 5461) (PimpinJuice).
|
||||||
|
- Fixed PrepSDKCall_SetSignature native not working with symbol names on L4D2 linux (bug 5440).
|
||||||
|
- Fixed resolution of GetProfilerTime native on non-Windows platforms.
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.4.4 [2012-07-03]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.4_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest Source 2009 engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Updated Nuclear Dawn gamedata.
|
||||||
|
- Fixed a crash that could occur when selecting an option on a clientprefs prefab menu (bug 5374).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Added new TF2 weapon and custom dmg defines.
|
||||||
|
- Added new TF2 TFHoliday value (bug 5364) (Powerlord).
|
||||||
|
- Updated sample extension to properly fill ninvoke with INativeInvoker ptr (bug 5340) (Afronanny).
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.4.3 [2012-06-09]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.3_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Made clientprefs attempt to reconnect to the database on map change (bug 4745).
|
||||||
|
- Log functions now respect sv_logecho (bug 5135).
|
||||||
|
- Fixed client console vote output (bug 5290, bug 5205) (FlaminSarge).
|
||||||
|
- Fixed error when reloading dependant plugins using aliased natives (bug 5302).
|
||||||
|
- Fixed intermittent crash when looking for an invalid signature (bug 5301).
|
||||||
|
- Fixed possible crash when reloading a plugin with an invalid binary (bug 5288).
|
||||||
|
- Exposed extensions list to clients (bug 5221) (VoiDeD).
|
||||||
|
- Fixed intermittent crashes in clientprefs (bug 4660).
|
||||||
|
- Fixed crash when passing an invalid entity reference to ReferenceToEntity (bug 5330).
|
||||||
|
- Fixed cstrike extension crash on shutdown (bug 5328).
|
||||||
|
- Lowered threading API think time to 20ms, making threaded MySQL queries complete faster (bug 4733).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Fixed client serials not being unique on Windows (bug 5285).
|
||||||
|
- Fixed broken SourceTV detection on L4D1 (bug 5216).
|
||||||
|
- Fixed Float negation operator (bug 5292).
|
||||||
|
- Updated TF2 condition defines (bug 5259) (FlaminSarge).
|
||||||
|
- Adding missing SetMenuNoVoteButton native declaration (bug 4522) (GoD-Tony).
|
||||||
|
- Fixed erroneous const-qualification of name param of GetAdminUsername (bug 5267).
|
||||||
|
- Added GetGameTickCount native (bug 5209) (GoD-Tony).
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.4.2 [2011-04-13]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.2_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Fixed regression in SourceMod 1.4.0 causing SM to cause load errors on The Ship (bug 5216).
|
||||||
|
- Fixed toggling and player lag issues with sm_drug command (bugs 5217, 5218) (FlaminSarge).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Updated TF2-specific defines and enums (bug 5194).
|
||||||
|
- Fixed StoreToAddress always writing 32 bits and throwing an error (bug 5248) (ProdigySim).
|
||||||
|
- Fixed crash with StoreToAddress if memory wasn't writable (bug 5252) (Dr!fter).
|
||||||
|
- Fixed return value of VoteMenuToAll (bug 5254) (VoiDeD).
|
||||||
|
- Fixed bug in command lower-casing API guarantee
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.4.1 [2011-12-07]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.1_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Added gamedata for Adrenaline Gamer 2 and No More Room in Hell.
|
||||||
|
- Fixed "not connected" error in reserve slots plugin (bug 5158) (ostrel).
|
||||||
|
- Fixed ff trigger output printing to all in triggerer's language (rather than viewer's language) (bug 5161).
|
||||||
|
- Fixed typo in one of basebans ban reasons (bug 5188).
|
||||||
|
- Fixed formatting error in Swedish "Vote Count" phrase (bug 5174).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Fixed sp MaxClients not being updated on map changes after load (bug 5160).
|
||||||
|
- Removed GLIBC_2.7 dependency from spcomp.
|
||||||
|
- Increased buffer for sm_rcon command to fit larger responses (bug 5169).
|
||||||
|
- BaseComm now properly registers a library allowing it to be required by other plugins (bug 5156).
|
||||||
|
- Fixed TFHoliday enum values (bug 5155).
|
||||||
|
- Updated TF2_OnIsHolidayActive ret behavior to match doc (bug 5155).
|
||||||
|
- Added new TF2 deathflag and dmg custom defines (bug 5157).
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.4.0 [2011-10-28]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.4.0_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Added support for Max OS X (bug 4392).
|
||||||
|
- Added support for Bloody Good Time (bug 4780).
|
||||||
|
- Added support for E.Y.E Divine Cybermancy (bug 5035).
|
||||||
|
- Added gamedata for Nuclear Dawn.
|
||||||
|
- Added gamedata for International Online Soccer: Source (bug 5019).
|
||||||
|
- Added gamedata for Half-Life 2 Capture the Flag (bug 5114).
|
||||||
|
- Updated mapchooser and other base plugins with Nuclear Dawn specific fixes (bug 5117).
|
||||||
|
- Fixed ServerLang value not being read properly on startup (bug 4675).
|
||||||
|
- Added support for aliases in languages.cfg (bug 4858).
|
||||||
|
- Added output display to sm_rcon command (bug 5018).
|
||||||
|
- Flood protection bypass access can now be overridden with command name sm_flood_access (bug 4584).
|
||||||
|
- Added a reset argument to sm cvars command to revset cvar values to default (bug 5043).
|
||||||
|
- Fixed incorrect language identifiers for Chinese (both Trad. and Simplified) and Brazilian Portuguese not matching cl_language values (bug 5067).
|
||||||
|
- Added translation support for Bulgarian (bg).
|
||||||
|
- Fixed incorrect number of slots being hidden for reserve with sm_hideslots on Source 2009 with SourceTV or replay (bug 5094).
|
||||||
|
- sm_hideslots changes now take effect immediately instead of waiting until a client joins or leaves (bug 5094).
|
||||||
|
- Fixed sv_visiblemaxplayers getting stuck at previous max clients in some cases with reserves and SourceTV or replay (bug 5094).
|
||||||
|
- Removed error logging if an optional extension is not found (bug 5112).
|
||||||
|
- Fixed bots with semicolon in name being unkickable (bug 5120).
|
||||||
|
- Changed strings in ice-related funcommands to be translatable (bug 4540).
|
||||||
|
- Changed Bintools extension to use a single build for every engine (bug 4548).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
- Provided native interface for basecomm (bug 2594).
|
||||||
|
- Client language detection is too late. (bug 3714) (Tony A. "GoD-Tony").
|
||||||
|
- Added ServerCommandEx native to execute server command and retrieve output (bug 3873).
|
||||||
|
- Added ability to update clientprefs cookies values on clients not currently connected (bug 3882) (databomb).
|
||||||
|
- Added library "matchmaking_ds" support to gamedata lookups (bug 4158).
|
||||||
|
- Rooted menu handles to callbacks (bug 4353).
|
||||||
|
- Fixed corner cases with ExplodeString (bug 4629). (Michael "LumiStance").
|
||||||
|
- Fixed return omission with else-after-return (bug 4852).
|
||||||
|
- Added OnConditionAdded and OnConditionRemoved forwards to TF2 extension (bug 4851).
|
||||||
|
- Added new natives and forward to the cstrike extension (bug 4732, bug 4985) (Dr!fter).
|
||||||
|
- Added WaitingForPlayers forwards to the TF2 extension (bug 4704) (CrimsonGT).
|
||||||
|
- Updated and added more TF2 condition, weapon, and damagecustom defines (multiple bug#s).
|
||||||
|
- Fixed TF2_RemoveCondition not always removing conditions (bug 4981).
|
||||||
|
- Fixed MaxClients not being updated correctly in some places with SourceTV or replay active (bug 4986).
|
||||||
|
- Fixed some vars not being marked for init on first compile pass (bug 4643).
|
||||||
|
- Increased symbol name limit to 63 characters (bug 4564) (javalia).
|
||||||
|
- Fixed crash when dynamic arrays run out of memory (bug 4632).
|
||||||
|
- Fixed a crash that could happen from looking up out-of-bounds edict or entity indexes (bug 5080).
|
||||||
|
- Fixed client serials not getting cleared on disconnect (bug 5121).
|
||||||
|
- Added error on declaring arrays that the compiler is too buggy to handle (bug 4977).
|
||||||
|
- Removed reliance on gamedata for multiple SDKTools functions in ep2 and later (bug 4899).
|
||||||
|
- Added InvalidateClient and ReconnectClient natives to SDKTools (bug 4931) (Brian "Afronanny" Simon).
|
||||||
|
- Added ability to lookup and set values on the gamerules class (bug 4983.
|
||||||
|
- BaseComm now uses AddCommandListener for chat hooks (bug 4991).
|
||||||
|
- Fixed shutdown bug in SDKTools (bug 5063).
|
||||||
|
- Fixed MM-enabled extensions continuing to load after failing MM attach (bug 5042).
|
||||||
|
- Added GetDistGainFromSoundLevel native to SDKTools (bug 5066) (javalia).
|
||||||
|
- Added CheckAccess native to check an AdminId's command access (bug 5083).
|
||||||
|
- Fixed GetEntProp not sign-extending unsigned values less than 32 bits (bug 5105).
|
||||||
|
- Fixed crashing when calling CreateEntityByName or CreateFakeClient when no map is running (now errors) (bug 5119).
|
||||||
|
- Fixed erring in kick function (e. bad translation) causing client to become unkickable until disconnect (bug 5120).
|
||||||
|
- Fixed KickClientEx not immediately kicking client if client was in kick queue (bug 5120).
|
||||||
|
- Added IsClientSourceTV and IsClientReplay natives (bug 5124).
|
||||||
|
- Added support for getting and setting individual array elements with Get/Set EntProp functions (bug 4160).
|
||||||
|
- Added support for threaded query handles to SQL_GetInsertId and SQL_GetAffectedRows (bug 4699) (Nephyrin).
|
||||||
|
- Added a GetGameRules function to ISDKTools for extensions to easily get the GameRules class pointer (bug 4707).
|
||||||
|
- Added GetMessageName to IUserMessages (bug 4573) (Zach "theY4Kman" Kanzler)
|
||||||
|
- Added HintTextMsg to IGameHelpers (bug 4950).
|
||||||
|
- Added ProcessTargetString simple filter API (bug 4404).
|
||||||
|
- Moved much functionality from core bins to logic bin (bug 4406, bug 4402).
|
||||||
|
- Fixed bogus asserts in sp compiler (bug 4486, bug 4487).
|
||||||
|
- Greatly improved sp compiler performance (~5x overall speedup) (bug 3820, bug 4493, bug 4495).
|
||||||
|
- Changed entity output detours to use CDetour (bug 4416).
|
||||||
|
- Enhanced nominations API (bug 4677) (CrimsonGT).
|
||||||
|
- Added Linux support for profiling natives (bug 4927).
|
||||||
|
- Added a new ValveCallType that allows for arbitrary |this| parameters, as well as associated features in gamedata and for reading/writing memory (bug 3520) (Downtown1).
|
||||||
|
- Updated TF2 extension to handle Valve's changes to the "holiday" system (bug 5150).
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.3.8 [2011-06-23]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.3.8_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Updated support for various games, including Garry's Mod, Zombie Panic, and Dino D-Day.
|
||||||
|
- Added gamedata for Eternal Silence.
|
||||||
|
- Fixed libgcc_s.so.1 load error present on some systems (bug 4876).
|
||||||
|
- Handle leak notices now print to error log (in addition fatal log) (bug 4929).
|
||||||
|
- Translator now properly falls back on bad server language (bug 4861).
|
||||||
|
- Fixed invalid client errors from bad MaxClients value when SourceTV is late-loaded (bug 4881).
|
||||||
|
- Fixed crash on plugin unload when two commands exist with same name, different casing (bug 4698).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- Updated TF2 condition defines (bug 4916).
|
||||||
|
- Fixed var names and docs for TF2_MakeBleed native (bug 4928).
|
||||||
|
- Removed compiler double include check (bug 4863).
|
||||||
|
- Fixed plugin compile errors when using GetEntityClassname (bug 4798).
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
SourceMod 1.3.7 [2011-04-15]
|
||||||
|
|
||||||
|
URL: http://wiki.alliedmods.net/SourceMod_1.3.7_Release_Notes
|
||||||
|
|
||||||
|
User Changes:
|
||||||
|
|
||||||
|
- Updated support for latest OrangeBox engine changes (CS:S, DoD:S, TF2, HL2DM, GMod).
|
||||||
|
- Updated support for various games, including Zombie Panic, CS ProMod, Empires, and GoldenEye: Source.
|
||||||
|
- Added gamedata for Dino D-Day.
|
||||||
|
- Fix precedence of voice mute flag versus specific client overrides (bug 4826).
|
||||||
|
- Fix mistaken unhooking of voice hooks (bug 4804).
|
||||||
|
- Fixed graphical glitches with funcommands effects in L4D1 (bug 3486).
|
||||||
|
- Fixed bug in nominations that could cause "Unknown command" error (bug 4797).
|
||||||
|
- Removed tv_enable hook to fix rare max client count issue (bug 4791).
|
||||||
|
- Added missing unhooking of ClientConnect in PlayerManager (bug 4749).
|
||||||
|
- Fixed sm_rtv printing "unknown command" (bug 4730).
|
||||||
|
- Fixed voting crash when client console, chat, and SourceTV are enabled (bug 4676).
|
||||||
|
- Fixed CDetour crash in TF2 extension when last plugin using forward is unloaded (bug 4713).
|
||||||
|
|
||||||
|
Developer Changes:
|
||||||
|
|
||||||
|
- SetEntProp now marks edict state as changed (bug 4855).
|
||||||
|
- Added GetEntityClassname stock (bug 4798).
|
||||||
|
- Fix compiler hanging when #including a directory (bug 4822).
|
||||||
|
- Added GetEntityFlags and SetEntityFlags natives for better cross-engine compatibility. (bug 4809).
|
||||||
|
- Fixed ClientPrefs natives not being marked optional when REQUIRE_EXTENSIONS not defined (bug 4839).
|
||||||
|
- Changed some instances of LogMessage to LogAction (bug 4649).
|
||||||
|
- Added some new language natives (bug 4613).
|
||||||
|
- Fixed SetTeamScore not updating score on client (bug 2736).
|
||||||
|
- Raised MAXPLAYERS from 64 to 65 (bug 4490).
|
||||||
|
- Added and updated many TF2-specific defines in tf2.inc and tf2_stocks.inc.
|
||||||
|
- Fixed TF2_GetPlayerConditionFlags no longer necessarily returning all set flags (bug 4726).
|
||||||
|
- Fixed profiler flush not clearing, added 'report' and 'clear' (bug 4674).
|
||||||
|
- Fixed GetPlayerDecalFile crash on L4D and L4D2 (bug 4729).
|
||||||
|
- Fixed TF2_OnGetHoliday detour no longer firing under all circumstances (bug 4700).
|
||||||
|
- Added TF2_IsPlayerInDuel native to TF2 extension (bug 4695).
|
||||||
|
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
SourceMod 1.3.6 [2010-10-31]
|
||||||
|
|
||||||
|
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]
|
SourceMod 1.2.0 [2009-03-05]
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
"banreasons"
|
||||||
|
{
|
||||||
|
"Abusive" "Abusive"
|
||||||
|
"Racism" "Racism"
|
||||||
|
"General cheating/exploits" "General cheating/exploits"
|
||||||
|
"Wallhack" "Wallhack"
|
||||||
|
"Aimbot" "Aimbot"
|
||||||
|
"Speedhacking" "Speedhacking"
|
||||||
|
"Mic spamming" "Mic spamming"
|
||||||
|
"Admin disrespect" "Admin disrespect"
|
||||||
|
"Camping" "Camping"
|
||||||
|
"Team killing" "Team killing"
|
||||||
|
"Unacceptable Spray" "Unacceptable Spray"
|
||||||
|
"Breaking Server Rules" "Breaking Server Rules"
|
||||||
|
"Other" "Other"
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
//This file unloads all plugins, re-loads a few "safe" ones, and then prevents
|
//This file unloads all plugins, re-loads a few "safe" ones, and then prevents
|
||||||
//any more plugins from being loaded.
|
//any more plugins from being loaded.
|
||||||
sm plugins unload_all
|
sm plugins unload_all
|
||||||
|
sm plugins load_unlock
|
||||||
sm plugins load basebans.smx
|
sm plugins load basebans.smx
|
||||||
sm plugins load basecommands.smx
|
sm plugins load basecommands.smx
|
||||||
sm plugins load admin-flatfile.smx
|
sm plugins load admin-flatfile.smx
|
||||||
|
|||||||
@@ -80,21 +80,21 @@ sm_reserve_type 0
|
|||||||
sm_reserved_slots 0
|
sm_reserved_slots 0
|
||||||
|
|
||||||
// Specifies whether or not reserved slots will be hidden (subtracted from max
|
// 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
|
// Requires: reservedslots.smx
|
||||||
// Default: 0
|
// Default: 0
|
||||||
sm_hide_slots 0
|
sm_hide_slots 0
|
||||||
|
|
||||||
// Specifies whether or not non-admins can send messages to admins using
|
// 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
|
// Requires: basechat.smx
|
||||||
// Default: 1
|
// Default: 1
|
||||||
sm_chat_mode 1
|
sm_chat_mode 1
|
||||||
|
|
||||||
// Specifies whether or not "timeleft" will automaticly be triggered every
|
// 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
|
// Requires: basetriggers.smx
|
||||||
// Default: 0
|
// Default: 0
|
||||||
@@ -107,3 +107,28 @@ sm_timeleft_interval 0
|
|||||||
// Requires: basetriggers.smx
|
// Requires: basetriggers.smx
|
||||||
// Default: 1
|
// Default: 1
|
||||||
sm_trigger_show 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
|
||||||
|
|||||||
@@ -107,4 +107,30 @@
|
|||||||
* Currently this will log details about the gamedata updating process.
|
* Currently this will log details about the gamedata updating process.
|
||||||
*/
|
*/
|
||||||
"DebugSpew" "no"
|
"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" "yes"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a plugin takes too long to execute, hanging or freezing the game server in the process,
|
||||||
|
* SourceMod will attempt to terminate that plugin after the specified timeout length has
|
||||||
|
* passed. You can disable this feature by setting the value to "0".
|
||||||
|
*/
|
||||||
|
"SlowScriptTimeout" "8"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
{
|
{
|
||||||
"driver_default" "mysql"
|
"driver_default" "mysql"
|
||||||
|
|
||||||
|
// When specifying "host", you may use an IP address, a hostname, or a socket file path
|
||||||
|
|
||||||
"default"
|
"default"
|
||||||
{
|
{
|
||||||
"driver" "default"
|
"driver" "default"
|
||||||
|
|||||||
Binary file not shown.
@@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Each sub-section of "Plugins" should have a title which specifies a plugin filename.
|
|
||||||
* Filenames have a wildcard of *. Appending .smx is not required.
|
|
||||||
* If the filename has no explicit path, it will be patched to any sub-path in the plugins folder.
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
* "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:
|
|
||||||
* "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).
|
|
||||||
* See the wiki article "SourceMod Profiler" for more information.
|
|
||||||
* 1 - Profile natives
|
|
||||||
* 2 - Profile callbacks
|
|
||||||
* 4 - Profile internal plugin function calls
|
|
||||||
*/
|
|
||||||
|
|
||||||
"Plugins"
|
|
||||||
{
|
|
||||||
"*"
|
|
||||||
{
|
|
||||||
"pause" "no"
|
|
||||||
"lifetime" "mapsync"
|
|
||||||
|
|
||||||
"Options"
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# vim: set ts=2 sw=2 tw=99 noet:
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
from ambuild2 import run
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
import ambuild
|
||||||
|
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
|
||||||
|
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
|
||||||
|
except:
|
||||||
|
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
||||||
|
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
run = run.PrepareBuild(sourcePath=sys.path[0])
|
||||||
|
run.default_build_folder = 'obj-' + run.target_platform
|
||||||
|
run.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||||
|
help='Root search folder for HL2SDKs')
|
||||||
|
run.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
|
||||||
|
help='Path to MySQL 5')
|
||||||
|
run.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
|
||||||
|
help='Path to Metamod:Source')
|
||||||
|
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.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
|
||||||
|
default=False, help='Dump and upload breakpad symbols')
|
||||||
|
run.Configure()
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
|
import os
|
||||||
|
|
||||||
|
project = SM.HL2Project(builder, 'sourcemod')
|
||||||
|
project.sources += [
|
||||||
|
'MenuStyle_Valve.cpp',
|
||||||
|
'logic_bridge.cpp',
|
||||||
|
'smn_entities.cpp',
|
||||||
|
'sm_stringutil.cpp',
|
||||||
|
'MenuVoting.cpp',
|
||||||
|
'smn_events.cpp',
|
||||||
|
'smn_menus.cpp',
|
||||||
|
'CDataPack.cpp',
|
||||||
|
'frame_hooks.cpp',
|
||||||
|
'smn_nextmap.cpp',
|
||||||
|
'sourcemm_api.cpp',
|
||||||
|
'ChatTriggers.cpp',
|
||||||
|
'smn_player.cpp',
|
||||||
|
'sourcemod.cpp',
|
||||||
|
'concmd_cleaner.cpp',
|
||||||
|
'HalfLife2.cpp',
|
||||||
|
'NextMap.cpp',
|
||||||
|
'ConCmdManager.cpp',
|
||||||
|
'ConVarManager.cpp',
|
||||||
|
'LibrarySys.cpp',
|
||||||
|
'PlayerManager.cpp',
|
||||||
|
'TimerSys.cpp',
|
||||||
|
'CoreConfig.cpp',
|
||||||
|
'Logger.cpp',
|
||||||
|
'smn_halflife.cpp',
|
||||||
|
'smn_console.cpp',
|
||||||
|
'UserMessages.cpp',
|
||||||
|
'MenuManager.cpp',
|
||||||
|
'smn_core.cpp',
|
||||||
|
'smn_hudtext.cpp',
|
||||||
|
'smn_usermsgs.cpp',
|
||||||
|
'MenuStyle_Base.cpp',
|
||||||
|
'smn_keyvalues.cpp',
|
||||||
|
'smn_vector.cpp',
|
||||||
|
'EventManager.cpp',
|
||||||
|
'MenuStyle_Radio.cpp',
|
||||||
|
'sm_autonatives.cpp',
|
||||||
|
'sm_srvcmds.cpp',
|
||||||
|
'ConsoleDetours.cpp'
|
||||||
|
]
|
||||||
|
|
||||||
|
for sdk_name in SM.sdks:
|
||||||
|
sdk = SM.sdks[sdk_name]
|
||||||
|
binary_name = 'sourcemod.' + sdk.ext
|
||||||
|
|
||||||
|
binary = SM.HL2Config(project, binary_name, sdk)
|
||||||
|
compiler = binary.compiler
|
||||||
|
|
||||||
|
if sdk.name == 'csgo':
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
|
||||||
|
]
|
||||||
|
elif sdk.name == 'dota':
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf')
|
||||||
|
]
|
||||||
|
|
||||||
|
if builder.target_platform == 'linux':
|
||||||
|
compiler.postlink += ['-lpthread', '-lrt']
|
||||||
|
|
||||||
|
if sdk.name == 'csgo' or sdk.name == 'dota':
|
||||||
|
if builder.target_platform == 'linux':
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
|
||||||
|
elif builder.target_platform == 'mac':
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||||
|
elif builder.target_platform == 'windows':
|
||||||
|
msvc_ver = compiler.version
|
||||||
|
vs_year = ''
|
||||||
|
if msvc_ver == 1800:
|
||||||
|
vs_year = '2013'
|
||||||
|
elif msvc_ver == 1700:
|
||||||
|
vs_year = '2012'
|
||||||
|
elif msvc_ver == 1600:
|
||||||
|
vs_year = '2010'
|
||||||
|
else:
|
||||||
|
raise Exception('Cannot find libprotobuf for MSVC version "' + compiler.version + '"')
|
||||||
|
|
||||||
|
if 'DEBUG' in compiler.defines:
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||||
|
else:
|
||||||
|
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||||
|
compiler.linkflags.insert(0, binary.Dep(lib_path))
|
||||||
|
|
||||||
|
if sdk.name in ['csgo', 'dota']:
|
||||||
|
binary.sources += ['smn_protobuf.cpp']
|
||||||
|
else:
|
||||||
|
binary.sources += ['smn_bitbuffer.cpp']
|
||||||
|
|
||||||
|
if sdk.name == 'csgo':
|
||||||
|
binary.sources += [
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
||||||
|
]
|
||||||
|
elif sdk.name == 'dota':
|
||||||
|
binary.sources += [
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'networkbasetypes.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'network_connection.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'ai_activity.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'usermessages.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_commonmessages.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessages.pb.cc'),
|
||||||
|
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_usermessage_helpers.cpp'),
|
||||||
|
]
|
||||||
|
|
||||||
|
SM.binaries += builder.Add(project)
|
||||||
|
|
||||||
@@ -44,7 +44,11 @@ public: //IRecipientFilter
|
|||||||
bool IsReliable() const;
|
bool IsReliable() const;
|
||||||
bool IsInitMessage() const;
|
bool IsInitMessage() const;
|
||||||
int GetRecipientCount() const;
|
int GetRecipientCount() const;
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
CEntityIndex GetRecipientIndex(int slot) const;
|
||||||
|
#else
|
||||||
int GetRecipientIndex(int slot) const;
|
int GetRecipientIndex(int slot) const;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
void Initialize(const cell_t *ptr, size_t count);
|
void Initialize(const cell_t *ptr, size_t count);
|
||||||
void SetToReliable(bool isreliable);
|
void SetToReliable(bool isreliable);
|
||||||
@@ -79,13 +83,27 @@ inline int CellRecipientFilter::GetRecipientCount() const
|
|||||||
return m_Size;
|
return m_Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
inline CEntityIndex CellRecipientFilter::GetRecipientIndex(int slot) const
|
||||||
|
#else
|
||||||
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
|
inline int CellRecipientFilter::GetRecipientIndex(int slot) const
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
if ((slot < 0) || (slot >= GetRecipientCount()))
|
if ((slot < 0) || (slot >= GetRecipientCount()))
|
||||||
{
|
{
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
return static_cast<int>(m_Players[slot]);
|
else
|
||||||
|
{
|
||||||
|
ret = static_cast<int>(m_Players[slot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
return CEntityIndex(ret);
|
||||||
|
#else
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
|
inline void CellRecipientFilter::SetToInit(bool isinitmsg)
|
||||||
|
|||||||
+224
-116
@@ -34,38 +34,40 @@
|
|||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "ConCmdManager.h"
|
#include "ConCmdManager.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "Translator.h"
|
|
||||||
#include "HalfLife2.h"
|
#include "HalfLife2.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
#include "sourcemod.h"
|
||||||
|
|
||||||
/* :HACKHACK: We can't SH_DECL here because ConCmdManager.cpp does.
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
* While the OB build only runs on MM:S 1.6.0+ (SH 5+), the older one
|
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||||
* can technically be compiled against any MM:S version after 1.4.2.
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
*/
|
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
|
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||||
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate1<const CCommand &, void>);
|
|
||||||
#else
|
#else
|
||||||
extern bool __SourceHook_FHRemoveConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
# if SH_IMPL_VERSION >= 4
|
||||||
#if SH_IMPL_VERSION >= 5
|
extern int __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||||
extern int __SourceHook_FHAddConCommandDispatch(void *, ISourceHook::AddHookMode, bool, class fastdelegate::FastDelegate0<void>);
|
# else
|
||||||
#elif SH_IMPL_VERSION == 4
|
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||||
extern int __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
# endif
|
||||||
#elif SH_IMPL_VERSION == 3
|
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||||
extern bool __SourceHook_FHAddConCommandDispatch(void *, bool, class fastdelegate::FastDelegate0<void>);
|
#endif
|
||||||
#endif //SH_IMPL_VERSION
|
|
||||||
#endif //SE_ORANGEBOX
|
|
||||||
|
|
||||||
ChatTriggers g_ChatTriggers;
|
ChatTriggers g_ChatTriggers;
|
||||||
bool g_bSupressSilentFails = false;
|
bool g_bSupressSilentFails = false;
|
||||||
|
|
||||||
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
|
ChatTriggers::ChatTriggers() : m_pSayCmd(NULL), m_bWillProcessInPost(false),
|
||||||
m_bTriggerWasSilent(false), m_ReplyTo(SM_REPLY_CONSOLE)
|
m_ReplyTo(SM_REPLY_CONSOLE), m_ArgSBackup(NULL)
|
||||||
{
|
{
|
||||||
m_PubTrigger = sm_strdup("!");
|
m_PubTrigger = sm_strdup("!");
|
||||||
m_PrivTrigger = sm_strdup("/");
|
m_PrivTrigger = sm_strdup("/");
|
||||||
m_PubTriggerSize = 1;
|
m_PubTriggerSize = 1;
|
||||||
m_PrivTriggerSize = 1;
|
m_PrivTriggerSize = 1;
|
||||||
m_bIsChatTrigger = false;
|
m_bIsChatTrigger = false;
|
||||||
|
m_bPluginIgnored = true;
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
m_bIsINS = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatTriggers::~ChatTriggers()
|
ChatTriggers::~ChatTriggers()
|
||||||
@@ -74,6 +76,8 @@ ChatTriggers::~ChatTriggers()
|
|||||||
m_PubTrigger = NULL;
|
m_PubTrigger = NULL;
|
||||||
delete [] m_PrivTrigger;
|
delete [] m_PrivTrigger;
|
||||||
m_PrivTrigger = NULL;
|
m_PrivTrigger = NULL;
|
||||||
|
delete [] m_ArgSBackup;
|
||||||
|
m_ArgSBackup = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
|
ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
|
||||||
@@ -107,13 +111,15 @@ ConfigResult ChatTriggers::OnSourceModConfigChanged(const char *key,
|
|||||||
|
|
||||||
void ChatTriggers::OnSourceModAllInitialized()
|
void ChatTriggers::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
m_pShouldFloodBlock = g_Forwards.CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
|
m_pShouldFloodBlock = forwardsys->CreateForward("OnClientFloodCheck", ET_Event, 1, NULL, Param_Cell);
|
||||||
m_pDidFloodBlock = g_Forwards.CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
|
m_pDidFloodBlock = forwardsys->CreateForward("OnClientFloodResult", ET_Event, 2, NULL, Param_Cell, Param_Cell);
|
||||||
|
m_pOnClientSayCmd = forwardsys->CreateForward("OnClientSayCommand", ET_Event, 3, NULL, Param_Cell, Param_String, Param_String);
|
||||||
|
m_pOnClientSayCmd_Post = forwardsys->CreateForward("OnClientSayCommand_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatTriggers::OnSourceModAllInitialized_Post()
|
void ChatTriggers::OnSourceModAllInitialized_Post()
|
||||||
{
|
{
|
||||||
g_pCorePhrases->AddPhraseFile("antiflood.phrases");
|
logicore.AddCorePhraseFile("antiflood.phrases");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatTriggers::OnSourceModGameInitialized()
|
void ChatTriggers::OnSourceModGameInitialized()
|
||||||
@@ -123,34 +129,76 @@ void ChatTriggers::OnSourceModGameInitialized()
|
|||||||
|
|
||||||
if (m_pSayCmd)
|
if (m_pSayCmd)
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||||
}
|
}
|
||||||
if (m_pSayTeamCmd)
|
if (m_pSayTeamCmd)
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||||
SH_ADD_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayTeamCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
SH_ADD_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
||||||
|
|
||||||
|
if (m_bIsINS)
|
||||||
|
{
|
||||||
|
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()
|
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)
|
if (m_pSayCmd)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Post, true);
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(ConCommand, Dispatch, m_pSayCmd, this, &ChatTriggers::OnSayCommand_Pre, false);
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Forwards.ReleaseForward(m_pShouldFloodBlock);
|
if (m_pSayTeamCmd)
|
||||||
g_Forwards.ReleaseForward(m_pDidFloodBlock);
|
{
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSayTeamCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
if (m_bIsINS && m_pSay2Cmd)
|
||||||
|
{
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSay2Cmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||||
|
}
|
||||||
|
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||||
|
if (m_pSaySquadCmd)
|
||||||
|
{
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Pre), false);
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, m_pSaySquadCmd, SH_MEMBER(this, &ChatTriggers::OnSayCommand_Post), true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
forwardsys->ReleaseForward(m_pShouldFloodBlock);
|
||||||
|
forwardsys->ReleaseForward(m_pDidFloodBlock);
|
||||||
|
forwardsys->ReleaseForward(m_pOnClientSayCmd);
|
||||||
|
forwardsys->ReleaseForward(m_pOnClientSayCmd_Post);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void ChatTriggers::OnSayCommand_Pre(const CCommandContext &context, const CCommand &command)
|
||||||
|
{
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
|
void ChatTriggers::OnSayCommand_Pre(const CCommand &command)
|
||||||
{
|
{
|
||||||
#else
|
#else
|
||||||
@@ -158,48 +206,106 @@ void ChatTriggers::OnSayCommand_Pre()
|
|||||||
{
|
{
|
||||||
CCommand command;
|
CCommand command;
|
||||||
#endif
|
#endif
|
||||||
int client;
|
int client = g_ConCmds.GetCommandClient();
|
||||||
CPlayer *pPlayer;
|
|
||||||
|
|
||||||
client = g_ConCmds.GetCommandClient();
|
|
||||||
m_bIsChatTrigger = false;
|
m_bIsChatTrigger = false;
|
||||||
m_bWasFloodedMessage = false;
|
m_bWasFloodedMessage = false;
|
||||||
|
m_bPluginIgnored = true;
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *args = command.ArgS();
|
const char *args = command.ArgS();
|
||||||
|
|
||||||
if (!args)
|
if (!args)
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_IGNORED);
|
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);
|
||||||
|
size_t len = strlen(args);
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
if (m_bIsINS)
|
||||||
|
{
|
||||||
|
if (strcmp(m_Arg0Backup, "say2") == 0 && len >= 4)
|
||||||
|
{
|
||||||
|
args += 4;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The first pair of quotes are stripped from client say commands, but not console ones.
|
||||||
|
* We do not want the forwards to differ from what is displayed.
|
||||||
|
* So only strip the first pair of quotes from client say commands. */
|
||||||
|
bool is_quoted = false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
!m_bIsINS &&
|
||||||
|
#endif
|
||||||
|
client != 0 && args[0] == '"' && args[len-1] == '"')
|
||||||
|
{
|
||||||
|
/* The server normally won't display empty say commands, but in this case it does.
|
||||||
|
* I don't think it's desired so let's block it. */
|
||||||
|
if (len <= 2)
|
||||||
|
{
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
args++;
|
||||||
|
len--;
|
||||||
|
is_quoted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some? engines strip the last quote when printing the string to chat.
|
||||||
|
* This results in having a double-quoted message passed to the OnClientSayCommand ("message") forward,
|
||||||
|
* but losing the last quote in the OnClientSayCommand_Post ("message) forward.
|
||||||
|
* To compensate this, we copy the args into our own buffer where the engine won't mess with
|
||||||
|
* and strip the quotes. */
|
||||||
|
delete [] m_ArgSBackup;
|
||||||
|
m_ArgSBackup = new char[CCommand::MaxCommandLength()+1];
|
||||||
|
memcpy(m_ArgSBackup, args, len+1);
|
||||||
|
|
||||||
|
/* Strip the quotes from the argument */
|
||||||
|
if (is_quoted)
|
||||||
|
{
|
||||||
|
if (m_ArgSBackup[len-1] == '"')
|
||||||
|
{
|
||||||
|
m_ArgSBackup[--len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The server console cannot do this */
|
||||||
|
if (client == 0)
|
||||||
|
{
|
||||||
|
if (CallOnClientSayCommand(client) >= Pl_Handled)
|
||||||
|
{
|
||||||
|
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 */
|
/* Check if we need to block this message from being sent */
|
||||||
if (ClientIsFlooding(client))
|
if (ClientIsFlooding(client))
|
||||||
{
|
{
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
|
||||||
if (!CoreTranslate(
|
if (!logicore.CoreTranslate(buffer, sizeof(buffer), "%T", 2, NULL, "Flooding the server", &client))
|
||||||
buffer,
|
|
||||||
sizeof(buffer),
|
|
||||||
"%T",
|
|
||||||
2,
|
|
||||||
NULL,
|
|
||||||
"Flooding the server",
|
|
||||||
&client))
|
|
||||||
{
|
|
||||||
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
|
UTIL_Format(buffer, sizeof(buffer), "You are flooding the server!");
|
||||||
}
|
|
||||||
|
|
||||||
/* :TODO: we should probably kick people who spam too much. */
|
/* :TODO: we should probably kick people who spam too much. */
|
||||||
|
|
||||||
@@ -212,62 +318,41 @@ void ChatTriggers::OnSayCommand_Pre()
|
|||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle quoted string sets */
|
|
||||||
bool is_quoted = false;
|
|
||||||
if (args[0] == '"')
|
|
||||||
{
|
|
||||||
args++;
|
|
||||||
is_quoted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_trigger = false;
|
bool is_trigger = false;
|
||||||
bool is_silent = false;
|
bool is_silent = false;
|
||||||
|
|
||||||
/* Check for either trigger */
|
/* Check for either trigger */
|
||||||
if (m_PubTriggerSize && strncmp(args, m_PubTrigger, m_PubTriggerSize) == 0)
|
if (m_PubTriggerSize && strncmp(m_ArgSBackup, m_PubTrigger, m_PubTriggerSize) == 0)
|
||||||
{
|
{
|
||||||
is_trigger = true;
|
is_trigger = true;
|
||||||
args = &args[m_PubTriggerSize];
|
args = &m_ArgSBackup[m_PubTriggerSize];
|
||||||
}
|
}
|
||||||
else if (m_PrivTriggerSize && strncmp(args, m_PrivTrigger, m_PrivTriggerSize) == 0)
|
else if (m_PrivTriggerSize && strncmp(m_ArgSBackup, m_PrivTrigger, m_PrivTriggerSize) == 0)
|
||||||
{
|
{
|
||||||
is_trigger = true;
|
is_trigger = true;
|
||||||
is_silent = true;
|
is_silent = true;
|
||||||
args = &args[m_PrivTriggerSize];
|
args = &m_ArgSBackup[m_PrivTriggerSize];
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_trigger)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if this is actually a command!
|
* Test if this is actually a command!
|
||||||
*/
|
*/
|
||||||
if (!PreProcessTrigger(PEntityOfEntIndex(client), args, is_quoted))
|
if (is_trigger && PreProcessTrigger(PEntityOfEntIndex(client), args))
|
||||||
{
|
{
|
||||||
CPlayer *pPlayer;
|
m_bIsChatTrigger = true;
|
||||||
if (is_silent
|
|
||||||
&& g_bSupressSilentFails
|
/**
|
||||||
&& client != 0
|
* We'll execute it in post.
|
||||||
&& (pPlayer = g_Players.GetPlayerByIndex(client)) != NULL
|
*/
|
||||||
&& pPlayer->GetAdminId() != INVALID_ADMIN_ID)
|
m_bWillProcessInPost = true;
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bIsChatTrigger = true;
|
if (is_silent && (m_bIsChatTrigger || (g_bSupressSilentFails && pPlayer->GetAdminId() != INVALID_ADMIN_ID)))
|
||||||
|
{
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (CallOnClientSayCommand(client) >= Pl_Handled)
|
||||||
* We'll execute it in post.
|
|
||||||
*/
|
|
||||||
m_bWillProcessInPost = true;
|
|
||||||
m_bTriggerWasSilent = is_silent;
|
|
||||||
|
|
||||||
/* If we're silent, block */
|
|
||||||
if (is_silent)
|
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
@@ -276,28 +361,44 @@ void ChatTriggers::OnSayCommand_Pre()
|
|||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void ChatTriggers::OnSayCommand_Post(const CCommandContext &context, const CCommand &command)
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
|
void ChatTriggers::OnSayCommand_Post(const CCommand &command)
|
||||||
#else
|
#else
|
||||||
void ChatTriggers::OnSayCommand_Post()
|
void ChatTriggers::OnSayCommand_Post()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
m_bIsChatTrigger = false;
|
int client = g_ConCmds.GetCommandClient();
|
||||||
m_bWasFloodedMessage = false;
|
|
||||||
if (m_bWillProcessInPost)
|
if (m_bWillProcessInPost)
|
||||||
{
|
{
|
||||||
/* Reset this for re-entrancy */
|
/* Reset this for re-entrancy */
|
||||||
m_bWillProcessInPost = false;
|
m_bWillProcessInPost = false;
|
||||||
|
|
||||||
/* Execute the cached command */
|
/* Execute the cached command */
|
||||||
int client = g_ConCmds.GetCommandClient();
|
|
||||||
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
|
unsigned int old = SetReplyTo(SM_REPLY_CHAT);
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
engine->ClientCommand(client, "%s", m_ToExecute);
|
||||||
|
#else
|
||||||
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
|
serverpluginhelpers->ClientCommand(PEntityOfEntIndex(client), m_ToExecute);
|
||||||
|
#endif
|
||||||
SetReplyTo(old);
|
SetReplyTo(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_bPluginIgnored && 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)
|
bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
||||||
{
|
{
|
||||||
/* Extract a command. This is kind of sloppy. */
|
/* Extract a command. This is kind of sloppy. */
|
||||||
char cmd_buf[64];
|
char cmd_buf[64];
|
||||||
@@ -339,12 +440,12 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepended = true;
|
prepended = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if we need to do extra string manipulation */
|
/* See if we need to do extra string manipulation */
|
||||||
if (is_quoted || prepended)
|
if (prepended)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@@ -355,15 +456,6 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_
|
|||||||
} else {
|
} else {
|
||||||
len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
len = strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we need to strip a quote */
|
|
||||||
if (is_quoted)
|
|
||||||
{
|
|
||||||
if (m_ToExecute[len-1] == '"')
|
|
||||||
{
|
|
||||||
m_ToExecute[--len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
strncopy(m_ToExecute, args, sizeof(m_ToExecute));
|
||||||
}
|
}
|
||||||
@@ -371,6 +463,22 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args, bool is_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cell_t ChatTriggers::CallOnClientSayCommand(int client)
|
||||||
|
{
|
||||||
|
cell_t res = Pl_Continue;
|
||||||
|
if (m_pOnClientSayCmd->GetFunctionCount() != 0)
|
||||||
|
{
|
||||||
|
m_pOnClientSayCmd->PushCell(client);
|
||||||
|
m_pOnClientSayCmd->PushString(m_Arg0Backup);
|
||||||
|
m_pOnClientSayCmd->PushString(m_ArgSBackup);
|
||||||
|
m_pOnClientSayCmd->Execute(&res);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bPluginIgnored = (res >= Pl_Stop);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
|
unsigned int ChatTriggers::SetReplyTo(unsigned int reply)
|
||||||
{
|
{
|
||||||
unsigned int old = m_ReplyTo;
|
unsigned int old = m_ReplyTo;
|
||||||
|
|||||||
+19
-3
@@ -54,7 +54,10 @@ public: //SMGlobalClass
|
|||||||
char *error,
|
char *error,
|
||||||
size_t maxlength);
|
size_t maxlength);
|
||||||
private: //ConCommand
|
private: //ConCommand
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void OnSayCommand_Pre(const CCommandContext &, const CCommand &command);
|
||||||
|
void OnSayCommand_Post(const CCommandContext &, const CCommand &command);
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void OnSayCommand_Pre(const CCommand &command);
|
void OnSayCommand_Pre(const CCommand &command);
|
||||||
void OnSayCommand_Post(const CCommand &command);
|
void OnSayCommand_Post(const CCommand &command);
|
||||||
#else
|
#else
|
||||||
@@ -67,23 +70,36 @@ public:
|
|||||||
bool IsChatTrigger();
|
bool IsChatTrigger();
|
||||||
bool WasFloodedMessage();
|
bool WasFloodedMessage();
|
||||||
private:
|
private:
|
||||||
bool PreProcessTrigger(edict_t *pEdict, const char *args, bool is_quoted);
|
bool PreProcessTrigger(edict_t *pEdict, const char *args);
|
||||||
bool ClientIsFlooding(int client);
|
bool ClientIsFlooding(int client);
|
||||||
|
cell_t CallOnClientSayCommand(int client);
|
||||||
private:
|
private:
|
||||||
ConCommand *m_pSayCmd;
|
ConCommand *m_pSayCmd;
|
||||||
ConCommand *m_pSayTeamCmd;
|
ConCommand *m_pSayTeamCmd;
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
ConCommand *m_pSay2Cmd;
|
||||||
|
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||||
|
ConCommand *m_pSaySquadCmd;
|
||||||
|
#endif
|
||||||
char *m_PubTrigger;
|
char *m_PubTrigger;
|
||||||
size_t m_PubTriggerSize;
|
size_t m_PubTriggerSize;
|
||||||
char *m_PrivTrigger;
|
char *m_PrivTrigger;
|
||||||
size_t m_PrivTriggerSize;
|
size_t m_PrivTriggerSize;
|
||||||
bool m_bWillProcessInPost;
|
bool m_bWillProcessInPost;
|
||||||
bool m_bTriggerWasSilent;
|
|
||||||
bool m_bIsChatTrigger;
|
bool m_bIsChatTrigger;
|
||||||
bool m_bWasFloodedMessage;
|
bool m_bWasFloodedMessage;
|
||||||
|
bool m_bPluginIgnored;
|
||||||
unsigned int m_ReplyTo;
|
unsigned int m_ReplyTo;
|
||||||
char m_ToExecute[300];
|
char m_ToExecute[300];
|
||||||
|
const char *m_Arg0Backup;
|
||||||
|
char *m_ArgSBackup;
|
||||||
IForward *m_pShouldFloodBlock;
|
IForward *m_pShouldFloodBlock;
|
||||||
IForward *m_pDidFloodBlock;
|
IForward *m_pDidFloodBlock;
|
||||||
|
IForward *m_pOnClientSayCmd;
|
||||||
|
IForward *m_pOnClientSayCmd_Post;
|
||||||
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
bool m_bIsINS;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ChatTriggers g_ChatTriggers;
|
extern ChatTriggers g_ChatTriggers;
|
||||||
|
|||||||
+228
-559
File diff suppressed because it is too large
Load Diff
+56
-33
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -34,71 +34,90 @@
|
|||||||
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "ForwardSys.h"
|
#include <IForwardSys.h>
|
||||||
#include "sm_trie.h"
|
|
||||||
#include "sm_memtable.h"
|
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include <IRootConsoleMenu.h>
|
#include <IRootConsoleMenu.h>
|
||||||
#include <IAdminSystem.h>
|
#include <IAdminSystem.h>
|
||||||
#include "concmd_cleaner.h"
|
#include "concmd_cleaner.h"
|
||||||
|
#include <sm_stringhashmap.h>
|
||||||
|
#include <am-utility.h>
|
||||||
|
#include <am-inlinelist.h>
|
||||||
|
#include <am-linkedlist.h>
|
||||||
|
#include <am-refcounting.h>
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
enum CmdType
|
struct CmdHook;
|
||||||
|
struct ConCmdInfo;
|
||||||
|
|
||||||
|
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
||||||
{
|
{
|
||||||
Cmd_Server,
|
ke::LinkedList<CmdHook *> hooks;
|
||||||
Cmd_Console,
|
|
||||||
Cmd_Admin,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AdminCmdInfo
|
struct AdminCmdInfo
|
||||||
{
|
{
|
||||||
AdminCmdInfo()
|
AdminCmdInfo(const ke::Ref<CommandGroup> &group, FlagBits flags)
|
||||||
|
: group(group),
|
||||||
|
flags(flags),
|
||||||
|
eflags(0)
|
||||||
{
|
{
|
||||||
cmdGrpId = -1;
|
|
||||||
flags = 0;
|
|
||||||
eflags = 0;
|
|
||||||
}
|
}
|
||||||
int cmdGrpId; /* index into cmdgroup string table */
|
ke::Ref<CommandGroup> group;
|
||||||
FlagBits flags; /* default flags */
|
FlagBits flags; /* default flags */
|
||||||
FlagBits eflags; /* effective flags */
|
FlagBits eflags; /* effective flags */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CmdHook
|
struct CmdHook : public ke::InlineListNode<CmdHook>
|
||||||
{
|
{
|
||||||
CmdHook()
|
enum Type {
|
||||||
|
Server,
|
||||||
|
Client
|
||||||
|
};
|
||||||
|
|
||||||
|
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description)
|
||||||
|
: type(type),
|
||||||
|
info(cmd),
|
||||||
|
pf(fun),
|
||||||
|
helptext(description)
|
||||||
{
|
{
|
||||||
pf = NULL;
|
|
||||||
pAdmin = NULL;
|
|
||||||
}
|
}
|
||||||
IPluginFunction *pf; /* function hook */
|
|
||||||
String helptext; /* help text */
|
Type type;
|
||||||
AdminCmdInfo *pAdmin; /* admin requirements, if any */
|
ConCmdInfo *info;
|
||||||
|
IPluginFunction *pf; /* function hook */
|
||||||
|
ke::AString helptext; /* help text */
|
||||||
|
ke::AutoPtr<AdminCmdInfo> admin; /* admin requirements, if any */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef ke::InlineList<CmdHook> CmdHookList;
|
||||||
|
|
||||||
struct ConCmdInfo
|
struct ConCmdInfo
|
||||||
{
|
{
|
||||||
ConCmdInfo()
|
ConCmdInfo()
|
||||||
{
|
{
|
||||||
sourceMod = false;
|
sourceMod = false;
|
||||||
pCmd = NULL;
|
pCmd = NULL;
|
||||||
|
eflags = 0;
|
||||||
}
|
}
|
||||||
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
||||||
ConCommand *pCmd; /**< Pointer to the command itself */
|
ConCommand *pCmd; /**< Pointer to the command itself */
|
||||||
List<CmdHook *> srvhooks; /**< Hooks as a server command */
|
CmdHookList hooks; /**< Hook list */
|
||||||
List<CmdHook *> conhooks; /**< Hooks as a console command */
|
FlagBits eflags; /**< Effective admin flags */
|
||||||
AdminCmdInfo admin; /**< Admin info, if any */
|
|
||||||
bool is_admin_set; /**< Whether or not admin info is set */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef List<ConCmdInfo *> ConCmdList;
|
||||||
|
|
||||||
class ConCmdManager :
|
class ConCmdManager :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IRootConsoleCommand,
|
public IRootConsoleCommand,
|
||||||
public IPluginsListener,
|
public IPluginsListener,
|
||||||
public IConCommandTracker
|
public IConCommandTracker
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
friend void CommandCallback(const CCommandContext &context, const CCommand &command);
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
friend void CommandCallback(const CCommand &command);
|
friend void CommandCallback(const CCommand &command);
|
||||||
#else
|
#else
|
||||||
friend void CommandCallback();
|
friend void CommandCallback();
|
||||||
@@ -117,7 +136,6 @@ public: //IConCommandTracker
|
|||||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||||
public:
|
public:
|
||||||
bool AddServerCommand(IPluginFunction *pFunction, const char *name, const char *description, int flags);
|
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,
|
bool AddAdminCommand(IPluginFunction *pFunction,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *group,
|
const char *group,
|
||||||
@@ -128,7 +146,6 @@ public:
|
|||||||
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
|
void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove);
|
||||||
bool LookForSourceModCommand(const char *cmd);
|
bool LookForSourceModCommand(const char *cmd);
|
||||||
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
|
bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags);
|
||||||
bool CheckCommandAccess(int client, const char *cmd, FlagBits flags);
|
|
||||||
private:
|
private:
|
||||||
void InternalDispatch(const CCommand &command);
|
void InternalDispatch(const CCommand &command);
|
||||||
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
|
ResultType RunAdminCommand(ConCmdInfo *pInfo, int client, int args);
|
||||||
@@ -136,9 +153,13 @@ private:
|
|||||||
void SetCommandClient(int client);
|
void SetCommandClient(int client);
|
||||||
void AddToCmdList(ConCmdInfo *info);
|
void AddToCmdList(ConCmdInfo *info);
|
||||||
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool is_read_safe, bool untrack);
|
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool is_read_safe, bool untrack);
|
||||||
void RemoveConCmds(List<CmdHook *> &cmdlist);
|
|
||||||
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
|
|
||||||
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
||||||
|
|
||||||
|
// Case insensitive
|
||||||
|
ConCmdList::iterator FindInList(const char *name);
|
||||||
|
|
||||||
|
// Case sensitive
|
||||||
|
ConCmdInfo *FindInTrie(const char *name);
|
||||||
public:
|
public:
|
||||||
inline int GetCommandClient()
|
inline int GetCommandClient()
|
||||||
{
|
{
|
||||||
@@ -149,13 +170,15 @@ public:
|
|||||||
return m_CmdList;
|
return m_CmdList;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Trie *m_pCmds; /* command lookup */
|
typedef StringHashMap<ke::Ref<CommandGroup> > GroupMap;
|
||||||
Trie *m_pCmdGrps; /* command group lookup */
|
|
||||||
List<ConCmdInfo *> m_CmdList; /* command list */
|
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */
|
||||||
|
GroupMap m_CmdGrps; /* command group map */
|
||||||
|
ConCmdList m_CmdList; /* command list */
|
||||||
int m_CmdClient; /* current client */
|
int m_CmdClient; /* current client */
|
||||||
BaseStringTable m_Strings; /* string table */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ConCmdManager g_ConCmds;
|
extern ConCmdManager g_ConCmds;
|
||||||
|
|
||||||
#endif // _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
#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_ */
|
||||||
|
|
||||||
+181
-64
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -25,40 +25,69 @@
|
|||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ConVarManager.h"
|
#include "ConVarManager.h"
|
||||||
#include "HalfLife2.h"
|
#include "HalfLife2.h"
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "ForwardSys.h"
|
|
||||||
#include "HandleSys.h"
|
|
||||||
#include "sm_srvcmds.h"
|
#include "sm_srvcmds.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include <sm_trie_tpl.h>
|
#include <sm_namehashset.h>
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
ConVarManager g_ConVarManager;
|
ConVarManager g_ConVarManager;
|
||||||
|
|
||||||
#if SOURCE_ENGINE <= SE_DARKMESSIAH
|
|
||||||
#define CallGlobalChangeCallbacks CallGlobalChangeCallback
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
|
SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float);
|
||||||
#else
|
#else
|
||||||
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *);
|
SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
|
||||||
|
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, CEntityIndex, EQueryCvarValueStatus, const char *, const char *);
|
||||||
|
#elif SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
SH_DECL_HOOK5_void(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 *);
|
SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
||||||
typedef List<const ConVar *> ConVarList;
|
typedef List<const ConVar *> ConVarList;
|
||||||
KTrie<ConVarInfo *> convar_cache;
|
NameHashSet<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)
|
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
|
||||||
{
|
{
|
||||||
@@ -78,7 +107,7 @@ void ConVarManager::OnSourceModStartup(bool late)
|
|||||||
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
||||||
|
|
||||||
/* Create the 'ConVar' handle type */
|
/* Create the 'ConVar' handle type */
|
||||||
m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
m_ConVarType = handlesys->CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVarManager::OnSourceModAllInitialized()
|
void ConVarManager::OnSourceModAllInitialized()
|
||||||
@@ -89,12 +118,20 @@ void ConVarManager::OnSourceModAllInitialized()
|
|||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
if (g_SMAPI->GetGameDLLVersion() >= 6)
|
if (g_SMAPI->GetGameDLLVersion() >= 6)
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
SH_ADD_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||||
m_bIsDLLQueryHooked = true;
|
m_bIsDLLQueryHooked = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
|
g_Players.AddClientListener(this);
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
|
SH_ADD_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
|
||||||
|
#else
|
||||||
|
SH_ADD_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
scripts->AddPluginsListener(this);
|
||||||
|
|
||||||
/* Add the 'convars' option to the 'sm' console command */
|
/* Add the 'convars' option to the 'sm' console command */
|
||||||
g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
|
g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
|
||||||
@@ -112,10 +149,10 @@ void ConVarManager::OnSourceModShutdown()
|
|||||||
|
|
||||||
iter = m_ConVars.erase(iter);
|
iter = m_ConVars.erase(iter);
|
||||||
|
|
||||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
handlesys->FreeHandle(pInfo->handle, &sec);
|
||||||
if (pInfo->pChangeForward != NULL)
|
if (pInfo->pChangeForward != NULL)
|
||||||
{
|
{
|
||||||
g_Forwards.ReleaseForward(pInfo->pChangeForward);
|
forwardsys->ReleaseForward(pInfo->pChangeForward);
|
||||||
}
|
}
|
||||||
if (pInfo->sourceMod)
|
if (pInfo->sourceMod)
|
||||||
{
|
{
|
||||||
@@ -147,23 +184,33 @@ void ConVarManager::OnSourceModShutdown()
|
|||||||
/* Unhook things */
|
/* Unhook things */
|
||||||
if (m_bIsDLLQueryHooked)
|
if (m_bIsDLLQueryHooked)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
SH_REMOVE_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||||
m_bIsDLLQueryHooked = false;
|
m_bIsDLLQueryHooked = false;
|
||||||
}
|
}
|
||||||
else if (m_bIsVSPQueryHooked)
|
else if (m_bIsVSPQueryHooked)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
#if SOURCE_ENGINE != SE_DOTA
|
||||||
|
SH_REMOVE_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||||
|
#endif
|
||||||
m_bIsVSPQueryHooked = false;
|
m_bIsVSPQueryHooked = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SH_REMOVE_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false);
|
g_Players.RemoveClientListener(this);
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
|
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false);
|
||||||
|
#else
|
||||||
|
SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Remove the 'convars' option from the 'sm' console command */
|
/* Remove the 'convars' option from the 'sm' console command */
|
||||||
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
|
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
|
||||||
|
|
||||||
|
scripts->RemovePluginsListener(this);
|
||||||
|
|
||||||
/* Remove the 'ConVar' handle type */
|
/* Remove the 'ConVar' handle type */
|
||||||
g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
|
handlesys->RemoveType(m_ConVarType, g_pCoreIdent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,7 +227,7 @@ void ConVarManager::OnSourceModVSPReceived()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* For later MM:S versions, use the updated API, since it's cleaner. */
|
/* 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();
|
int engine = g_SMAPI->GetSourceEngineBuild();
|
||||||
if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
|
if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2)
|
||||||
{
|
{
|
||||||
@@ -193,24 +240,15 @@ void ConVarManager::OnSourceModVSPReceived()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE != SE_DARKMESSIAH && SOURCE_ENGINE != SE_DOTA
|
||||||
SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
SH_ADD_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false);
|
||||||
m_bIsVSPQueryHooked = true;
|
m_bIsVSPQueryHooked = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
|
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
|
||||||
{
|
{
|
||||||
ConVarInfo **pLookup = convar_cache.retrieve(name);
|
return convar_cache.retrieve(name, pVar);
|
||||||
if (pLookup != NULL)
|
|
||||||
{
|
|
||||||
*pVar = *pLookup;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
|
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
|
||||||
@@ -229,7 +267,7 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
|||||||
convar_cache.remove(name);
|
convar_cache.remove(name);
|
||||||
|
|
||||||
/* Now make sure no plugins are referring to this pointer */
|
/* Now make sure no plugins are referring to this pointer */
|
||||||
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
|
IPluginIterator *pl_iter = scripts->GetPluginIterator();
|
||||||
while (pl_iter->MorePlugins())
|
while (pl_iter->MorePlugins())
|
||||||
{
|
{
|
||||||
IPlugin *pl = pl_iter->GetPlugin();
|
IPlugin *pl = pl_iter->GetPlugin();
|
||||||
@@ -245,19 +283,51 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Free resources */
|
/* Free resources */
|
||||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
handlesys->FreeHandle(pInfo->handle, &sec);
|
||||||
delete pInfo;
|
delete pInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||||
{
|
{
|
||||||
ConVarList *pConVarList;
|
ConVarList *pConVarList;
|
||||||
|
List<ConVarQuery>::iterator iter;
|
||||||
|
|
||||||
/* If plugin has a convar list, free its memory */
|
/* If plugin has a convar list, free its memory */
|
||||||
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
||||||
{
|
{
|
||||||
delete pConVarList;
|
delete pConVarList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
||||||
|
|
||||||
|
/* Remove convar queries for this plugin that haven't returned results yet */
|
||||||
|
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||||
|
{
|
||||||
|
ConVarQuery &query = (*iter);
|
||||||
|
if (query.pCallback->GetParentRuntime() == pRuntime)
|
||||||
|
{
|
||||||
|
iter = m_ConVarQueries.erase(iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConVarManager::OnClientDisconnected(int client)
|
||||||
|
{
|
||||||
|
/* Remove convar queries for this client that haven't returned results yet */
|
||||||
|
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||||
|
{
|
||||||
|
ConVarQuery &query = (*iter);
|
||||||
|
if (query.client == client)
|
||||||
|
{
|
||||||
|
iter = m_ConVarQueries.erase(iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
|
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||||
@@ -275,11 +345,18 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
|
|||||||
int argcount = command.ArgC();
|
int argcount = command.ArgC();
|
||||||
if (argcount >= 3)
|
if (argcount >= 3)
|
||||||
{
|
{
|
||||||
|
bool wantReset = false;
|
||||||
|
|
||||||
/* Get plugin index that was passed */
|
/* Get plugin index that was passed */
|
||||||
const char *arg = command.Arg(2);
|
const char *arg = command.Arg(2);
|
||||||
|
if (argcount >= 4 && strcmp(arg, "reset") == 0)
|
||||||
|
{
|
||||||
|
wantReset = true;
|
||||||
|
arg = command.Arg(3);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get plugin object */
|
/* Get plugin object */
|
||||||
CPlugin *plugin = g_PluginSys.FindPluginByConsoleArg(arg);
|
IPlugin *plugin = scripts->FindPluginByConsoleArg(arg);
|
||||||
|
|
||||||
if (!plugin)
|
if (!plugin)
|
||||||
{
|
{
|
||||||
@@ -301,21 +378,34 @@ void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &co
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
|
if (!wantReset)
|
||||||
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
|
{
|
||||||
|
g_RootMenu.ConsolePrint("[SM] Listing %d convars for: %s", pConVarList->size(), plname);
|
||||||
/* Iterate convar list and display each one */
|
g_RootMenu.ConsolePrint(" %-32.31s %s", "[Name]", "[Value]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate convar list and display/reset each one */
|
||||||
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
|
for (iter = pConVarList->begin(); iter != pConVarList->end(); iter++)
|
||||||
{
|
{
|
||||||
const ConVar *pConVar = (*iter);
|
/*const */ConVar *pConVar = const_cast<ConVar *>(*iter);
|
||||||
g_RootMenu.ConsolePrint(" %-32.31s %s", pConVar->GetName(), pConVar->GetString());
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Display usage of subcommand */
|
/* 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)
|
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)
|
||||||
@@ -347,7 +437,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
pInfo->pVar = pConVar;
|
pInfo->pVar = pConVar;
|
||||||
|
|
||||||
/* If we don't, then create a new handle from the convar */
|
/* If we don't, then create a new handle from the convar */
|
||||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||||
if (hndl == BAD_HANDLE)
|
if (hndl == BAD_HANDLE)
|
||||||
{
|
{
|
||||||
delete pInfo;
|
delete pInfo;
|
||||||
@@ -378,7 +468,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
pInfo->pChangeForward = NULL;
|
pInfo->pChangeForward = NULL;
|
||||||
|
|
||||||
/* Create a handle from the new convar */
|
/* Create a handle from the new convar */
|
||||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||||
if (hndl == BAD_HANDLE)
|
if (hndl == BAD_HANDLE)
|
||||||
{
|
{
|
||||||
delete pInfo;
|
delete pInfo;
|
||||||
@@ -407,7 +497,13 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
|||||||
ConVarInfo *pInfo;
|
ConVarInfo *pInfo;
|
||||||
Handle_t hndl;
|
Handle_t hndl;
|
||||||
|
|
||||||
/* Search for convar */
|
/* Check convar cache to find out if we already have a handle */
|
||||||
|
if (convar_cache_lookup(name, &pInfo))
|
||||||
|
{
|
||||||
|
return pInfo->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couldn't find it in cache, so search for it */
|
||||||
pConVar = icvar->FindVar(name);
|
pConVar = icvar->FindVar(name);
|
||||||
|
|
||||||
/* If it doesn't exist, then return an invalid handle */
|
/* If it doesn't exist, then return an invalid handle */
|
||||||
@@ -416,12 +512,6 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
|||||||
return BAD_HANDLE;
|
return BAD_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At this point, the convar exists. So, find out if we already have a handle */
|
|
||||||
if (convar_cache_lookup(name, &pInfo))
|
|
||||||
{
|
|
||||||
return pInfo->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create and initialize ConVarInfo structure */
|
/* Create and initialize ConVarInfo structure */
|
||||||
pInfo = new ConVarInfo();
|
pInfo = new ConVarInfo();
|
||||||
pInfo->sourceMod = false;
|
pInfo->sourceMod = false;
|
||||||
@@ -429,7 +519,7 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
|||||||
pInfo->pVar = pConVar;
|
pInfo->pVar = pConVar;
|
||||||
|
|
||||||
/* If we don't have a handle, then create a new one */
|
/* If we don't have a handle, then create a new one */
|
||||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||||
if (hndl == BAD_HANDLE)
|
if (hndl == BAD_HANDLE)
|
||||||
{
|
{
|
||||||
delete pInfo;
|
delete pInfo;
|
||||||
@@ -487,7 +577,7 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction
|
|||||||
/* If forward does not exist, create it */
|
/* If forward does not exist, create it */
|
||||||
if (!pForward)
|
if (!pForward)
|
||||||
{
|
{
|
||||||
pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
|
pForward = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS);
|
||||||
pInfo->pChangeForward = pForward;
|
pInfo->pChangeForward = pForward;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,10 +613,11 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If the forward now has 0 functions in it... */
|
/* If the forward now has 0 functions in it... */
|
||||||
if (pForward->GetFunctionCount() == 0)
|
if (pForward->GetFunctionCount() == 0 &&
|
||||||
|
!ConVarReentrancyGuard::IsCvarInChain(pConVar))
|
||||||
{
|
{
|
||||||
/* Free this forward */
|
/* Free this forward */
|
||||||
g_Forwards.ReleaseForward(pForward);
|
forwardsys->ReleaseForward(pForward);
|
||||||
pInfo->pChangeForward = NULL;
|
pInfo->pChangeForward = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -540,19 +631,28 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
|
|||||||
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
|
/* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */
|
||||||
if (m_bIsDLLQueryHooked)
|
if (m_bIsDLLQueryHooked)
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
cookie = engine->StartQueryCvarValue(CEntityIndex(IndexOfEdict(pPlayer)), name);
|
||||||
|
#else
|
||||||
cookie = engine->StartQueryCvarValue(pPlayer, name);
|
cookie = engine->StartQueryCvarValue(pPlayer, name);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#if SOURCE_ENGINE != SE_DOTA
|
||||||
else if (m_bIsVSPQueryHooked)
|
else if (m_bIsVSPQueryHooked)
|
||||||
{
|
{
|
||||||
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
|
cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return InvalidQueryCvarCookie;
|
return InvalidQueryCvarCookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConVarQuery query = {cookie, pCallback, hndl};
|
if (pCallback != NULL)
|
||||||
m_ConVarQueries.push_back(query);
|
{
|
||||||
|
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) };
|
||||||
|
m_ConVarQueries.push_back(query);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return cookie;
|
return cookie;
|
||||||
@@ -565,7 +665,7 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar
|
|||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
const char *orig = pConVar->GetName();
|
const char *orig = pConVar->GetName();
|
||||||
|
|
||||||
IPlugin *plugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
|
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
||||||
|
|
||||||
/* Check plugin for an existing convar list */
|
/* Check plugin for an existing convar list */
|
||||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||||
@@ -634,6 +734,8 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
|||||||
|
|
||||||
if (pForward != NULL)
|
if (pForward != NULL)
|
||||||
{
|
{
|
||||||
|
ConVarReentrancyGuard guard(pConVar);
|
||||||
|
|
||||||
/* Now call forwards in plugins that have hooked this */
|
/* Now call forwards in plugins that have hooked this */
|
||||||
pForward->PushCell(pInfo->handle);
|
pForward->PushCell(pInfo->handle);
|
||||||
pForward->PushString(oldValue);
|
pForward->PushString(oldValue);
|
||||||
@@ -648,8 +750,19 @@ bool ConVarManager::IsQueryingSupported()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||||
|
#else
|
||||||
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||||
|
#endif // SE_DOTA
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
|
if (g_Players.HandleConVarQuery(cookie, pPlayer, result, cvarName, cvarValue))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
IPluginFunction *pCallback = NULL;
|
IPluginFunction *pCallback = NULL;
|
||||||
cell_t value = 0;
|
cell_t value = 0;
|
||||||
List<ConVarQuery>::iterator iter;
|
List<ConVarQuery>::iterator iter;
|
||||||
@@ -670,7 +783,11 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *
|
|||||||
cell_t ret;
|
cell_t ret;
|
||||||
|
|
||||||
pCallback->PushCell(cookie);
|
pCallback->PushCell(cookie);
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
pCallback->PushCell(player.Get());
|
||||||
|
#else
|
||||||
pCallback->PushCell(IndexOfEdict(pPlayer));
|
pCallback->PushCell(IndexOfEdict(pPlayer));
|
||||||
|
#endif
|
||||||
pCallback->PushCell(result);
|
pCallback->PushCell(result);
|
||||||
pCallback->PushString(cvarName);
|
pCallback->PushString(cvarName);
|
||||||
|
|
||||||
@@ -696,7 +813,7 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
|||||||
ConVarInfo *pInfo;
|
ConVarInfo *pInfo;
|
||||||
HandleError error;
|
HandleError error;
|
||||||
|
|
||||||
if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
|
if ((error = handlesys->ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
|
||||||
{
|
{
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -39,8 +39,10 @@
|
|||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <IRootConsoleMenu.h>
|
#include <IRootConsoleMenu.h>
|
||||||
|
#include <IPlayerHelpers.h>
|
||||||
#include <compat_wrappers.h>
|
#include <compat_wrappers.h>
|
||||||
#include "concmd_cleaner.h"
|
#include "concmd_cleaner.h"
|
||||||
|
#include "PlayerManager.h"
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_DARKMESSIAH
|
#if SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
class EQueryCvarValueStatus;
|
class EQueryCvarValueStatus;
|
||||||
@@ -65,6 +67,11 @@ struct ConVarInfo
|
|||||||
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
||||||
ConVar *pVar; /**< The actual convar */
|
ConVar *pVar; /**< The actual convar */
|
||||||
List<IConVarChangeListener *> changeListeners;
|
List<IConVarChangeListener *> changeListeners;
|
||||||
|
|
||||||
|
static inline bool matches(const char *name, const ConVarInfo *info)
|
||||||
|
{
|
||||||
|
return strcmp(name, info->pVar->GetName()) == 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +82,7 @@ struct ConVarQuery
|
|||||||
QueryCvarCookie_t cookie; /**< Cookie that identifies query */
|
QueryCvarCookie_t cookie; /**< Cookie that identifies query */
|
||||||
IPluginFunction *pCallback; /**< Function that will be called when query is finished */
|
IPluginFunction *pCallback; /**< Function that will be called when query is finished */
|
||||||
cell_t value; /**< Optional value passed to query function */
|
cell_t value; /**< Optional value passed to query function */
|
||||||
|
cell_t client; /**< Only used for cleaning up on client disconnection */
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConVarManager :
|
class ConVarManager :
|
||||||
@@ -82,7 +90,8 @@ class ConVarManager :
|
|||||||
public IHandleTypeDispatch,
|
public IHandleTypeDispatch,
|
||||||
public IPluginsListener,
|
public IPluginsListener,
|
||||||
public IRootConsoleCommand,
|
public IRootConsoleCommand,
|
||||||
public IConCommandTracker
|
public IConCommandTracker,
|
||||||
|
public IClientListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConVarManager();
|
ConVarManager();
|
||||||
@@ -101,6 +110,8 @@ public: //IRootConsoleCommand
|
|||||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||||
public: //IConCommandTracker
|
public: //IConCommandTracker
|
||||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||||
|
public: //IClientListener
|
||||||
|
void OnClientDisconnected(int client);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a convar and return a handle to it.
|
* Create a convar and return a handle to it.
|
||||||
@@ -154,7 +165,10 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Callback for when StartQueryCvarValue() has finished.
|
* Callback for when StartQueryCvarValue() has finished.
|
||||||
*/
|
*/
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIndex player, EQueryCvarValueStatus result,
|
||||||
|
const char *cvarName, const char *cvarValue);
|
||||||
|
#elif SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
|
void OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result,
|
||||||
const char *cvarName, const char *cvarValue);
|
const char *cvarName, const char *cvarValue);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,739 @@
|
|||||||
|
/**
|
||||||
|
* 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 "logic_bridge.h"
|
||||||
|
#include <am-utility.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_DOTA
|
||||||
|
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||||
|
# elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
|
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||||
|
# else
|
||||||
|
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_DOTA
|
||||||
|
void Dispatch(const CCommandContext &context, const CCommand& args)
|
||||||
|
# elif 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 = forwardsys->CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
|
||||||
|
Param_String, Param_Cell);
|
||||||
|
sharesys->AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleDetours::OnSourceModShutdown()
|
||||||
|
{
|
||||||
|
for (StringHashMap<IChangeableForward *>::iterator iter = m_Listeners.iter();
|
||||||
|
!iter.empty();
|
||||||
|
iter.next())
|
||||||
|
{
|
||||||
|
forwardsys->ReleaseForward(iter->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardsys->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
|
||||||
|
{
|
||||||
|
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
|
||||||
|
IChangeableForward *forward;
|
||||||
|
if (!m_Listeners.retrieve(str, &forward))
|
||||||
|
{
|
||||||
|
forward = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, NULL, Param_Cell,
|
||||||
|
Param_String, Param_Cell);
|
||||||
|
m_Listeners.insert(str, forward);
|
||||||
|
}
|
||||||
|
forward->AddFunction(fun);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
|
||||||
|
{
|
||||||
|
if (command == NULL)
|
||||||
|
{
|
||||||
|
return m_pForward->RemoveFunction(fun);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ke::AutoArray<char> str(UTIL_ToLowerCase(command));
|
||||||
|
IChangeableForward *forward;
|
||||||
|
if (!m_Listeners.retrieve(str, &forward))
|
||||||
|
return false;
|
||||||
|
return 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;
|
||||||
|
|
||||||
|
IChangeableForward *forward;
|
||||||
|
if (!m_Listeners.retrieve(name, &forward))
|
||||||
|
return result;
|
||||||
|
if (forward->GetFunctionCount() == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
cell_t result2 = Pl_Continue;
|
||||||
|
forward->PushCell(client);
|
||||||
|
forward->PushString(name);
|
||||||
|
forward->PushCell(args.ArgC() - 1);
|
||||||
|
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(ConCommand, Dispatch, pBase, SH_STATIC(DummyHook), false);
|
||||||
|
dummy_hook_set = true;
|
||||||
|
pBase->Dispatch();
|
||||||
|
SH_REMOVE_HOOK(ConCommand, Dispatch, pBase, SH_STATIC(DummyHook), false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Make sure the command gets invoked. See bug 4019 on making this better. */
|
||||||
|
pBase->Dispatch();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -28,85 +28,51 @@
|
|||||||
*
|
*
|
||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CONSOLE_DETOURS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CONSOLE_DETOURS_H_
|
||||||
|
|
||||||
#include <string.h>
|
#include "sm_globals.h"
|
||||||
#include <stdlib.h>
|
#include "sourcemm_api.h"
|
||||||
#include "sm_memtable.h"
|
#include <IForwardSys.h>
|
||||||
|
#include <sm_stringhashmap.h>
|
||||||
|
|
||||||
BaseMemTable::BaseMemTable(unsigned int init_size)
|
class ConsoleDetours :
|
||||||
|
public SMGlobalClass,
|
||||||
|
public IFeatureProvider
|
||||||
{
|
{
|
||||||
membase = (unsigned char *)malloc(init_size);
|
friend class PlayerManager;
|
||||||
size = init_size;
|
friend class GenericCommandHooker;
|
||||||
tail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseMemTable::~BaseMemTable()
|
public:
|
||||||
{
|
ConsoleDetours();
|
||||||
free(membase);
|
public: //SMGlobalClass
|
||||||
membase = NULL;
|
void OnSourceModAllInitialized();
|
||||||
}
|
void OnSourceModShutdown();
|
||||||
|
public: //IFeatureProvider
|
||||||
int BaseMemTable::CreateMem(unsigned int addsize, void **addr)
|
FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
|
||||||
{
|
public:
|
||||||
int idx = (int)tail;
|
bool AddListener(IPluginFunction *fun, const char *command);
|
||||||
|
bool RemoveListener(IPluginFunction *fun, const char *command);
|
||||||
while (tail + addsize >= size)
|
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()
|
||||||
{
|
{
|
||||||
size *= 2;
|
return status == FeatureStatus_Available;
|
||||||
membase = (unsigned char *)realloc(membase, size);
|
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
FeatureStatus status;
|
||||||
|
IChangeableForward *m_pForward;
|
||||||
|
StringHashMap<IChangeableForward *> m_Listeners;
|
||||||
|
};
|
||||||
|
|
||||||
tail += addsize;
|
extern ConsoleDetours g_ConsoleDetours;
|
||||||
|
|
||||||
if (addr)
|
#endif /* _INCLUDE_SOURCEMOD_CONSOLE_DETOURS_H_ */
|
||||||
{
|
|
||||||
*addr = (void *)&membase[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *BaseMemTable::GetAddress(int index)
|
|
||||||
{
|
|
||||||
if (index < 0 || (unsigned int)index >= tail)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &membase[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseMemTable::Reset()
|
|
||||||
{
|
|
||||||
tail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseStringTable::BaseStringTable(unsigned int init_size) : m_table(init_size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseStringTable::~BaseStringTable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int BaseStringTable::AddString(const char *string)
|
|
||||||
{
|
|
||||||
size_t len = strlen(string) + 1;
|
|
||||||
int idx;
|
|
||||||
char *addr;
|
|
||||||
|
|
||||||
idx = m_table.CreateMem(len, (void **)&addr);
|
|
||||||
strcpy(addr, string);
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*const char *BaseStringTable::GetString(int str)
|
|
||||||
{
|
|
||||||
return (const char *)m_table.GetAddress(str);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void BaseStringTable::Reset()
|
|
||||||
{
|
|
||||||
m_table.Reset();
|
|
||||||
}
|
|
||||||
+79
-47
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -34,13 +34,12 @@
|
|||||||
#include "sourcemod.h"
|
#include "sourcemod.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "sm_srvcmds.h"
|
#include "sm_srvcmds.h"
|
||||||
#include "sm_version.h"
|
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "LibrarySys.h"
|
#include "LibrarySys.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "ForwardSys.h"
|
|
||||||
#include "frame_hooks.h"
|
#include "frame_hooks.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
#include <sourcemod_version.h>
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
|
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
|
||||||
@@ -61,14 +60,21 @@ ConVar *g_ServerCfgFile = NULL;
|
|||||||
|
|
||||||
void CheckAndFinalizeConfigs();
|
void CheckAndFinalizeConfigs();
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||||
|
void Hook_ExecDispatchPre(const CCommandContext &context, const CCommand &cmd)
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||||
void Hook_ExecDispatchPre(const CCommand &cmd)
|
void Hook_ExecDispatchPre(const CCommand &cmd)
|
||||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||||
void Hook_ExecDispatchPre()
|
void Hook_ExecDispatchPre()
|
||||||
#else
|
#else
|
||||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
# 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>);
|
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||||
void Hook_ExecDispatchPre()
|
void Hook_ExecDispatchPre()
|
||||||
#endif
|
#endif
|
||||||
@@ -85,7 +91,9 @@ void Hook_ExecDispatchPre()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void Hook_ExecDispatchPost(const CCommandContext &context, const CCommand &cmd)
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void Hook_ExecDispatchPost(const CCommand &cmd)
|
void Hook_ExecDispatchPost(const CCommand &cmd)
|
||||||
#else
|
#else
|
||||||
void Hook_ExecDispatchPost()
|
void Hook_ExecDispatchPost()
|
||||||
@@ -103,23 +111,19 @@ void CheckAndFinalizeConfigs()
|
|||||||
{
|
{
|
||||||
if ((g_bServerExecd || g_ServerCfgFile == NULL) && g_bGotServerStart)
|
if ((g_bServerExecd || g_ServerCfgFile == NULL) && g_bGotServerStart)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
g_PendingInternalPush = true;
|
g_PendingInternalPush = true;
|
||||||
#else
|
|
||||||
SM_InternalCmdTrigger();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreConfig::OnSourceModAllInitialized()
|
void CoreConfig::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
|
g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
|
||||||
g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
|
g_pOnServerCfg = forwardsys->CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
|
||||||
g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
|
g_pOnConfigsExecuted = forwardsys->CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
|
||||||
g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
|
g_pOnAutoConfigsBuffered = forwardsys->CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreConfig::CoreConfig() : m_Strings(512)
|
CoreConfig::CoreConfig()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,14 +134,14 @@ CoreConfig::~CoreConfig()
|
|||||||
void CoreConfig::OnSourceModShutdown()
|
void CoreConfig::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
g_RootMenu.RemoveRootConsoleCommand("config", this);
|
g_RootMenu.RemoveRootConsoleCommand("config", this);
|
||||||
g_Forwards.ReleaseForward(g_pOnServerCfg);
|
forwardsys->ReleaseForward(g_pOnServerCfg);
|
||||||
g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
|
forwardsys->ReleaseForward(g_pOnConfigsExecuted);
|
||||||
g_Forwards.ReleaseForward(g_pOnAutoConfigsBuffered);
|
forwardsys->ReleaseForward(g_pOnAutoConfigsBuffered);
|
||||||
|
|
||||||
if (g_pExecPtr != NULL)
|
if (g_pExecPtr != NULL)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
|
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
|
||||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
|
SH_REMOVE_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
|
||||||
g_pExecPtr = NULL;
|
g_pExecPtr = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,8 +166,8 @@ void CoreConfig::OnSourceModLevelChange(const char *mapName)
|
|||||||
g_pExecPtr = FindCommand("exec");
|
g_pExecPtr = FindCommand("exec");
|
||||||
if (g_pExecPtr != NULL)
|
if (g_pExecPtr != NULL)
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPre, false);
|
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPre), false);
|
||||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_pExecPtr, Hook_ExecDispatchPost, true);
|
SH_ADD_HOOK(ConCommand, Dispatch, g_pExecPtr, SH_STATIC(Hook_ExecDispatchPost), true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -193,17 +197,30 @@ void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &comma
|
|||||||
|
|
||||||
if (res == ConfigResult_Reject)
|
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) {
|
} else if (res == ConfigResult_Ignore) {
|
||||||
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
|
||||||
} else {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
|
g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> [value]");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreConfig::Initialize()
|
void CoreConfig::Initialize()
|
||||||
@@ -214,18 +231,31 @@ void CoreConfig::Initialize()
|
|||||||
/* Try to get command line value of core config convar */
|
/* Try to get command line value of core config convar */
|
||||||
const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
|
const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
|
||||||
|
|
||||||
/* If sm_corecfgfile not specified on command line, use default value */
|
/* If sm_corecfgfile is on the command line, use that
|
||||||
if (!corecfg)
|
* 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 */
|
/* Format path to config file */
|
||||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset cached key values */
|
/* Reset cached key values */
|
||||||
m_KeyValues.clear();
|
m_KeyValues.clear();
|
||||||
m_Strings.Reset();
|
|
||||||
|
|
||||||
/* Parse config file */
|
/* Parse config file */
|
||||||
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
|
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
|
||||||
@@ -265,19 +295,18 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
|
|||||||
pBase = pBase->m_pGlobalClassNext;
|
pBase = pBase->m_pGlobalClassNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_KeyValues.replace(option, m_Strings.AddString(value));
|
ke::AString vstr(value);
|
||||||
|
m_KeyValues.replace(option, ke::Move(vstr));
|
||||||
|
|
||||||
return ConfigResult_Ignore;
|
return ConfigResult_Ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
||||||
{
|
{
|
||||||
int *pKey = m_KeyValues.retrieve(key);
|
StringHashMap<ke::AString>::Result r = m_KeyValues.find(key);
|
||||||
if (pKey == NULL)
|
if (!r.found())
|
||||||
{
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
return r->value.chars();
|
||||||
return m_Strings.GetString(*pKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SM_AreConfigsExecuted()
|
bool SM_AreConfigsExecuted()
|
||||||
@@ -294,7 +323,7 @@ inline bool IsPathSepChar(char c)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
|
bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
|
||||||
{
|
{
|
||||||
bool will_create = false;
|
bool will_create = false;
|
||||||
|
|
||||||
@@ -381,7 +410,7 @@ bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
|
|||||||
FILE *fp = fopen(file, "wt");
|
FILE *fp = fopen(file, "wt");
|
||||||
if (fp)
|
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", SOURCEMOD_VERSION);
|
||||||
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
|
fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
|
||||||
fprintf(fp, "\n\n");
|
fprintf(fp, "\n\n");
|
||||||
|
|
||||||
@@ -438,6 +467,11 @@ bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
|
|||||||
can_create = false;
|
can_create = false;
|
||||||
fclose(fp);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,10 +502,10 @@ void SM_DoSingleExecFwds(IPluginContext *ctx)
|
|||||||
|
|
||||||
void SM_ConfigsExecuted_Plugin(unsigned int serial)
|
void SM_ConfigsExecuted_Plugin(unsigned int serial)
|
||||||
{
|
{
|
||||||
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
|
IPluginIterator *iter = scripts->GetPluginIterator();
|
||||||
while (iter->MorePlugins())
|
while (iter->MorePlugins())
|
||||||
{
|
{
|
||||||
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
|
IPlugin *plugin = iter->GetPlugin();
|
||||||
if (plugin->GetSerial() == serial)
|
if (plugin->GetSerial() == serial)
|
||||||
{
|
{
|
||||||
SM_DoSingleExecFwds(plugin->GetBaseContext());
|
SM_DoSingleExecFwds(plugin->GetBaseContext());
|
||||||
@@ -484,7 +518,7 @@ void SM_ConfigsExecuted_Plugin(unsigned int serial)
|
|||||||
|
|
||||||
void SM_ExecuteForPlugin(IPluginContext *ctx)
|
void SM_ExecuteForPlugin(IPluginContext *ctx)
|
||||||
{
|
{
|
||||||
CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
|
SMPlugin *plugin = scripts->FindPluginByContext(ctx->GetContext());
|
||||||
|
|
||||||
unsigned int num = plugin->GetConfigCount();
|
unsigned int num = plugin->GetConfigCount();
|
||||||
if (!num)
|
if (!num)
|
||||||
@@ -513,19 +547,17 @@ void SM_ExecuteAllConfigs()
|
|||||||
|
|
||||||
engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
|
engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
|
||||||
|
|
||||||
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
|
AutoPluginList plugins(scripts);
|
||||||
while (iter->MorePlugins())
|
for (size_t i = 0; i < plugins->size(); i++)
|
||||||
{
|
{
|
||||||
CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
|
SMPlugin *plugin = plugins->at(i);
|
||||||
unsigned int num = plugin->GetConfigCount();
|
unsigned int num = plugin->GetConfigCount();
|
||||||
bool can_create = true;
|
bool can_create = true;
|
||||||
for (unsigned int i=0; i<num; i++)
|
for (unsigned int i=0; i<num; i++)
|
||||||
{
|
{
|
||||||
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
|
can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
|
||||||
}
|
}
|
||||||
iter->NextPlugin();
|
|
||||||
}
|
}
|
||||||
iter->Release();
|
|
||||||
|
|
||||||
g_bGotServerStart = true;
|
g_bGotServerStart = true;
|
||||||
CheckAndFinalizeConfigs();
|
CheckAndFinalizeConfigs();
|
||||||
|
|||||||
+4
-5
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -35,8 +35,8 @@
|
|||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include <ITextParsers.h>
|
#include <ITextParsers.h>
|
||||||
#include <IRootConsoleMenu.h>
|
#include <IRootConsoleMenu.h>
|
||||||
#include <sm_trie_tpl.h>
|
#include <am-string.h>
|
||||||
#include "sm_memtable.h"
|
#include <sm_stringhashmap.h>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
@@ -68,8 +68,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
||||||
private:
|
private:
|
||||||
BaseStringTable m_Strings;
|
StringHashMap<ke::AString> m_KeyValues;
|
||||||
KTrie<int> m_KeyValues;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool SM_AreConfigsExecuted();
|
extern bool SM_AreConfigsExecuted();
|
||||||
|
|||||||
+64
-41
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -30,10 +30,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "EventManager.h"
|
#include "EventManager.h"
|
||||||
#include "ForwardSys.h"
|
|
||||||
#include "HandleSys.h"
|
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
EventManager g_EventManager;
|
EventManager g_EventManager;
|
||||||
|
|
||||||
@@ -42,16 +40,26 @@ SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *,
|
|||||||
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
|
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
|
||||||
typedef List<EventHook *> EventHookList;
|
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)
|
EventManager::EventManager() : m_EventType(0)
|
||||||
{
|
{
|
||||||
/* Create an event lookup trie */
|
|
||||||
m_EventHooks = sm_trie_create();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager::~EventManager()
|
EventManager::~EventManager()
|
||||||
{
|
{
|
||||||
sm_trie_destroy(m_EventHooks);
|
|
||||||
|
|
||||||
/* Free memory used by EventInfo structs if any */
|
/* Free memory used by EventInfo structs if any */
|
||||||
CStack<EventInfo *>::iterator iter;
|
CStack<EventInfo *>::iterator iter;
|
||||||
for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
|
for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
|
||||||
@@ -65,8 +73,8 @@ EventManager::~EventManager()
|
|||||||
void EventManager::OnSourceModAllInitialized()
|
void EventManager::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
/* Add a hook for IGameEventManager2::FireEvent() */
|
/* Add a hook for IGameEventManager2::FireEvent() */
|
||||||
SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
|
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
|
||||||
SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
|
SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
|
||||||
|
|
||||||
HandleAccess sec;
|
HandleAccess sec;
|
||||||
|
|
||||||
@@ -76,17 +84,17 @@ void EventManager::OnSourceModAllInitialized()
|
|||||||
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
||||||
|
|
||||||
/* Create the 'GameEvent' handle type */
|
/* Create the 'GameEvent' handle type */
|
||||||
m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
m_EventType = handlesys->CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventManager::OnSourceModShutdown()
|
void EventManager::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
/* Remove hook for IGameEventManager2::FireEvent() */
|
/* Remove hook for IGameEventManager2::FireEvent() */
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
|
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
|
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
|
||||||
|
|
||||||
/* Remove the 'GameEvent' handle type */
|
/* Remove the 'GameEvent' handle type */
|
||||||
g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
|
handlesys->RemoveType(m_EventType, g_pCoreIdent);
|
||||||
|
|
||||||
/* Remove ourselves as listener for events */
|
/* Remove ourselves as listener for events */
|
||||||
gameevents->RemoveListener(this);
|
gameevents->RemoveListener(this);
|
||||||
@@ -124,12 +132,12 @@ void EventManager::OnPluginUnloaded(IPlugin *plugin)
|
|||||||
{
|
{
|
||||||
if (pHook->pPreHook)
|
if (pHook->pPreHook)
|
||||||
{
|
{
|
||||||
g_Forwards.ReleaseForward(pHook->pPreHook);
|
forwardsys->ReleaseForward(pHook->pPreHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pHook->pPostHook)
|
if (pHook->pPostHook)
|
||||||
{
|
{
|
||||||
g_Forwards.ReleaseForward(pHook->pPostHook);
|
forwardsys->ReleaseForward(pHook->pPostHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete pHook;
|
delete pHook;
|
||||||
@@ -147,6 +155,13 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
|
|||||||
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
|
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
|
||||||
|
int EventManager::GetEventDebugID()
|
||||||
|
{
|
||||||
|
return EVENT_DEBUG_ID_INIT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
|
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
|
||||||
{
|
{
|
||||||
EventHook *pHook;
|
EventHook *pHook;
|
||||||
@@ -163,10 +178,10 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If a hook structure does not exist... */
|
/* If a hook structure does not exist... */
|
||||||
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
|
if (!m_EventHooks.retrieve(name, &pHook))
|
||||||
{
|
{
|
||||||
EventHookList *pHookList;
|
EventHookList *pHookList;
|
||||||
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
|
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
|
||||||
|
|
||||||
/* Check plugin for an existing EventHook list */
|
/* Check plugin for an existing EventHook list */
|
||||||
if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
|
if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
|
||||||
@@ -181,12 +196,12 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
|||||||
if (mode == EventHookMode_Pre)
|
if (mode == EventHookMode_Pre)
|
||||||
{
|
{
|
||||||
/* Create forward for a pre hook */
|
/* Create forward for a pre hook */
|
||||||
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
|
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
|
||||||
/* Add to forward list */
|
/* Add to forward list */
|
||||||
pHook->pPreHook->AddFunction(pFunction);
|
pHook->pPreHook->AddFunction(pFunction);
|
||||||
} else {
|
} else {
|
||||||
/* Create forward for a post hook */
|
/* Create forward for a post hook */
|
||||||
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
||||||
/* Should we copy data from a pre hook to the post hook? */
|
/* Should we copy data from a pre hook to the post hook? */
|
||||||
pHook->postCopy = (mode == EventHookMode_Post);
|
pHook->postCopy = (mode == EventHookMode_Post);
|
||||||
/* Add to forward list */
|
/* Add to forward list */
|
||||||
@@ -194,14 +209,14 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Cache the name for post hooks */
|
/* Cache the name for post hooks */
|
||||||
pHook->name = strdup(name);
|
pHook->name = name;
|
||||||
|
|
||||||
/* Increase reference count */
|
/* Increase reference count */
|
||||||
pHook->refCount++;
|
pHook->refCount++;
|
||||||
|
|
||||||
/* Add hook structure to hook lists */
|
/* Add hook structure to hook lists */
|
||||||
pHookList->push_back(pHook);
|
pHookList->push_back(pHook);
|
||||||
sm_trie_insert(m_EventHooks, name, pHook);
|
m_EventHooks.insert(name, pHook);
|
||||||
|
|
||||||
return EventHookErr_Okay;
|
return EventHookErr_Okay;
|
||||||
}
|
}
|
||||||
@@ -213,7 +228,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
|||||||
/* Create pre hook forward if necessary */
|
/* Create pre hook forward if necessary */
|
||||||
if (!pHook->pPreHook)
|
if (!pHook->pPreHook)
|
||||||
{
|
{
|
||||||
pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
|
pHook->pPreHook = forwardsys->CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add plugin function to forward list */
|
/* Add plugin function to forward list */
|
||||||
@@ -222,7 +237,7 @@ EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunct
|
|||||||
/* Create post hook forward if necessary */
|
/* Create post hook forward if necessary */
|
||||||
if (!pHook->pPostHook)
|
if (!pHook->pPostHook)
|
||||||
{
|
{
|
||||||
pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
pHook->pPostHook = forwardsys->CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If postCopy is false, then we may want to set it to true */
|
/* If postCopy is false, then we may want to set it to true */
|
||||||
@@ -247,7 +262,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
|||||||
IChangeableForward **pEventForward;
|
IChangeableForward **pEventForward;
|
||||||
|
|
||||||
/* If hook does not exist at all */
|
/* If hook does not exist at all */
|
||||||
if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
|
if (!m_EventHooks.retrieve(name, &pHook))
|
||||||
{
|
{
|
||||||
return EventHookErr_NotActive;
|
return EventHookErr_NotActive;
|
||||||
}
|
}
|
||||||
@@ -269,7 +284,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
|||||||
/* If forward's list contains 0 functions now, free it */
|
/* If forward's list contains 0 functions now, free it */
|
||||||
if ((*pEventForward)->GetFunctionCount() == 0)
|
if ((*pEventForward)->GetFunctionCount() == 0)
|
||||||
{
|
{
|
||||||
g_Forwards.ReleaseForward(*pEventForward);
|
forwardsys->ReleaseForward(*pEventForward);
|
||||||
*pEventForward = NULL;
|
*pEventForward = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +294,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
|||||||
/* If reference count is now 0, free hook structure */
|
/* If reference count is now 0, free hook structure */
|
||||||
|
|
||||||
EventHookList *pHookList;
|
EventHookList *pHookList;
|
||||||
IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
|
IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
|
||||||
|
|
||||||
/* Get plugin's event hook list */
|
/* Get plugin's event hook list */
|
||||||
if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
|
if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
|
||||||
@@ -297,10 +312,7 @@ EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFun
|
|||||||
pHookList->remove(pHook);
|
pHookList->remove(pHook);
|
||||||
|
|
||||||
/* Delete entry in trie */
|
/* Delete entry in trie */
|
||||||
sm_trie_delete(m_EventHooks, name);
|
m_EventHooks.remove(name);
|
||||||
|
|
||||||
/* Free the cached name */
|
|
||||||
free(pHook->name);
|
|
||||||
|
|
||||||
/* And finally free structure memory */
|
/* And finally free structure memory */
|
||||||
delete pHook;
|
delete pHook;
|
||||||
@@ -327,6 +339,7 @@ EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name,
|
|||||||
|
|
||||||
pInfo->pEvent = pEvent;
|
pInfo->pEvent = pEvent;
|
||||||
pInfo->pOwner = pContext->GetIdentity();
|
pInfo->pOwner = pContext->GetIdentity();
|
||||||
|
pInfo->bDontBroadcast = false;
|
||||||
|
|
||||||
return pInfo;
|
return pInfo;
|
||||||
}
|
}
|
||||||
@@ -365,6 +378,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
IChangeableForward *pForward;
|
IChangeableForward *pForward;
|
||||||
const char *name;
|
const char *name;
|
||||||
cell_t res = Pl_Continue;
|
cell_t res = Pl_Continue;
|
||||||
|
bool broadcast = bDontBroadcast;
|
||||||
|
|
||||||
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
|
/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
|
||||||
if (!pEvent)
|
if (!pEvent)
|
||||||
@@ -374,7 +388,7 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
|
|
||||||
name = pEvent->GetName();
|
name = pEvent->GetName();
|
||||||
|
|
||||||
if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
|
if (m_EventHooks.retrieve(name, &pHook))
|
||||||
{
|
{
|
||||||
/* Push the event onto the event stack. The reference count is increased to make sure
|
/* 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.
|
* the structure is not garbage collected in between now and the post hook.
|
||||||
@@ -388,14 +402,20 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
{
|
{
|
||||||
EventInfo info(pEvent, NULL);
|
EventInfo info(pEvent, NULL);
|
||||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||||
Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
Handle_t hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||||
|
|
||||||
|
info.bDontBroadcast = bDontBroadcast;
|
||||||
|
|
||||||
|
EventForwardFilter filter(&info);
|
||||||
|
|
||||||
pForward->PushCell(hndl);
|
pForward->PushCell(hndl);
|
||||||
pForward->PushString(name);
|
pForward->PushString(name);
|
||||||
pForward->PushCell(bDontBroadcast);
|
pForward->PushCell(bDontBroadcast);
|
||||||
pForward->Execute(&res, NULL);
|
pForward->Execute(&res, &filter);
|
||||||
|
|
||||||
g_HandleSys.FreeHandle(hndl, &sec);
|
broadcast = info.bDontBroadcast;
|
||||||
|
|
||||||
|
handlesys->FreeHandle(hndl, &sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pHook->postCopy)
|
if (pHook->postCopy)
|
||||||
@@ -414,6 +434,9 @@ bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
m_EventStack.push(NULL);
|
m_EventStack.push(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (broadcast != bDontBroadcast)
|
||||||
|
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &IGameEventManager2::FireEvent, (pEvent, broadcast));
|
||||||
|
|
||||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,16 +464,17 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
{
|
{
|
||||||
if (pHook->postCopy)
|
if (pHook->postCopy)
|
||||||
{
|
{
|
||||||
|
info.bDontBroadcast = bDontBroadcast;
|
||||||
info.pEvent = m_EventCopies.front();
|
info.pEvent = m_EventCopies.front();
|
||||||
info.pOwner = NULL;
|
info.pOwner = NULL;
|
||||||
hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
|
||||||
|
|
||||||
pForward->PushCell(hndl);
|
pForward->PushCell(hndl);
|
||||||
} else {
|
} else {
|
||||||
pForward->PushCell(BAD_HANDLE);
|
pForward->PushCell(BAD_HANDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pForward->PushString(pHook->name);
|
pForward->PushString(pHook->name.chars());
|
||||||
pForward->PushCell(bDontBroadcast);
|
pForward->PushCell(bDontBroadcast);
|
||||||
pForward->Execute(NULL);
|
pForward->Execute(NULL);
|
||||||
|
|
||||||
@@ -458,7 +482,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
{
|
{
|
||||||
/* Free handle */
|
/* Free handle */
|
||||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||||
g_HandleSys.FreeHandle(hndl, &sec);
|
handlesys->FreeHandle(hndl, &sec);
|
||||||
|
|
||||||
/* Free event structure */
|
/* Free event structure */
|
||||||
gameevents->FreeEvent(info.pEvent);
|
gameevents->FreeEvent(info.pEvent);
|
||||||
@@ -471,8 +495,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
{
|
{
|
||||||
assert(pHook->pPostHook == NULL);
|
assert(pHook->pPostHook == NULL);
|
||||||
assert(pHook->pPreHook == NULL);
|
assert(pHook->pPreHook == NULL);
|
||||||
sm_trie_delete(m_EventHooks, pHook->name);
|
m_EventHooks.remove(pHook->name.chars());
|
||||||
free(pHook->name);
|
|
||||||
delete pHook;
|
delete pHook;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-5
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "sm_trie.h"
|
#include <sm_namehashset.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
@@ -53,6 +53,7 @@ struct EventInfo
|
|||||||
}
|
}
|
||||||
IGameEvent *pEvent;
|
IGameEvent *pEvent;
|
||||||
IdentityToken_t *pOwner;
|
IdentityToken_t *pOwner;
|
||||||
|
bool bDontBroadcast;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EventHook
|
struct EventHook
|
||||||
@@ -68,7 +69,12 @@ struct EventHook
|
|||||||
IChangeableForward *pPostHook;
|
IChangeableForward *pPostHook;
|
||||||
bool postCopy;
|
bool postCopy;
|
||||||
unsigned int refCount;
|
unsigned int refCount;
|
||||||
char *name;
|
ke::AString name;
|
||||||
|
|
||||||
|
static inline bool matches(const char *name, const EventHook *hook)
|
||||||
|
{
|
||||||
|
return strcmp(name, hook->name.chars()) == 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EventHookMode
|
enum EventHookMode
|
||||||
@@ -104,6 +110,9 @@ public: // IPluginsListener
|
|||||||
void OnPluginUnloaded(IPlugin *plugin);
|
void OnPluginUnloaded(IPlugin *plugin);
|
||||||
public: // IGameEventListener2
|
public: // IGameEventListener2
|
||||||
void FireGameEvent(IGameEvent *pEvent);
|
void FireGameEvent(IGameEvent *pEvent);
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
|
||||||
|
int GetEventDebugID();
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Get the 'GameEvent' handle type ID.
|
* Get the 'GameEvent' handle type ID.
|
||||||
@@ -123,7 +132,7 @@ private: // IGameEventManager2 hooks
|
|||||||
bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast);
|
bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast);
|
||||||
private:
|
private:
|
||||||
HandleType_t m_EventType;
|
HandleType_t m_EventType;
|
||||||
Trie *m_EventHooks;
|
NameHashSet<EventHook *> m_EventHooks;
|
||||||
CStack<EventInfo *> m_FreeEvents;
|
CStack<EventInfo *> m_FreeEvents;
|
||||||
CStack<EventHook *> m_EventStack;
|
CStack<EventHook *> m_EventStack;
|
||||||
CStack<IGameEvent *> m_EventCopies;
|
CStack<IGameEvent *> m_EventCopies;
|
||||||
|
|||||||
+683
-83
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -35,71 +35,93 @@
|
|||||||
#include "UserMessages.h"
|
#include "UserMessages.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "GameConfigs.h"
|
#include <IGameConfigs.h>
|
||||||
#include <compat_wrappers.h>
|
#include <compat_wrappers.h>
|
||||||
|
#include <Logger.h>
|
||||||
|
#include "LibrarySys.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
#include <tier0/mem.h>
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
#include <game/shared/protobuf/usermessages.pb.h>
|
||||||
|
#elif 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_SDK2013 || SOURCE_ENGINE == SE_LEFT4DEAD2 || SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||||
|
#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;
|
CHalfLife2 g_HL2;
|
||||||
ConVar *sv_lan = NULL;
|
ConVar *sv_lan = NULL;
|
||||||
|
|
||||||
namespace SourceHook
|
static void *g_EntList = NULL;
|
||||||
{
|
static void **g_pEntInfoList = NULL;
|
||||||
template<>
|
static int entInfoOffset = -1;
|
||||||
int HashFunction<datamap_t *>(datamap_t * const &k)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<int>(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
static CEntInfo *EntInfoArray()
|
||||||
int Compare<datamap_t *>(datamap_t * const &k1, datamap_t * const &k2)
|
{
|
||||||
|
if (g_EntList != NULL)
|
||||||
{
|
{
|
||||||
return (k1-k2);
|
return (CEntInfo *)((intp)g_EntList + entInfoOffset);
|
||||||
}
|
}
|
||||||
|
else if (g_pEntInfoList)
|
||||||
|
{
|
||||||
|
return *(CEntInfo **)g_pEntInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHalfLife2::CHalfLife2()
|
CHalfLife2::CHalfLife2()
|
||||||
{
|
{
|
||||||
m_pClasses = sm_trie_create();
|
m_Maps.init();
|
||||||
|
|
||||||
|
m_pGetCommandLine = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHalfLife2::~CHalfLife2()
|
CHalfLife2::~CHalfLife2()
|
||||||
{
|
{
|
||||||
sm_trie_destroy(m_pClasses);
|
for (NameHashSet<DataTableInfo *>::iterator iter = m_Classes.iter(); !iter.empty(); iter.next())
|
||||||
|
delete *iter;
|
||||||
|
|
||||||
List<DataTableInfo *>::iterator iter;
|
for (DataTableMap::iterator iter = m_Maps.iter(); !iter.empty(); iter.next())
|
||||||
DataTableInfo *pInfo;
|
delete iter->value;
|
||||||
for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++)
|
|
||||||
{
|
|
||||||
pInfo = (*iter);
|
|
||||||
delete pInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Tables.clear();
|
|
||||||
|
|
||||||
THash<datamap_t *, DataMapTrie>::iterator h_iter;
|
|
||||||
for (h_iter=m_Maps.begin(); h_iter!=m_Maps.end(); h_iter++)
|
|
||||||
{
|
|
||||||
if (h_iter->val.trie)
|
|
||||||
{
|
|
||||||
sm_trie_destroy(h_iter->val.trie);
|
|
||||||
h_iter->val.trie = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Maps.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
|
CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
|
||||||
bool is_original_engine = false;
|
bool is_original_engine = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
void CHalfLife2::OnSourceModStartup(bool late)
|
void CHalfLife2::OnSourceModStartup(bool late)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
|
|
||||||
/* The Ship currently is the only known game to use an older version of the engine */
|
/* 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)
|
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
|
||||||
#else
|
#else
|
||||||
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
|
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
|
||||||
@@ -120,10 +142,143 @@ void CHalfLife2::OnSourceModAllInitialized()
|
|||||||
m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
|
m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText");
|
||||||
m_SayTextMsg = g_UserMsgs.GetMessageIndex("SayText");
|
m_SayTextMsg = g_UserMsgs.GetMessageIndex("SayText");
|
||||||
m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
|
m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu");
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
sharesys->AddInterface(NULL, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined METAMOD_PLAPI_VERSION
|
void CHalfLife2::OnSourceModAllInitialized_Post()
|
||||||
|
{
|
||||||
|
InitLogicalEntData();
|
||||||
|
InitCommandLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHalfLife2::InitLogicalEntData()
|
||||||
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_TF2 \
|
||||||
|
|| SOURCE_ENGINE == SE_DODS \
|
||||||
|
|| SOURCE_ENGINE == SE_HL2DM \
|
||||||
|
|| SOURCE_ENGINE == SE_CSS \
|
||||||
|
|| SOURCE_ENGINE == SE_SDK2013
|
||||||
|
|
||||||
|
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", NULL))
|
||||||
|
{
|
||||||
|
g_EntList = servertools->GetEntityList();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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_EntList)
|
||||||
|
{
|
||||||
|
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) && addr)
|
||||||
|
{
|
||||||
|
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 we have g_EntList from either of the above methods, make sure we can get the offset from it to EntInfo as well
|
||||||
|
if (g_EntList && !g_pGameConf->GetOffset("EntInfo", &entInfoOffset))
|
||||||
|
{
|
||||||
|
g_Logger.LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
|
||||||
|
g_EntList = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have g_EntList or have it but don't know where EntInfo is on it, use fallback.
|
||||||
|
if (!g_EntList || entInfoOffset == -1)
|
||||||
|
{
|
||||||
|
g_pGameConf->GetAddress("EntInfosPtr", (void **)&g_pEntInfoList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_EntList && !g_pEntInfoList)
|
||||||
|
{
|
||||||
|
g_Logger.LogError("Failed lookup of gEntList - Reverting to networkable entities only");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHalfLife2::InitCommandLine()
|
||||||
|
{
|
||||||
|
char error[256];
|
||||||
|
|
||||||
|
if (!is_original_engine)
|
||||||
|
{
|
||||||
|
ke::AutoPtr<ILibrary> lib(g_LibSys.OpenLibrary(TIER0_NAME, error, sizeof(error)));
|
||||||
|
if (lib == NULL)
|
||||||
|
{
|
||||||
|
g_Logger.LogError("Could not load %s: %s", TIER0_NAME, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine_Tier0");
|
||||||
|
|
||||||
|
/* '_Tier0' dropped on Alien Swarm version */
|
||||||
|
if (m_pGetCommandLine == NULL)
|
||||||
|
{
|
||||||
|
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ke::AutoPtr<ILibrary> lib(g_LibSys.OpenLibrary(VSTDLIB_NAME, error, sizeof(error)));
|
||||||
|
if (lib == NULL)
|
||||||
|
{
|
||||||
|
g_Logger.LogError("Could not load %s: %s", VSTDLIB_NAME, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pGetCommandLine = lib->GetSymbolAddress("CommandLine");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pGetCommandLine == NULL)
|
||||||
|
{
|
||||||
|
g_Logger.LogError("Could not locate any command line functionality");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ICommandLine *CHalfLife2::GetValveCommandLine()
|
||||||
|
{
|
||||||
|
if (!m_pGetCommandLine)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ((FakeGetCommandLine)((FakeGetCommandLine *)m_pGetCommandLine))();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
|
||||||
bool CHalfLife2::IsOriginalEngine()
|
bool CHalfLife2::IsOriginalEngine()
|
||||||
{
|
{
|
||||||
return is_original_engine;
|
return is_original_engine;
|
||||||
@@ -133,7 +288,11 @@ bool CHalfLife2::IsOriginalEngine()
|
|||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
|
IChangeInfoAccessor *CBaseEdict::GetChangeAccessor()
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
return engine->GetChangeAccessor( IndexOfEdict((const edict_t *)this) );
|
||||||
|
#else
|
||||||
return engine->GetChangeAccessor( (const edict_t *)this );
|
return engine->GetChangeAccessor( (const edict_t *)this );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -172,11 +331,11 @@ bool UTIL_FindInSendTable(SendTable *pTable,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
|
bool UTIL_FindDataMapInfo(datamap_t *pMap, const char *name, sm_datatable_info_t *pDataTable)
|
||||||
{
|
{
|
||||||
while (pMap)
|
while (pMap)
|
||||||
{
|
{
|
||||||
for (int i=0; i<pMap->dataNumFields; i++)
|
for (int i = 0; i < pMap->dataNumFields; ++i)
|
||||||
{
|
{
|
||||||
if (pMap->dataDesc[i].fieldName == NULL)
|
if (pMap->dataDesc[i].fieldName == NULL)
|
||||||
{
|
{
|
||||||
@@ -184,21 +343,23 @@ typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name)
|
|||||||
}
|
}
|
||||||
if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
|
if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
|
||||||
{
|
{
|
||||||
return &(pMap->dataDesc[i]);
|
pDataTable->prop = &(pMap->dataDesc[i]);
|
||||||
|
pDataTable->actual_offset = GetTypeDescOffs(pDataTable->prop);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (pMap->dataDesc[i].td)
|
if (pMap->dataDesc[i].td == NULL || !UTIL_FindDataMapInfo(pMap->dataDesc[i].td, name, pDataTable))
|
||||||
{
|
{
|
||||||
typedescription_t *_td;
|
continue;
|
||||||
if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name)) != NULL)
|
|
||||||
{
|
|
||||||
return _td;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pDataTable->actual_offset += GetTypeDescOffs(&(pMap->dataDesc[i]));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pMap = pMap->baseMap;
|
pMap = pMap->baseMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerClass *CHalfLife2::FindServerClass(const char *classname)
|
ServerClass *CHalfLife2::FindServerClass(const char *classname)
|
||||||
@@ -206,9 +367,7 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
|
|||||||
DataTableInfo *pInfo = _FindServerClass(classname);
|
DataTableInfo *pInfo = _FindServerClass(classname);
|
||||||
|
|
||||||
if (!pInfo)
|
if (!pInfo)
|
||||||
{
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return pInfo->sc;
|
return pInfo->sc;
|
||||||
}
|
}
|
||||||
@@ -216,26 +375,21 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
|
|||||||
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
|
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
|
||||||
{
|
{
|
||||||
DataTableInfo *pInfo = NULL;
|
DataTableInfo *pInfo = NULL;
|
||||||
|
if (!m_Classes.retrieve(classname, &pInfo))
|
||||||
if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo))
|
|
||||||
{
|
{
|
||||||
ServerClass *sc = gamedll->GetAllServerClasses();
|
ServerClass *sc = gamedll->GetAllServerClasses();
|
||||||
while (sc)
|
while (sc)
|
||||||
{
|
{
|
||||||
if (strcmp(classname, sc->GetName()) == 0)
|
if (strcmp(classname, sc->GetName()) == 0)
|
||||||
{
|
{
|
||||||
pInfo = new DataTableInfo;
|
pInfo = new DataTableInfo(sc);
|
||||||
pInfo->sc = sc;
|
m_Classes.insert(classname, pInfo);
|
||||||
sm_trie_insert(m_pClasses, classname, pInfo);
|
|
||||||
m_Tables.push_back(pInfo);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sc = sc->m_pNext;
|
sc = sc->m_pNext;
|
||||||
}
|
}
|
||||||
if (!pInfo)
|
if (!pInfo)
|
||||||
{
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pInfo;
|
return pInfo;
|
||||||
@@ -244,14 +398,13 @@ DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
|
|||||||
bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info)
|
bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info)
|
||||||
{
|
{
|
||||||
DataTableInfo *pInfo;
|
DataTableInfo *pInfo;
|
||||||
sm_sendprop_info_t *prop;
|
|
||||||
|
|
||||||
if ((pInfo = _FindServerClass(classname)) == NULL)
|
if ((pInfo = _FindServerClass(classname)) == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = pInfo->lookup.retrieve(offset)) == NULL)
|
if (!pInfo->lookup.retrieve(offset, info))
|
||||||
{
|
{
|
||||||
sm_sendprop_info_t temp_info;
|
sm_sendprop_info_t temp_info;
|
||||||
|
|
||||||
@@ -263,10 +416,6 @@ bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_
|
|||||||
pInfo->lookup.insert(offset, temp_info);
|
pInfo->lookup.insert(offset, temp_info);
|
||||||
*info = temp_info;
|
*info = temp_info;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
*info = *prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -285,22 +434,32 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
|
|||||||
|
|
||||||
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
|
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
|
||||||
{
|
{
|
||||||
typedescription_t *td = NULL;
|
sm_datatable_info_t dt_info;
|
||||||
DataMapTrie &val = m_Maps[pMap];
|
|
||||||
|
if (!(this->FindDataMapInfo(pMap, offset, &dt_info)))
|
||||||
if (!val.trie)
|
|
||||||
{
|
{
|
||||||
val.trie = sm_trie_create();
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
|
|
||||||
|
return dt_info.prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable)
|
||||||
|
{
|
||||||
|
DataTableMap::Insert i = m_Maps.findForAdd(pMap);
|
||||||
|
if (!i.found())
|
||||||
|
m_Maps.add(i, pMap, new DataMapCache());
|
||||||
|
|
||||||
|
DataMapCache *cache = i->value;
|
||||||
|
|
||||||
|
if (!cache->retrieve(offset, pDataTable))
|
||||||
{
|
{
|
||||||
if ((td = UTIL_FindInDataMap(pMap, offset)) != NULL)
|
if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable))
|
||||||
{
|
return false;
|
||||||
sm_trie_insert(val.trie, offset, td);
|
cache->insert(offset, *pDataTable);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return td;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||||
@@ -326,7 +485,9 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
|||||||
|
|
||||||
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||||
bf_write *pBitBuf = NULL;
|
bf_write *pBitBuf = NULL;
|
||||||
|
#endif
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
if (dest == HUD_PRINTTALK)
|
if (dest == HUD_PRINTTALK)
|
||||||
@@ -339,7 +500,28 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
char buffer[192];
|
char buffer[192];
|
||||||
UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg);
|
UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg);
|
||||||
|
|
||||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
CUserMsg_SayText *pMsg;
|
||||||
|
if ((pMsg = (CUserMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pMsg->set_client(0);
|
||||||
|
pMsg->set_text(buffer);
|
||||||
|
pMsg->set_chat(false);
|
||||||
|
#elif 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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -347,6 +529,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
pBitBuf->WriteByte(0);
|
pBitBuf->WriteByte(0);
|
||||||
pBitBuf->WriteString(buffer);
|
pBitBuf->WriteString(buffer);
|
||||||
pBitBuf->WriteByte(1);
|
pBitBuf->WriteByte(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
g_UserMsgs.EndMessage();
|
g_UserMsgs.EndMessage();
|
||||||
|
|
||||||
@@ -354,13 +537,38 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
CUserMsg_TextMsg *pMsg;
|
||||||
|
if ((pMsg = (CUserMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pMsg->set_dest(dest);
|
||||||
|
pMsg->add_param(msg);
|
||||||
|
#elif 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pBitBuf->WriteByte(dest);
|
pBitBuf->WriteByte(dest);
|
||||||
pBitBuf->WriteString(msg);
|
pBitBuf->WriteString(msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
g_UserMsgs.EndMessage();
|
g_UserMsgs.EndMessage();
|
||||||
|
|
||||||
@@ -369,10 +577,28 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
|
|
||||||
bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||||
{
|
{
|
||||||
bf_write *pBitBuf = NULL;
|
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
CUserMsg_HintText *pMsg;
|
||||||
|
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pMsg->set_message(msg);
|
||||||
|
#elif 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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -383,6 +609,46 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
|||||||
pBitBuf->WriteByte(1);
|
pBitBuf->WriteByte(1);
|
||||||
}
|
}
|
||||||
pBitBuf->WriteString(msg);
|
pBitBuf->WriteString(msg);
|
||||||
|
#endif
|
||||||
|
g_UserMsgs.EndMessage();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
||||||
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
CUserMsg_HintText *pMsg;
|
||||||
|
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pMsg->set_message(msg);
|
||||||
|
#elif 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();
|
g_UserMsgs.EndMessage();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -390,15 +656,29 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
|||||||
|
|
||||||
bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
|
bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show)
|
||||||
{
|
{
|
||||||
bf_write *pBitBuf = NULL;
|
|
||||||
KeyValues *SubKey = NULL;
|
KeyValues *SubKey = NULL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
CUserMsg_VGUIMenu *pMsg;
|
||||||
|
if ((pMsg = (CUserMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#elif 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)
|
if (data)
|
||||||
{
|
{
|
||||||
@@ -411,6 +691,29 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
|||||||
SubKey = data->GetFirstSubKey();
|
SubKey = data->GetFirstSubKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
pMsg->set_name(name);
|
||||||
|
pMsg->set_show(show);
|
||||||
|
|
||||||
|
while (SubKey)
|
||||||
|
{
|
||||||
|
CUserMsg_VGUIMenu_Keys *key = pMsg->add_keys();
|
||||||
|
key->set_name(SubKey->GetName());
|
||||||
|
key->set_value(SubKey->GetString());
|
||||||
|
SubKey = SubKey->GetNextKey();
|
||||||
|
}
|
||||||
|
#elif 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->WriteString(name);
|
||||||
pBitBuf->WriteByte((show) ? 1 : 0);
|
pBitBuf->WriteByte((show) ? 1 : 0);
|
||||||
pBitBuf->WriteByte(count);
|
pBitBuf->WriteByte(count);
|
||||||
@@ -420,6 +723,8 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
|||||||
pBitBuf->WriteString(SubKey->GetString());
|
pBitBuf->WriteString(SubKey->GetString());
|
||||||
SubKey = SubKey->GetNextKey();
|
SubKey = SubKey->GetNextKey();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
g_UserMsgs.EndMessage();
|
g_UserMsgs.EndMessage();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -453,10 +758,15 @@ void CHalfLife2::ProcessFakeCliCmdQueue()
|
|||||||
if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
|
if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client)
|
||||||
{
|
{
|
||||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
|
CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client);
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
engine->ClientCommand(pPlayer->GetIndex(), "%s", pFake->cmd.c_str());
|
||||||
|
#else
|
||||||
serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
|
serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
m_CmdQueue.pop();
|
m_CmdQueue.pop();
|
||||||
|
m_FreeCmds.push(pFake);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +784,7 @@ bool CHalfLife2::IsLANServer()
|
|||||||
|
|
||||||
bool CHalfLife2::KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID)
|
bool CHalfLife2::KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID)
|
||||||
{
|
{
|
||||||
#if defined METAMOD_PLAPI_VERSION
|
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
|
||||||
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
|
if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL)
|
||||||
#else
|
#else
|
||||||
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
|
if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0)
|
||||||
@@ -551,6 +861,14 @@ const char *CHalfLife2::CurrentCommandName()
|
|||||||
|
|
||||||
void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg)
|
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;
|
DelayedKickInfo kick;
|
||||||
|
|
||||||
kick.client = client;
|
kick.client = client;
|
||||||
@@ -599,7 +917,10 @@ edict_t *CHalfLife2::GetHandleEntity(CBaseHandle &hndl)
|
|||||||
edict_t *pStoredEdict;
|
edict_t *pStoredEdict;
|
||||||
CBaseEntity *pStoredEntity;
|
CBaseEntity *pStoredEntity;
|
||||||
|
|
||||||
pStoredEdict = GetEntity(index, &pStoredEntity);
|
if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (pStoredEdict == NULL || pStoredEntity == NULL)
|
if (pStoredEdict == NULL || pStoredEntity == NULL)
|
||||||
{
|
{
|
||||||
@@ -642,3 +963,282 @@ void CHalfLife2::ServerCommand(const char *buffer)
|
|||||||
{
|
{
|
||||||
engine->ServerCommand(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEntInfo *entInfos = EntInfoArray();
|
||||||
|
|
||||||
|
if (!entInfos)
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entInfos[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)
|
||||||
|
{
|
||||||
|
CBaseEntity *pGetterEnt = ReferenceToEntity(0);
|
||||||
|
datamap_t *pMap = GetDataMap(pGetterEnt);
|
||||||
|
|
||||||
|
sm_datatable_info_t info;
|
||||||
|
if (!FindDataMapInfo(pMap, "m_iClassname", &info))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = info.actual_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
+76
-12
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -35,14 +35,21 @@
|
|||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include <sh_tinyhash.h>
|
#include <sh_tinyhash.h>
|
||||||
#include <sm_trie_tpl.h>
|
#include <am-utility.h>
|
||||||
#include "sm_trie.h"
|
#include <am-hashmap.h>
|
||||||
|
#include <sm_stringhashmap.h>
|
||||||
|
#include <sm_namehashset.h>
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "sm_queue.h"
|
#include "sm_queue.h"
|
||||||
#include <IGameHelpers.h>
|
#include <IGameHelpers.h>
|
||||||
#include <KeyValues.h>
|
#include <KeyValues.h>
|
||||||
#include <server_class.h>
|
#include <server_class.h>
|
||||||
#include <datamap.h>
|
#include <datamap.h>
|
||||||
|
#include <ihandleentity.h>
|
||||||
|
#include <tier0/icommandline.h>
|
||||||
|
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||||
|
#include <string_t.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class CCommand;
|
class CCommand;
|
||||||
|
|
||||||
@@ -54,16 +61,38 @@ using namespace SourceMod;
|
|||||||
|
|
||||||
struct DataTableInfo
|
struct DataTableInfo
|
||||||
{
|
{
|
||||||
|
struct SendPropPolicy
|
||||||
|
{
|
||||||
|
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
|
||||||
|
{
|
||||||
|
return strcmp(name, info.prop->GetName()) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool matches(const char *name, const DataTableInfo *info)
|
||||||
|
{
|
||||||
|
return strcmp(name, info->sc->GetName()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTableInfo(ServerClass *sc)
|
||||||
|
: sc(sc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ServerClass *sc;
|
ServerClass *sc;
|
||||||
KTrie<sm_sendprop_info_t> lookup;
|
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DataMapTrie
|
struct DataMapCachePolicy
|
||||||
{
|
{
|
||||||
DataMapTrie() : trie(NULL) {}
|
static inline bool matches(const char *name, const sm_datatable_info_t &info)
|
||||||
Trie *trie;
|
{
|
||||||
|
return strcmp(name, info.prop->fieldName) == 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
|
||||||
|
|
||||||
struct DelayedFakeCliCmd
|
struct DelayedFakeCliCmd
|
||||||
{
|
{
|
||||||
String cmd;
|
String cmd;
|
||||||
@@ -86,6 +115,20 @@ struct DelayedKickInfo
|
|||||||
char buffer[384];
|
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) && (SOURCE_ENGINE != SE_DOTA)
|
||||||
|
string_t m_iName;
|
||||||
|
string_t m_iClassName;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
class CHalfLife2 :
|
class CHalfLife2 :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IGameHelpers
|
public IGameHelpers
|
||||||
@@ -96,6 +139,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
void OnSourceModStartup(bool late);
|
void OnSourceModStartup(bool late);
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
|
void OnSourceModAllInitialized_Post();
|
||||||
/*void OnSourceModAllShutdown();*/
|
/*void OnSourceModAllShutdown();*/
|
||||||
public: //IGameHelpers
|
public: //IGameHelpers
|
||||||
SendProp *FindInSendTable(const char *classname, const char *offset);
|
SendProp *FindInSendTable(const char *classname, const char *offset);
|
||||||
@@ -103,9 +147,11 @@ public: //IGameHelpers
|
|||||||
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
||||||
ServerClass *FindServerClass(const char *classname);
|
ServerClass *FindServerClass(const char *classname);
|
||||||
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
|
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
|
||||||
|
bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
|
||||||
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
|
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
|
||||||
bool TextMsg(int client, int dest, const char *msg);
|
bool TextMsg(int client, int dest, const char *msg);
|
||||||
bool HintTextMsg(int client, 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 ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show);
|
||||||
bool IsLANServer();
|
bool IsLANServer();
|
||||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
||||||
@@ -115,6 +161,19 @@ public: //IGameHelpers
|
|||||||
void SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt);
|
void SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt);
|
||||||
const char *GetCurrentMap();
|
const char *GetCurrentMap();
|
||||||
void ServerCommand(const char *buffer);
|
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:
|
public:
|
||||||
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
||||||
void ProcessFakeCliCmdQueue();
|
void ProcessFakeCliCmdQueue();
|
||||||
@@ -125,15 +184,19 @@ public:
|
|||||||
const char *CurrentCommandName();
|
const char *CurrentCommandName();
|
||||||
void AddDelayedKick(int client, int userid, const char *msg);
|
void AddDelayedKick(int client, int userid, const char *msg);
|
||||||
void ProcessDelayedKicks();
|
void ProcessDelayedKicks();
|
||||||
#if !defined METAMOD_PLAPI_VERSION
|
#if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11
|
||||||
bool IsOriginalEngine();
|
bool IsOriginalEngine();
|
||||||
#endif
|
#endif
|
||||||
private:
|
private:
|
||||||
DataTableInfo *_FindServerClass(const char *classname);
|
DataTableInfo *_FindServerClass(const char *classname);
|
||||||
private:
|
private:
|
||||||
Trie *m_pClasses;
|
void InitLogicalEntData();
|
||||||
List<DataTableInfo *> m_Tables;
|
void InitCommandLine();
|
||||||
THash<datamap_t *, DataMapTrie> m_Maps;
|
private:
|
||||||
|
typedef ke::HashMap<datamap_t *, DataMapCache *, ke::PointerPolicy<datamap_t> > DataTableMap;
|
||||||
|
|
||||||
|
NameHashSet<DataTableInfo *> m_Classes;
|
||||||
|
DataTableMap m_Maps;
|
||||||
int m_MsgTextMsg;
|
int m_MsgTextMsg;
|
||||||
int m_HinTextMsg;
|
int m_HinTextMsg;
|
||||||
int m_SayTextMsg;
|
int m_SayTextMsg;
|
||||||
@@ -142,10 +205,11 @@ private:
|
|||||||
CStack<DelayedFakeCliCmd *> m_FreeCmds;
|
CStack<DelayedFakeCliCmd *> m_FreeCmds;
|
||||||
CStack<CachedCommandInfo> m_CommandStack;
|
CStack<CachedCommandInfo> m_CommandStack;
|
||||||
Queue<DelayedKickInfo> m_DelayedKicks;
|
Queue<DelayedKickInfo> m_DelayedKicks;
|
||||||
|
void *m_pGetCommandLine;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CHalfLife2 g_HL2;
|
extern CHalfLife2 g_HL2;
|
||||||
|
|
||||||
edict_t *GetEntity(cell_t num, CBaseEntity **pData);
|
bool IndexToAThings(cell_t, CBaseEntity **pEntData, edict_t **pEdictData);
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_
|
#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_
|
||||||
|
|||||||
+12
-10
@@ -241,7 +241,7 @@ bool LibrarySystem::IsPathDirectory(const char *path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined PLATFORM_LINUX
|
#elif defined PLATFORM_POSIX
|
||||||
struct stat s;
|
struct stat s;
|
||||||
|
|
||||||
if (stat(path, &s) != 0)
|
if (stat(path, &s) != 0)
|
||||||
@@ -285,14 +285,16 @@ void LibrarySystem::GetPlatformErrorEx(int code, char *error, size_t maxlength)
|
|||||||
if (error && maxlength)
|
if (error && maxlength)
|
||||||
{
|
{
|
||||||
#if defined PLATFORM_WINDOWS
|
#if defined PLATFORM_WINDOWS
|
||||||
FormatMessageA(
|
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
NULL,
|
||||||
NULL,
|
(DWORD)code,
|
||||||
(DWORD)code,
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
(LPSTR)error,
|
||||||
(LPSTR)error,
|
maxlength,
|
||||||
maxlength,
|
NULL) == 0)
|
||||||
NULL);
|
{
|
||||||
|
UTIL_Format(error, maxlength, "error code %08x", code);
|
||||||
|
}
|
||||||
#elif defined PLATFORM_LINUX
|
#elif defined PLATFORM_LINUX
|
||||||
const char *ae = strerror_r(code, error, maxlength);
|
const char *ae = strerror_r(code, error, maxlength);
|
||||||
if (ae != error)
|
if (ae != error)
|
||||||
@@ -408,7 +410,7 @@ size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char
|
|||||||
size_t length = strlen(path);
|
size_t length = strlen(path);
|
||||||
|
|
||||||
for (size_t i = length - 1;
|
for (size_t i = length - 1;
|
||||||
i >= 0 && i <= length - 1;
|
i <= length - 1;
|
||||||
i--)
|
i--)
|
||||||
{
|
{
|
||||||
if (path[i] == '/'
|
if (path[i] == '/'
|
||||||
|
|||||||
+58
-23
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 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
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -36,10 +36,13 @@
|
|||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "LibrarySys.h"
|
#include "LibrarySys.h"
|
||||||
#include "TimerSys.h"
|
#include "TimerSys.h"
|
||||||
#include "sm_version.h"
|
#include "logic_bridge.h"
|
||||||
|
#include <sourcemod_version.h>
|
||||||
|
|
||||||
Logger g_Logger;
|
Logger g_Logger;
|
||||||
|
|
||||||
|
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* :TODO: This should be creating the log folder if it doesn't exist
|
* :TODO: This should be creating the log folder if it doesn't exist
|
||||||
*/
|
*/
|
||||||
@@ -91,14 +94,27 @@ ConfigResult Logger::OnSourceModConfigChanged(const char *key,
|
|||||||
return ConfigResult_Ignore;
|
return ConfigResult_Ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void HookLogPrint(const char *message)
|
||||||
|
{
|
||||||
|
g_in_game_log_hook = true;
|
||||||
|
bool stopped = logicore.OnLogPrint(message);
|
||||||
|
g_in_game_log_hook = false;
|
||||||
|
|
||||||
|
if (stopped)
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::OnSourceModStartup(bool late)
|
void Logger::OnSourceModStartup(bool late)
|
||||||
{
|
{
|
||||||
InitLogger(m_Mode);
|
InitLogger(m_Mode);
|
||||||
|
|
||||||
|
SH_ADD_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::OnSourceModAllShutdown()
|
void Logger::OnSourceModAllShutdown()
|
||||||
{
|
{
|
||||||
CloseLogger();
|
CloseLogger();
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::OnSourceModLevelChange(const char *mapName)
|
void Logger::OnSourceModLevelChange(const char *mapName)
|
||||||
@@ -149,7 +165,7 @@ void Logger::_NewMapFile()
|
|||||||
} else {
|
} else {
|
||||||
char date[32];
|
char date[32];
|
||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||||
fprintf(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, SOURCEMOD_VERSION);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +212,8 @@ void Logger::InitLogger(LoggingMode mode)
|
|||||||
time_t t;
|
time_t t;
|
||||||
GetAdjustedTime(&t);
|
GetAdjustedTime(&t);
|
||||||
tm *curtime = localtime(&t);
|
tm *curtime = localtime(&t);
|
||||||
m_CurDay = curtime->tm_mday;
|
m_NrmCurDay = curtime->tm_mday;
|
||||||
|
m_ErrCurDay = curtime->tm_mday;
|
||||||
|
|
||||||
char _filename[256];
|
char _filename[256];
|
||||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||||
@@ -265,6 +282,8 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ConVar *sv_logecho = icvar->FindVar("sv_logecho");
|
||||||
|
|
||||||
char buffer[3072];
|
char buffer[3072];
|
||||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||||
|
|
||||||
@@ -275,7 +294,11 @@ void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
|
|||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||||
|
|
||||||
fprintf(fp, "L %s: %s\n", date, buffer);
|
fprintf(fp, "L %s: %s\n", date, buffer);
|
||||||
g_SMAPI->ConPrintf("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)
|
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
|
||||||
@@ -299,6 +322,14 @@ void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Logger::LogMessage(const char *vafmt, ...)
|
void Logger::LogMessage(const char *vafmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, vafmt);
|
||||||
|
LogMessageEx(vafmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::LogMessageEx(const char *vafmt, va_list ap)
|
||||||
{
|
{
|
||||||
if (!m_Active)
|
if (!m_Active)
|
||||||
{
|
{
|
||||||
@@ -307,10 +338,7 @@ void Logger::LogMessage(const char *vafmt, ...)
|
|||||||
|
|
||||||
if (m_Mode == LoggingMode_Game)
|
if (m_Mode == LoggingMode_Game)
|
||||||
{
|
{
|
||||||
va_list ap;
|
|
||||||
va_start(ap, vafmt);
|
|
||||||
_PrintToGameLog(vafmt, ap);
|
_PrintToGameLog(vafmt, ap);
|
||||||
va_end(ap);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,12 +366,12 @@ void Logger::LogMessage(const char *vafmt, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (m_CurDay != curtime->tm_mday)
|
if (m_NrmCurDay != curtime->tm_mday)
|
||||||
{
|
{
|
||||||
char _filename[256];
|
char _filename[256];
|
||||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||||
m_NrmFileName.assign(_filename);
|
m_NrmFileName.assign(_filename);
|
||||||
m_CurDay = curtime->tm_mday;
|
m_NrmCurDay = curtime->tm_mday;
|
||||||
m_DailyPrintHdr = true;
|
m_DailyPrintHdr = true;
|
||||||
}
|
}
|
||||||
fp = fopen(m_NrmFileName.c_str(), "a+");
|
fp = fopen(m_NrmFileName.c_str(), "a+");
|
||||||
@@ -356,12 +384,9 @@ void Logger::LogMessage(const char *vafmt, ...)
|
|||||||
char date[32];
|
char date[32];
|
||||||
m_DailyPrintHdr = false;
|
m_DailyPrintHdr = false;
|
||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
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, SOURCEMOD_VERSION);
|
||||||
}
|
}
|
||||||
va_list ap;
|
|
||||||
va_start(ap, vafmt);
|
|
||||||
LogToOpenFileEx(fp, vafmt, ap);
|
LogToOpenFileEx(fp, vafmt, ap);
|
||||||
va_end(ap);
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
goto print_error;
|
goto print_error;
|
||||||
@@ -378,6 +403,14 @@ print_error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Logger::LogError(const char *vafmt, ...)
|
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)
|
if (!m_Active)
|
||||||
{
|
{
|
||||||
@@ -388,12 +421,12 @@ void Logger::LogError(const char *vafmt, ...)
|
|||||||
GetAdjustedTime(&t);
|
GetAdjustedTime(&t);
|
||||||
tm *curtime = localtime(&t);
|
tm *curtime = localtime(&t);
|
||||||
|
|
||||||
if (curtime->tm_mday != m_CurDay)
|
if (curtime->tm_mday != m_ErrCurDay)
|
||||||
{
|
{
|
||||||
char _filename[256];
|
char _filename[256];
|
||||||
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||||
m_ErrFileName.assign(_filename);
|
m_ErrFileName.assign(_filename);
|
||||||
m_CurDay = curtime->tm_mday;
|
m_ErrCurDay = curtime->tm_mday;
|
||||||
m_ErrMapStart = false;
|
m_ErrMapStart = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,10 +441,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);
|
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;
|
m_ErrMapStart = true;
|
||||||
}
|
}
|
||||||
va_list ap;
|
|
||||||
va_start(ap, vafmt);
|
|
||||||
LogToOpenFileEx(fp, vafmt, ap);
|
LogToOpenFileEx(fp, vafmt, ap);
|
||||||
va_end(ap);
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -515,13 +545,20 @@ void Logger::DisableLogging()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Logger::LogFatal(const char *msg, ...)
|
void Logger::LogFatal(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
LogFatalEx(msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::LogFatalEx(const char *msg, va_list ap)
|
||||||
{
|
{
|
||||||
/* :TODO: make this print all pretty-like
|
/* :TODO: make this print all pretty-like
|
||||||
* In fact, the pretty log printing function should be abstracted.
|
* In fact, the pretty log printing function should be abstracted.
|
||||||
* It's already implemented twice which is bad.
|
* It's already implemented twice which is bad.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
|
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
|
||||||
@@ -530,9 +567,7 @@ void Logger::LogFatal(const char *msg, ...)
|
|||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
m_Active = true;
|
m_Active = true;
|
||||||
va_start(ap, msg);
|
|
||||||
LogToOpenFileEx(fp, msg, ap);
|
LogToOpenFileEx(fp, msg, ap);
|
||||||
va_end(ap);
|
|
||||||
m_Active = false;
|
m_Active = false;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -74,8 +74,11 @@ public:
|
|||||||
void EnableLogging();
|
void EnableLogging();
|
||||||
void DisableLogging();
|
void DisableLogging();
|
||||||
void LogMessage(const char *msg, ...);
|
void LogMessage(const char *msg, ...);
|
||||||
|
void LogMessageEx(const char *msg, va_list ap);
|
||||||
void LogError(const char *msg, ...);
|
void LogError(const char *msg, ...);
|
||||||
|
void LogErrorEx(const char *msg, va_list ap);
|
||||||
void LogFatal(const char *msg, ...);
|
void LogFatal(const char *msg, ...);
|
||||||
|
void LogFatalEx(const char *msg, va_list ap);
|
||||||
void LogToOpenFile(FILE *fp, const char *msg, ...);
|
void LogToOpenFile(FILE *fp, const char *msg, ...);
|
||||||
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
|
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
|
||||||
/* This version does not print to console, and is thus thread-safe */
|
/* This version does not print to console, and is thus thread-safe */
|
||||||
@@ -93,7 +96,8 @@ private:
|
|||||||
String m_ErrFileName;
|
String m_ErrFileName;
|
||||||
String m_CurMapName;
|
String m_CurMapName;
|
||||||
LoggingMode m_Mode;
|
LoggingMode m_Mode;
|
||||||
int m_CurDay;
|
int m_NrmCurDay;
|
||||||
|
int m_ErrCurDay;
|
||||||
bool m_ErrMapStart;
|
bool m_ErrMapStart;
|
||||||
bool m_Active;
|
bool m_Active;
|
||||||
bool m_DelayedStart;
|
bool m_DelayedStart;
|
||||||
|
|||||||
+107
-42
@@ -2,31 +2,33 @@
|
|||||||
# Makefile written by David "BAILOPAN" Anderson
|
# Makefile written by David "BAILOPAN" Anderson
|
||||||
|
|
||||||
SMSDK = ..
|
SMSDK = ..
|
||||||
SRCDS_BASE = ~/srcds
|
|
||||||
HL2SDK_ORIG = ../../hl2sdk
|
HL2SDK_ORIG = ../../hl2sdk
|
||||||
HL2SDK_OB = ../../hl2sdk-ob
|
HL2SDK_OB = ../../hl2sdk-ob
|
||||||
|
HL2SDK_CSS = ../../hl2sdk-css
|
||||||
|
HL2SDK_OB_VALVE = ../../hl2sdk-ob-valve
|
||||||
HL2SDK_L4D = ../../hl2sdk-l4d
|
HL2SDK_L4D = ../../hl2sdk-l4d
|
||||||
MMSOURCE17 = ../../mmsource-1.7
|
HL2SDK_L4D2 = ../../hl2sdk-l4d2
|
||||||
|
HL2SDK_CSGO = ../../hl2sdk-csgo
|
||||||
|
MMSOURCE = ../../mmsource-central
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||||
#####################################
|
#####################################
|
||||||
|
|
||||||
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
|
OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreConfig.cpp \
|
||||||
Database.cpp DebugReporter.cpp EventManager.cpp GameConfigs.cpp HalfLife2.cpp Logger.cpp \
|
Database.cpp DebugReporter.cpp EventManager.cpp HalfLife2.cpp Logger.cpp \
|
||||||
MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \
|
PlayerManager.cpp TimerSys.cpp UserMessages.cpp \
|
||||||
sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.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 \
|
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 \
|
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp \
|
||||||
frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp PhraseCollection.cpp NextMap.cpp \
|
frame_hooks.cpp concmd_cleaner.cpp NextMap.cpp \
|
||||||
NativeOwner.cpp TagsSystem.cpp
|
NativeOwner.cpp logic_bridge.cpp ConsoleDetours.cpp
|
||||||
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
OBJECTS += smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||||
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
|
smn_database.cpp smn_entities.cpp smn_events.cpp \
|
||||||
smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp \
|
smn_fakenatives.cpp smn_filesystem.cpp smn_halflife.cpp \
|
||||||
smn_handles.cpp smn_keyvalues.cpp smn_banning.cpp smn_maplists.cpp \
|
smn_keyvalues.cpp smn_player.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_vector.cpp \
|
||||||
smn_usermsgs.cpp smn_menus.cpp smn_database.cpp smn_vector.cpp smn_adt_array.cpp \
|
smn_hudtext.cpp smn_nextmap.cpp
|
||||||
smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp
|
|
||||||
OBJECTS += ExtensionSys.cpp \
|
OBJECTS += ExtensionSys.cpp \
|
||||||
ForwardSys.cpp \
|
ForwardSys.cpp \
|
||||||
HandleSys.cpp \
|
HandleSys.cpp \
|
||||||
@@ -35,7 +37,6 @@ OBJECTS += ExtensionSys.cpp \
|
|||||||
PluginSys.cpp \
|
PluginSys.cpp \
|
||||||
ShareSys.cpp \
|
ShareSys.cpp \
|
||||||
NativeInvoker.cpp
|
NativeInvoker.cpp
|
||||||
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
|
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||||
@@ -48,53 +49,119 @@ CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
|
|||||||
CPP = gcc
|
CPP = gcc
|
||||||
|
|
||||||
override ENGSET = false
|
override ENGSET = false
|
||||||
|
|
||||||
|
ifneq (,$(filter original orangebox css orangeboxvalve left4dead left4dead2 csgo,$(ENGINE)))
|
||||||
|
override ENGSET = true
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq "$(ENGINE)" "original"
|
ifeq "$(ENGINE)" "original"
|
||||||
HL2SDK = $(HL2SDK_ORIG)
|
HL2SDK = $(HL2SDK_ORIG)
|
||||||
HL2PUB = $(HL2SDK)/public
|
|
||||||
HL2LIB = $(HL2SDK)/linux_sdk
|
HL2LIB = $(HL2SDK)/linux_sdk
|
||||||
CFLAGS += -DSOURCE_ENGINE=1
|
CFLAGS += -DSOURCE_ENGINE=1
|
||||||
METAMOD = $(MMSOURCE17)/core-legacy
|
METAMOD = $(MMSOURCE)/core-legacy
|
||||||
INCLUDE += -I$(HL2SDK)/public/dlls
|
INCLUDE += -I$(HL2SDK)/public/dlls
|
||||||
SRCDS = $(SRCDS_BASE)
|
|
||||||
BINARY = sourcemod.1.ep1.so
|
BINARY = sourcemod.1.ep1.so
|
||||||
override ENGSET = true
|
|
||||||
endif
|
endif
|
||||||
ifeq "$(ENGINE)" "orangebox"
|
ifeq "$(ENGINE)" "orangebox"
|
||||||
HL2SDK = $(HL2SDK_OB)
|
HL2SDK = $(HL2SDK_OB)
|
||||||
HL2PUB = $(HL2SDK)/public
|
|
||||||
HL2LIB = $(HL2SDK)/lib/linux
|
HL2LIB = $(HL2SDK)/lib/linux
|
||||||
CFLAGS += -DSOURCE_ENGINE=3
|
CFLAGS += -DSOURCE_ENGINE=3
|
||||||
METAMOD = $(MMSOURCE17)/core
|
METAMOD = $(MMSOURCE)/core
|
||||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||||
SRCDS = $(SRCDS_BASE)/orangebox
|
|
||||||
BINARY = sourcemod.2.ep2.so
|
BINARY = sourcemod.2.ep2.so
|
||||||
override ENGSET = true
|
endif
|
||||||
|
ifeq "$(ENGINE)" "css"
|
||||||
|
HL2SDK = $(HL2SDK_CSS)
|
||||||
|
HL2LIB = $(HL2SDK)/lib/linux
|
||||||
|
CFLAGS += -DSOURCE_ENGINE=6
|
||||||
|
METAMOD = $(MMSOURCE)/core
|
||||||
|
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||||
|
BINARY = sourcemod.2.css.so
|
||||||
|
endif
|
||||||
|
ifeq "$(ENGINE)" "orangeboxvalve"
|
||||||
|
HL2SDK = $(HL2SDK_OB_VALVE)
|
||||||
|
HL2LIB = $(HL2SDK)/lib/linux
|
||||||
|
CFLAGS += -DSOURCE_ENGINE=7
|
||||||
|
METAMOD = $(MMSOURCE)/core
|
||||||
|
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||||
|
BINARY = sourcemod.2.ep2v.so
|
||||||
endif
|
endif
|
||||||
ifeq "$(ENGINE)" "left4dead"
|
ifeq "$(ENGINE)" "left4dead"
|
||||||
HL2SDK = $(HL2SDK_L4D)
|
HL2SDK = $(HL2SDK_L4D)
|
||||||
HL2PUB = $(HL2SDK)/public
|
|
||||||
HL2LIB = $(HL2SDK)/lib/linux
|
HL2LIB = $(HL2SDK)/lib/linux
|
||||||
CFLAGS += -DSOURCE_ENGINE=4
|
CFLAGS += -DSOURCE_ENGINE=8
|
||||||
METAMOD = $(MMSOURCE17)/core
|
METAMOD = $(MMSOURCE)/core
|
||||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||||
SRCDS = $(SRCDS_BASE)/l4d
|
|
||||||
BINARY = sourcemod.2.l4d.so
|
BINARY = sourcemod.2.l4d.so
|
||||||
override ENGSET = true
|
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
|
endif
|
||||||
|
|
||||||
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_LEFT4DEAD=4
|
HL2PUB = $(HL2SDK)/public
|
||||||
|
|
||||||
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
|
OS := $(shell uname -s)
|
||||||
tier0_i486.so -lpthread -static-libgcc
|
|
||||||
|
ifeq "$(OS)" "Darwin"
|
||||||
|
LIB_EXT = dylib
|
||||||
|
HL2LIB = $(HL2SDK)/lib/mac
|
||||||
|
else
|
||||||
|
LIB_EXT = so
|
||||||
|
ifeq "$(ENGINE)" "original"
|
||||||
|
HL2LIB = $(HL2SDK)/linux_sdk
|
||||||
|
else
|
||||||
|
HL2LIB = $(HL2SDK)/lib/linux
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
|
||||||
|
LIB_SUFFIX = _i486.$(LIB_EXT)
|
||||||
|
else
|
||||||
|
LIB_PREFIX = lib
|
||||||
|
ifneq (,$(filter orangeboxvalve css,$(ENGINE)))
|
||||||
|
ifneq "$(OS)" "Darwin"
|
||||||
|
LIB_SUFFIX = _srv.$(LIB_EXT)
|
||||||
|
else
|
||||||
|
LIB_SUFFIX = .$(LIB_EXT)
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
LIB_SUFFIX = .$(LIB_EXT)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_BLOODYGOODTIME=4 -DSE_EYE=5 \
|
||||||
|
-DSE_CSS=6 -DSE_ORANGEBOXVALVE=7 -DSE_LEFT4DEAD=8 -DSE_LEFT4DEAD2=9 -DSE_ALIENSWARM=10 \
|
||||||
|
-DSE_PORTAL2=11 -DSE_CSGO=12
|
||||||
|
|
||||||
|
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a $(LIB_PREFIX)vstdlib$(LIB_SUFFIX) \
|
||||||
|
$(LIB_PREFIX)tier0$(LIB_SUFFIX) -static-libgcc
|
||||||
|
|
||||||
|
ifeq "$(ENGINE)" "csgo"
|
||||||
|
LINK += $(HL2LIB)/interfaces_i486.a
|
||||||
|
endif
|
||||||
|
|
||||||
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/mathlib -I$(HL2PUB)/vstdlib \
|
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$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook \
|
||||||
-I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
-I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
||||||
|
|
||||||
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
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 \
|
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||||
-Wno-uninitialized -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -m32
|
-Wno-uninitialized -Wno-unused -Wno-switch -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H \
|
||||||
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
-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 ###
|
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||||
@@ -124,15 +191,15 @@ $(BIN_DIR)/%.o: %.c
|
|||||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
all: check
|
all: check
|
||||||
mkdir -p $(BIN_DIR)/systems
|
mkdir -p $(BIN_DIR)
|
||||||
mkdir -p $(BIN_DIR)/thread
|
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX)
|
||||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
|
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX)
|
||||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
|
|
||||||
$(MAKE) -f Makefile sourcemod
|
$(MAKE) -f Makefile sourcemod
|
||||||
|
|
||||||
check:
|
check:
|
||||||
if [ "$(ENGSET)" = "false" ]; then \
|
if [ "$(ENGSET)" = "false" ]; then \
|
||||||
echo "You must supply ENGINE=left4dead or ENGINE=orangebox or ENGINE=original"; \
|
echo "You must supply one of the following values for ENGINE:"; \
|
||||||
|
echo "csgo, left4dead2, left4dead, orangeboxvalve, css, orangebox, or original"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -146,6 +213,4 @@ default: all
|
|||||||
|
|
||||||
clean: check
|
clean: check
|
||||||
rm -rf $(BIN_DIR)/*.o
|
rm -rf $(BIN_DIR)/*.o
|
||||||
rm -rf $(BIN_DIR)/systems/*.o
|
|
||||||
rm -rf $(BIN_DIR)/thread/*.o
|
|
||||||
rm -rf $(BIN_DIR)/$(BINARY)
|
rm -rf $(BIN_DIR)/$(BINARY)
|
||||||
|
|||||||
@@ -1,220 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "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;
|
|
||||||
}
|
|
||||||
+42
-18
@@ -38,10 +38,8 @@
|
|||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "MenuStyle_Valve.h"
|
#include "MenuStyle_Valve.h"
|
||||||
#include "ShareSys.h"
|
|
||||||
#include "HandleSys.h"
|
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "Translator.h"
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
MenuManager g_Menus;
|
MenuManager g_Menus;
|
||||||
VoteMenuHandler s_VoteHandler;
|
VoteMenuHandler s_VoteHandler;
|
||||||
@@ -56,24 +54,24 @@ MenuManager::MenuManager()
|
|||||||
|
|
||||||
void MenuManager::OnSourceModAllInitialized()
|
void MenuManager::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
sharesys->AddInterface(NULL, this);
|
||||||
|
|
||||||
HandleAccess access;
|
HandleAccess access;
|
||||||
g_HandleSys.InitAccessDefaults(NULL, &access);
|
handlesys->InitAccessDefaults(NULL, &access);
|
||||||
|
|
||||||
/* Deny cloning to menus */
|
/* Deny cloning to menus */
|
||||||
access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
||||||
m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
m_MenuType = handlesys->CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||||
|
|
||||||
/* Also deny deletion to styles */
|
/* Also deny deletion to styles */
|
||||||
access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
||||||
m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuManager::OnSourceModAllShutdown()
|
void MenuManager::OnSourceModAllShutdown()
|
||||||
{
|
{
|
||||||
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
|
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
|
||||||
g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
|
handlesys->RemoveType(m_StyleType, g_pCoreIdent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
|
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||||
@@ -112,7 +110,7 @@ Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
|
|||||||
return BAD_HANDLE;
|
return BAD_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
|
return handlesys->CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
|
Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
|
||||||
@@ -122,7 +120,7 @@ Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
|
|||||||
return BAD_HANDLE;
|
return BAD_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
|
return handlesys->CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
|
HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
|
||||||
@@ -132,7 +130,7 @@ HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
|
|||||||
sec.pIdentity = g_pCoreIdent;
|
sec.pIdentity = g_pCoreIdent;
|
||||||
sec.pOwner = NULL;
|
sec.pOwner = NULL;
|
||||||
|
|
||||||
return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
|
return handlesys->ReadHandle(handle, m_MenuType, &sec, (void **)menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
|
HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
|
||||||
@@ -142,7 +140,7 @@ HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
|
|||||||
sec.pIdentity = g_pCoreIdent;
|
sec.pIdentity = g_pCoreIdent;
|
||||||
sec.pOwner = g_pCoreIdent;
|
sec.pOwner = g_pCoreIdent;
|
||||||
|
|
||||||
return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
|
return handlesys->ReadHandle(handle, m_StyleType, &sec, (void **)style);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MenuManager::SetDefaultStyle(IMenuStyle *style)
|
bool MenuManager::SetDefaultStyle(IMenuStyle *style)
|
||||||
@@ -231,6 +229,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
|||||||
unsigned int pgn = menu->GetPagination();
|
unsigned int pgn = menu->GetPagination();
|
||||||
unsigned int maxItems = style->GetMaxPageItems();
|
unsigned int maxItems = style->GetMaxPageItems();
|
||||||
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
|
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)
|
if (pgn != MENU_NO_PAGINATION)
|
||||||
{
|
{
|
||||||
@@ -241,6 +240,11 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
|
|||||||
maxItems--;
|
maxItems--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (novoteButton)
|
||||||
|
{
|
||||||
|
maxItems--;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is very not allowed! */
|
/* This is very not allowed! */
|
||||||
if (maxItems < 2)
|
if (maxItems < 2)
|
||||||
{
|
{
|
||||||
@@ -436,6 +440,20 @@ skip_search:
|
|||||||
/* Draw the item according to the order */
|
/* Draw the item according to the order */
|
||||||
menu_slots_t *slots = md.slots;
|
menu_slots_t *slots = md.slots;
|
||||||
unsigned int position = 0; /* Keep track of the last position */
|
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)
|
if (order == ItemOrder_Ascending)
|
||||||
{
|
{
|
||||||
md.item_on_page = drawItems[0].position;
|
md.item_on_page = drawItems[0].position;
|
||||||
@@ -586,7 +604,7 @@ skip_search:
|
|||||||
{
|
{
|
||||||
if (exitBackButton)
|
if (exitBackButton)
|
||||||
{
|
{
|
||||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
|
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
|
||||||
{
|
{
|
||||||
UTIL_Format(text, sizeof(text), "Back");
|
UTIL_Format(text, sizeof(text), "Back");
|
||||||
}
|
}
|
||||||
@@ -596,7 +614,7 @@ skip_search:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
|
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
|
||||||
{
|
{
|
||||||
UTIL_Format(text, sizeof(text), "Previous");
|
UTIL_Format(text, sizeof(text), "Previous");
|
||||||
}
|
}
|
||||||
@@ -617,7 +635,7 @@ skip_search:
|
|||||||
/* NEXT */
|
/* NEXT */
|
||||||
if (displayNext || canDrawDisabled)
|
if (displayNext || canDrawDisabled)
|
||||||
{
|
{
|
||||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
|
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
|
||||||
{
|
{
|
||||||
UTIL_Format(text, sizeof(text), "Next");
|
UTIL_Format(text, sizeof(text), "Next");
|
||||||
}
|
}
|
||||||
@@ -648,7 +666,7 @@ skip_search:
|
|||||||
/* EXIT */
|
/* EXIT */
|
||||||
if (exitButton)
|
if (exitButton)
|
||||||
{
|
{
|
||||||
if (!CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
|
if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
|
||||||
{
|
{
|
||||||
UTIL_Format(text, sizeof(text), "Exit");
|
UTIL_Format(text, sizeof(text), "Exit");
|
||||||
}
|
}
|
||||||
@@ -798,5 +816,11 @@ bool MenuManager::IsClientInVotePool(int client)
|
|||||||
|
|
||||||
bool MenuManager::RedrawClientVoteMenu(int client)
|
bool MenuManager::RedrawClientVoteMenu(int client)
|
||||||
{
|
{
|
||||||
return s_VoteHandler.RedrawToClient(client);
|
return RedrawClientVoteMenu2(client, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MenuManager::RedrawClientVoteMenu2(int client, bool revote)
|
||||||
|
{
|
||||||
|
return s_VoteHandler.RedrawToClient(client, revote);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,6 @@
|
|||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include "sm_memtable.h"
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
@@ -91,6 +90,7 @@ public:
|
|||||||
unsigned int GetRemainingVoteDelay();
|
unsigned int GetRemainingVoteDelay();
|
||||||
bool IsClientInVotePool(int client);
|
bool IsClientInVotePool(int client);
|
||||||
bool RedrawClientVoteMenu(int client);
|
bool RedrawClientVoteMenu(int client);
|
||||||
|
bool RedrawClientVoteMenu2(int client, bool revote);
|
||||||
public: //IHandleTypeDispatch
|
public: //IHandleTypeDispatch
|
||||||
void OnHandleDestroy(HandleType_t type, void *object);
|
void OnHandleDestroy(HandleType_t type, void *object);
|
||||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
||||||
|
|||||||
+37
-46
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -34,11 +34,12 @@
|
|||||||
#include "MenuStyle_Base.h"
|
#include "MenuStyle_Base.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include "HandleSys.h"
|
|
||||||
#include "CellRecipientFilter.h"
|
#include "CellRecipientFilter.h"
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
#include "AutoHandleRooter.h"
|
||||||
|
|
||||||
BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
|
BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
|
||||||
{
|
{
|
||||||
@@ -322,15 +323,24 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
|||||||
if (pCollideable)
|
if (pCollideable)
|
||||||
{
|
{
|
||||||
const Vector & pos = pCollideable->GetCollisionOrigin();
|
const Vector & pos = pCollideable->GetCollisionOrigin();
|
||||||
|
|
||||||
enginesound->EmitSound(filter,
|
enginesound->EmitSound(filter,
|
||||||
client,
|
client,
|
||||||
CHAN_AUTO,
|
CHAN_AUTO,
|
||||||
|
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||||
|
sound,
|
||||||
|
-1,
|
||||||
|
#endif
|
||||||
sound,
|
sound,
|
||||||
VOL_NORM,
|
VOL_NORM,
|
||||||
ATTN_NORM,
|
ATTN_NORM,
|
||||||
|
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
0,
|
0,
|
||||||
PITCH_NORM,
|
PITCH_NORM,
|
||||||
|
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
&pos);
|
&pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,6 +387,9 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
|||||||
RemoveClientFromWatch(client);
|
RemoveClientFromWatch(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
|
||||||
|
AutoHandleRooter ahr(hndl);
|
||||||
|
|
||||||
if (cancel)
|
if (cancel)
|
||||||
{
|
{
|
||||||
mh->OnMenuCancel(menu, client, reason);
|
mh->OnMenuCancel(menu, client, reason);
|
||||||
@@ -591,7 +604,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
||||||
m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
|
m_pStyle(pStyle), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
|
||||||
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
|
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
|
||||||
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
|
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
|
||||||
{
|
{
|
||||||
@@ -614,94 +627,74 @@ Handle_t CBaseMenu::GetHandle()
|
|||||||
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
||||||
{
|
{
|
||||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
||||||
&& m_items.size() >= m_pStyle->GetMaxPageItems())
|
&& m_items.length() >= m_pStyle->GetMaxPageItems())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CItem item;
|
CItem item;
|
||||||
|
|
||||||
item.infoString = m_Strings.AddString(info);
|
item.info = info;
|
||||||
if (draw.display)
|
if (draw.display)
|
||||||
{
|
item.display = new ke::AString(draw.display);
|
||||||
item.displayString = m_Strings.AddString(draw.display);
|
|
||||||
}
|
|
||||||
item.style = draw.style;
|
item.style = draw.style;
|
||||||
|
|
||||||
m_items.push_back(item);
|
m_items.append(ke::Move(item));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
||||||
{
|
{
|
||||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
|
||||||
&& m_items.size() >= m_pStyle->GetMaxPageItems())
|
m_items.length() >= m_pStyle->GetMaxPageItems())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position >= m_items.size())
|
if (position >= m_items.length())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
CItem item;
|
CItem item;
|
||||||
item.infoString = m_Strings.AddString(info);
|
item.info = info;
|
||||||
if (draw.display)
|
if (draw.display)
|
||||||
{
|
item.display = new ke::AString(draw.display);
|
||||||
item.displayString = m_Strings.AddString(draw.display);
|
|
||||||
}
|
|
||||||
item.style = draw.style;
|
item.style = draw.style;
|
||||||
|
|
||||||
CVector<CItem>::iterator iter = m_items.iterAt(position);
|
m_items.insert(position, ke::Move(item));
|
||||||
m_items.insert(iter, item);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::RemoveItem(unsigned int position)
|
bool CBaseMenu::RemoveItem(unsigned int position)
|
||||||
{
|
{
|
||||||
if (position >= m_items.size())
|
if (position >= m_items.length())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
m_items.erase(m_items.iterAt(position));
|
|
||||||
|
|
||||||
if (m_items.size() == 0)
|
|
||||||
{
|
|
||||||
m_Strings.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m_items.remove(position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBaseMenu::RemoveAllItems()
|
void CBaseMenu::RemoveAllItems()
|
||||||
{
|
{
|
||||||
m_items.clear();
|
m_items.clear();
|
||||||
m_Strings.Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
|
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
|
||||||
{
|
{
|
||||||
if (position >= m_items.size())
|
if (position >= m_items.length())
|
||||||
{
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (draw)
|
if (draw)
|
||||||
{
|
{
|
||||||
draw->display = m_Strings.GetString(m_items[position].displayString);
|
draw->display = m_items[position].display->chars();
|
||||||
draw->style = m_items[position].style;
|
draw->style = m_items[position].style;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_Strings.GetString(m_items[position].infoString);
|
return m_items[position].info.chars();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CBaseMenu::GetItemCount()
|
unsigned int CBaseMenu::GetItemCount()
|
||||||
{
|
{
|
||||||
return m_items.size();
|
return m_items.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
||||||
@@ -734,12 +727,12 @@ IMenuStyle *CBaseMenu::GetDrawStyle()
|
|||||||
|
|
||||||
void CBaseMenu::SetDefaultTitle(const char *message)
|
void CBaseMenu::SetDefaultTitle(const char *message)
|
||||||
{
|
{
|
||||||
m_Title.assign(message);
|
m_Title = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CBaseMenu::GetDefaultTitle()
|
const char *CBaseMenu::GetDefaultTitle()
|
||||||
{
|
{
|
||||||
return m_Title.c_str();
|
return m_Title.chars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBaseMenu::Cancel()
|
void CBaseMenu::Cancel()
|
||||||
@@ -806,7 +799,7 @@ void CBaseMenu::InternalDelete()
|
|||||||
|
|
||||||
m_hHandle = BAD_HANDLE;
|
m_hHandle = BAD_HANDLE;
|
||||||
m_bDeleting = true;
|
m_bDeleting = true;
|
||||||
g_HandleSys.FreeHandle(hndl, &sec);
|
handlesys->FreeHandle(hndl, &sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pHandler->OnMenuDestroy(this);
|
m_pHandler->OnMenuDestroy(this);
|
||||||
@@ -831,7 +824,5 @@ IMenuHandler *CBaseMenu::GetHandler()
|
|||||||
|
|
||||||
unsigned int CBaseMenu::GetBaseMemUsage()
|
unsigned int CBaseMenu::GetBaseMemUsage()
|
||||||
{
|
{
|
||||||
return m_Title.size()
|
return m_Title.length() + (m_items.length() * sizeof(CItem));
|
||||||
+ m_Strings.GetMemTable()->GetMemUsage()
|
|
||||||
+ (m_items.size() * sizeof(CItem));
|
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-12
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -34,29 +34,45 @@
|
|||||||
|
|
||||||
#include <IMenuManager.h>
|
#include <IMenuManager.h>
|
||||||
#include <IPlayerHelpers.h>
|
#include <IPlayerHelpers.h>
|
||||||
#include <sh_string.h>
|
#include <am-string.h>
|
||||||
#include <sh_vector.h>
|
#include <am-vector.h>
|
||||||
#include "sm_memtable.h"
|
|
||||||
#include "sm_fastlink.h"
|
#include "sm_fastlink.h"
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
using namespace SourceHook;
|
|
||||||
|
|
||||||
class CItem
|
class CItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CItem()
|
CItem()
|
||||||
{
|
{
|
||||||
infoString = -1;
|
|
||||||
displayString = -1;
|
|
||||||
style = 0;
|
style = 0;
|
||||||
access = 0;
|
access = 0;
|
||||||
}
|
}
|
||||||
|
CItem(ke::Moveable<CItem> other)
|
||||||
|
: info(ke::Move(other->info)),
|
||||||
|
display(ke::Move(other->display))
|
||||||
|
{
|
||||||
|
style = other->style;
|
||||||
|
access = other->access;
|
||||||
|
}
|
||||||
|
CItem & operator =(ke::Moveable<CItem> other)
|
||||||
|
{
|
||||||
|
info = ke::Move(other->info);
|
||||||
|
display = ke::Move(other->display);
|
||||||
|
style = other->style;
|
||||||
|
access = other->access;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int infoString;
|
ke::AString info;
|
||||||
int displayString;
|
ke::AutoPtr<ke::AString> display;
|
||||||
unsigned int style;
|
unsigned int style;
|
||||||
unsigned int access;
|
unsigned int access;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CItem(const CItem &other) KE_DELETE;
|
||||||
|
CItem &operator =(const CItem &other) KE_DELETE;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CBaseMenuPlayer
|
class CBaseMenuPlayer
|
||||||
@@ -139,11 +155,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
void InternalDelete();
|
void InternalDelete();
|
||||||
protected:
|
protected:
|
||||||
String m_Title;
|
ke::AString m_Title;
|
||||||
IMenuStyle *m_pStyle;
|
IMenuStyle *m_pStyle;
|
||||||
BaseStringTable m_Strings;
|
|
||||||
unsigned int m_Pagination;
|
unsigned int m_Pagination;
|
||||||
CVector<CItem> m_items;
|
ke::Vector<CItem> m_items;
|
||||||
bool m_bShouldDelete;
|
bool m_bShouldDelete;
|
||||||
bool m_bCancelling;
|
bool m_bCancelling;
|
||||||
IdentityToken_t *m_pOwner;
|
IdentityToken_t *m_pOwner;
|
||||||
|
|||||||
@@ -32,11 +32,20 @@
|
|||||||
#include "MenuStyle_Radio.h"
|
#include "MenuStyle_Radio.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "UserMessages.h"
|
#include "UserMessages.h"
|
||||||
#include "GameConfigs.h"
|
#include <IGameConfigs.h>
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#endif
|
#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[];
|
extern const char *g_RadioNumTable[];
|
||||||
CRadioStyle g_RadioMenuStyle;
|
CRadioStyle g_RadioMenuStyle;
|
||||||
@@ -44,6 +53,14 @@ int g_ShowMenuId = -1;
|
|||||||
bool g_bRadioInit = false;
|
bool g_bRadioInit = false;
|
||||||
unsigned int g_RadioMenuTimeout = 0;
|
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()
|
CRadioStyle::CRadioStyle()
|
||||||
{
|
{
|
||||||
m_players = new CRadioMenuPlayer[256+1];
|
m_players = new CRadioMenuPlayer[256+1];
|
||||||
@@ -89,6 +106,18 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
|||||||
g_RadioMenuTimeout = 0;
|
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.AddStyle(this);
|
||||||
g_Menus.SetDefaultStyle(this);
|
g_Menus.SetDefaultStyle(this);
|
||||||
|
|
||||||
@@ -109,7 +138,11 @@ void CRadioStyle::OnSourceModShutdown()
|
|||||||
|
|
||||||
bool CRadioStyle::IsSupported()
|
bool CRadioStyle::IsSupported()
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
return (g_ShowMenuId != -1);
|
return (g_ShowMenuId != -1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
|
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
|
||||||
@@ -134,13 +167,23 @@ static unsigned int g_last_holdtime = 0;
|
|||||||
static unsigned int g_last_client_count = 0;
|
static unsigned int g_last_client_count = 0;
|
||||||
static int g_last_clients[256];
|
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)
|
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE != SE_DOTA
|
||||||
int count = pFilter->GetRecipientCount();
|
int count = pFilter->GetRecipientCount();
|
||||||
|
|
||||||
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||||
|
#else
|
||||||
bf_read br(bf->GetBasePointer(), 3);
|
bf_read br(bf->GetBasePointer(), 3);
|
||||||
|
|
||||||
br.ReadWord();
|
br.ReadWord();
|
||||||
int c = br.ReadChar();
|
int c = br.ReadChar();
|
||||||
|
#endif
|
||||||
|
|
||||||
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
|
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
|
||||||
|
|
||||||
@@ -148,6 +191,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
|
|||||||
{
|
{
|
||||||
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
|
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRadioStyle::OnUserMessageSent(int msg_id)
|
void CRadioStyle::OnUserMessageSent(int msg_id)
|
||||||
@@ -188,7 +232,7 @@ IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwn
|
|||||||
|
|
||||||
unsigned int CRadioStyle::GetMaxPageItems()
|
unsigned int CRadioStyle::GetMaxPageItems()
|
||||||
{
|
{
|
||||||
return 10;
|
return s_RadioMaxPageItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CRadioStyle::GetStyleName()
|
const char *CRadioStyle::GetStyleName()
|
||||||
@@ -306,7 +350,7 @@ unsigned int CRadioDisplay::GetCurrentKey()
|
|||||||
|
|
||||||
bool CRadioDisplay::SetCurrentKey(unsigned int key)
|
bool CRadioDisplay::SetCurrentKey(unsigned int key)
|
||||||
{
|
{
|
||||||
if (key < m_NextPos || m_NextPos > 10)
|
if (key < m_NextPos || m_NextPos > s_RadioMaxPageItems)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -342,7 +386,7 @@ void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
|
|||||||
|
|
||||||
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
|
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
|
||||||
{
|
{
|
||||||
if (m_NextPos > 10 || !CanDrawItem(item.style))
|
if (m_NextPos > s_RadioMaxPageItems || !CanDrawItem(item.style))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -435,7 +479,8 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
|||||||
|
|
||||||
void CRadioMenuPlayer::Radio_Refresh()
|
void CRadioMenuPlayer::Radio_Refresh()
|
||||||
{
|
{
|
||||||
cell_t players[1] = {m_index};
|
#if SOURCE_ENGINE != SE_DOTA
|
||||||
|
cell_t players[1] = { (cell_t)m_index };
|
||||||
char *ptr = display_pkt;
|
char *ptr = display_pkt;
|
||||||
char save = 0;
|
char save = 0;
|
||||||
size_t len = display_len;
|
size_t len = display_len;
|
||||||
@@ -451,6 +496,15 @@ void CRadioMenuPlayer::Radio_Refresh()
|
|||||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
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)
|
while (true)
|
||||||
{
|
{
|
||||||
if (len > 240)
|
if (len > 240)
|
||||||
@@ -458,7 +512,8 @@ void CRadioMenuPlayer::Radio_Refresh()
|
|||||||
save = ptr[240];
|
save = ptr[240];
|
||||||
ptr[240] = '\0';
|
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->WriteWord(display_keys);
|
||||||
buffer->WriteChar(time ? time : -1);
|
buffer->WriteChar(time ? time : -1);
|
||||||
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
||||||
@@ -475,8 +530,10 @@ void CRadioMenuPlayer::Radio_Refresh()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
display_last_refresh = gpGlobals->curtime;
|
display_last_refresh = gpGlobals->curtime;
|
||||||
|
#endif // !DOTA
|
||||||
}
|
}
|
||||||
|
|
||||||
int CRadioDisplay::GetAmountRemaining()
|
int CRadioDisplay::GetAmountRemaining()
|
||||||
@@ -510,6 +567,7 @@ unsigned int CRadioDisplay::GetApproxMemUsage()
|
|||||||
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
|
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
|
||||||
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
|
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
|
||||||
{
|
{
|
||||||
|
m_Pagination = s_RadioMaxPageItems - MAX_PAGINATION_OPTIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
||||||
@@ -550,6 +608,17 @@ bool CRadioMenu::DisplayAtItem(int client,
|
|||||||
time);
|
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()
|
void CRadioMenu::Cancel_Finally()
|
||||||
{
|
{
|
||||||
g_RadioMenuStyle.CancelMenu(this);
|
g_RadioMenuStyle.CancelMenu(this);
|
||||||
|
|||||||
+11
-2
@@ -37,7 +37,7 @@
|
|||||||
#include "MenuStyle_Base.h"
|
#include "MenuStyle_Base.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include <IPlayerHelpers.h>
|
#include <IPlayerHelpers.h>
|
||||||
#include <IUserMessages.h>
|
#include "UserMessages.h"
|
||||||
#include "sm_fastlink.h"
|
#include "sm_fastlink.h"
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include <compat_wrappers.h>
|
#include <compat_wrappers.h>
|
||||||
@@ -65,7 +65,11 @@ private:
|
|||||||
class CRadioStyle :
|
class CRadioStyle :
|
||||||
public BaseMenuStyle,
|
public BaseMenuStyle,
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IUserMessageListener
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
public IProtobufUserMessageListener
|
||||||
|
#else
|
||||||
|
public IBitBufUserMessageListener
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CRadioStyle();
|
CRadioStyle();
|
||||||
@@ -84,7 +88,11 @@ public: //IMenuStyle
|
|||||||
unsigned int GetMaxPageItems();
|
unsigned int GetMaxPageItems();
|
||||||
unsigned int GetApproxMemUsage();
|
unsigned int GetApproxMemUsage();
|
||||||
public: //IUserMessageListener
|
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);
|
void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter);
|
||||||
|
#endif
|
||||||
void OnUserMessageSent(int msg_id);
|
void OnUserMessageSent(int msg_id);
|
||||||
public:
|
public:
|
||||||
bool IsSupported();
|
bool IsSupported();
|
||||||
@@ -142,6 +150,7 @@ public:
|
|||||||
unsigned int time,
|
unsigned int time,
|
||||||
unsigned int start_item,
|
unsigned int start_item,
|
||||||
IMenuHandler *alt_handler/* =NULL */);
|
IMenuHandler *alt_handler/* =NULL */);
|
||||||
|
bool SetPagination(unsigned int itemsPerPage);
|
||||||
void Cancel_Finally();
|
void Cancel_Finally();
|
||||||
unsigned int GetApproxMemUsage();
|
unsigned int GetApproxMemUsage();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "MenuStyle_Valve.h"
|
#include "MenuStyle_Valve.h"
|
||||||
#include "Translator.h"
|
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "ConCmdManager.h"
|
#include "ConCmdManager.h"
|
||||||
|
|
||||||
@@ -66,16 +65,20 @@ bool ValveMenuStyle::OnClientCommand(int client, const char *cmdname, const CCom
|
|||||||
|
|
||||||
void ValveMenuStyle::OnSourceModAllInitialized()
|
void ValveMenuStyle::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE != SE_DOTA
|
||||||
g_Players.AddClientListener(this);
|
g_Players.AddClientListener(this);
|
||||||
SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
|
SH_ADD_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
|
||||||
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
|
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValveMenuStyle::OnSourceModShutdown()
|
void ValveMenuStyle::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE != SE_DOTA
|
||||||
SH_RELEASE_CALLCLASS(g_pSPHCC);
|
SH_RELEASE_CALLCLASS(g_pSPHCC);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
|
SH_REMOVE_HOOK(IServerPluginHelpers, CreateMessage, serverpluginhelpers, SH_MEMBER(this, &ValveMenuStyle::HookCreateMessage), false);
|
||||||
g_Players.RemoveClientListener(this);
|
g_Players.RemoveClientListener(this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
|
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
|
||||||
|
|||||||
+220
-10
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 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
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -34,9 +34,56 @@
|
|||||||
#include "MenuVoting.h"
|
#include "MenuVoting.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "sourcemm_api.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;
|
float g_next_vote = 0.0f;
|
||||||
|
|
||||||
|
#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
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
|
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
|
||||||
#else
|
#else
|
||||||
@@ -117,7 +164,7 @@ void VoteMenuHandler::OnClientDisconnected(int client)
|
|||||||
* newly connected client is not allowed to vote.
|
* newly connected client is not allowed to vote.
|
||||||
*/
|
*/
|
||||||
int item;
|
int item;
|
||||||
if ((item = m_ClientVotes[client]) >= -1)
|
if ((item = m_ClientVotes[client]) >= VOTE_PENDING)
|
||||||
{
|
{
|
||||||
if (item >= 0)
|
if (item >= 0)
|
||||||
{
|
{
|
||||||
@@ -125,7 +172,7 @@ void VoteMenuHandler::OnClientDisconnected(int client)
|
|||||||
assert(m_Votes[item] > 0);
|
assert(m_Votes[item] > 0);
|
||||||
m_Votes[item]--;
|
m_Votes[item]--;
|
||||||
}
|
}
|
||||||
m_ClientVotes[client] = -2;
|
m_ClientVotes[client] = VOTE_NOT_VOTING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,13 +236,13 @@ bool VoteMenuHandler::IsClientInVotePool(int client)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (m_ClientVotes[client] > -2);
|
return (m_ClientVotes[client] > VOTE_NOT_VOTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
|
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
|
||||||
{
|
{
|
||||||
if (!IsClientInVotePool(client)
|
if (!IsClientInVotePool(client)
|
||||||
|| m_ClientVotes[client] == -1)
|
|| m_ClientVotes[client] == VOTE_PENDING)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -205,7 +252,7 @@ bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoteMenuHandler::RedrawToClient(int client)
|
bool VoteMenuHandler::RedrawToClient(int client, bool revotes)
|
||||||
{
|
{
|
||||||
unsigned int time_limit;
|
unsigned int time_limit;
|
||||||
|
|
||||||
@@ -214,6 +261,20 @@ bool VoteMenuHandler::RedrawToClient(int client)
|
|||||||
return false;
|
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)
|
if (m_nMenuTime == MENU_TIME_FOREVER)
|
||||||
{
|
{
|
||||||
time_limit = m_nMenuTime;
|
time_limit = m_nMenuTime;
|
||||||
@@ -247,7 +308,8 @@ bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
|
|||||||
/* Mark all clients as not voting */
|
/* Mark all clients as not voting */
|
||||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
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();
|
m_Items = menu->GetItemCount();
|
||||||
@@ -291,6 +353,8 @@ void VoteMenuHandler::StartVoting()
|
|||||||
|
|
||||||
m_pHandler->OnMenuVoteStart(m_pCurMenu);
|
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.
|
/* By now we know how many clients were set.
|
||||||
* If there are none, we should end IMMEDIATELY.
|
* If there are none, we should end IMMEDIATELY.
|
||||||
*/
|
*/
|
||||||
@@ -298,6 +362,8 @@ void VoteMenuHandler::StartVoting()
|
|||||||
{
|
{
|
||||||
EndVoting();
|
EndVoting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_TotalClients = m_Clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoteMenuHandler::DecrementPlayerCount()
|
void VoteMenuHandler::DecrementPlayerCount()
|
||||||
@@ -334,6 +400,11 @@ void VoteMenuHandler::EndVoting()
|
|||||||
g_next_vote = gpGlobals->curtime + fVoteDelay;
|
g_next_vote = gpGlobals->curtime + fVoteDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_displayTimer)
|
||||||
|
{
|
||||||
|
g_Timers.KillTimer(m_displayTimer);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_bCancelled)
|
if (m_bCancelled)
|
||||||
{
|
{
|
||||||
/* If we were cancelled, don't bother tabulating anything.
|
/* If we were cancelled, don't bother tabulating anything.
|
||||||
@@ -380,7 +451,7 @@ void VoteMenuHandler::EndVoting()
|
|||||||
/* Build the client list */
|
/* Build the client list */
|
||||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
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].client = i;
|
||||||
client_vote[vote.num_clients].item = m_ClientVotes[i];
|
client_vote[vote.num_clients].item = m_ClientVotes[i];
|
||||||
@@ -424,7 +495,7 @@ void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason
|
|||||||
|
|
||||||
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
|
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
|
||||||
{
|
{
|
||||||
m_ClientVotes[client] = -1;
|
m_ClientVotes[client] = VOTE_PENDING;
|
||||||
m_pHandler->OnMenuDisplay(menu, client, display);
|
m_pHandler->OnMenuDisplay(menu, client, display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,6 +517,58 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
|
|||||||
m_ClientVotes[client] = item;
|
m_ClientVotes[client] = item;
|
||||||
m_Votes[item]++;
|
m_Votes[item]++;
|
||||||
m_NumVotes++;
|
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);
|
m_pHandler->OnMenuSelect(menu, client, item);
|
||||||
@@ -468,6 +591,9 @@ void VoteMenuHandler::InternalReset()
|
|||||||
m_NumVotes = 0;
|
m_NumVotes = 0;
|
||||||
m_bCancelled = false;
|
m_bCancelled = false;
|
||||||
m_pHandler = NULL;
|
m_pHandler = NULL;
|
||||||
|
m_leaderList[0] = '\0';
|
||||||
|
m_displayTimer = NULL;
|
||||||
|
m_TotalClients = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoteMenuHandler::CancelVoting()
|
void VoteMenuHandler::CancelVoting()
|
||||||
@@ -489,3 +615,87 @@ bool VoteMenuHandler::IsCancelling()
|
|||||||
{
|
{
|
||||||
return m_bCancelled;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
+14
-2
@@ -36,6 +36,7 @@
|
|||||||
#include <IPlayerHelpers.h>
|
#include <IPlayerHelpers.h>
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
|
#include <TimerSys.h>
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
@@ -43,7 +44,8 @@ using namespace SourceMod;
|
|||||||
class VoteMenuHandler :
|
class VoteMenuHandler :
|
||||||
public IMenuHandler,
|
public IMenuHandler,
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IClientListener
|
public IClientListener,
|
||||||
|
public ITimedEvent
|
||||||
{
|
{
|
||||||
public: //SMGlobalClass
|
public: //SMGlobalClass
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
@@ -61,6 +63,9 @@ public: //IMenuHandler
|
|||||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||||
|
public: //ITimedEvent
|
||||||
|
ResultType OnTimer(ITimer *pTimer, void *pData);
|
||||||
|
void OnTimerEnd(ITimer *pTimer, void *pData);
|
||||||
public:
|
public:
|
||||||
bool StartVote(IBaseMenu *menu,
|
bool StartVote(IBaseMenu *menu,
|
||||||
unsigned int num_clients,
|
unsigned int num_clients,
|
||||||
@@ -74,7 +79,7 @@ public:
|
|||||||
unsigned int GetRemainingVoteDelay();
|
unsigned int GetRemainingVoteDelay();
|
||||||
bool IsClientInVotePool(int client);
|
bool IsClientInVotePool(int client);
|
||||||
bool GetClientVoteChoice(int client, unsigned int *pItem);
|
bool GetClientVoteChoice(int client, unsigned int *pItem);
|
||||||
bool RedrawToClient(int client);
|
bool RedrawToClient(int client, bool revote);
|
||||||
private:
|
private:
|
||||||
void Reset(IMenuHandler *mh);
|
void Reset(IMenuHandler *mh);
|
||||||
void DecrementPlayerCount();
|
void DecrementPlayerCount();
|
||||||
@@ -85,9 +90,12 @@ private:
|
|||||||
unsigned int time,
|
unsigned int time,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
void StartVoting();
|
void StartVoting();
|
||||||
|
void DrawHintProgress();
|
||||||
|
void BuildVoteLeaders();
|
||||||
private:
|
private:
|
||||||
IMenuHandler *m_pHandler;
|
IMenuHandler *m_pHandler;
|
||||||
unsigned int m_Clients;
|
unsigned int m_Clients;
|
||||||
|
unsigned int m_TotalClients;
|
||||||
unsigned int m_Items;
|
unsigned int m_Items;
|
||||||
CVector<unsigned int> m_Votes;
|
CVector<unsigned int> m_Votes;
|
||||||
IBaseMenu *m_pCurMenu;
|
IBaseMenu *m_pCurMenu;
|
||||||
@@ -99,6 +107,10 @@ private:
|
|||||||
float m_fStartTime;
|
float m_fStartTime;
|
||||||
unsigned int m_nMenuTime;
|
unsigned int m_nMenuTime;
|
||||||
int m_ClientVotes[256+1];
|
int m_ClientVotes[256+1];
|
||||||
|
bool m_Revoting[256+1];
|
||||||
|
char m_leaderList[1024];
|
||||||
|
ITimer *m_displayTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_
|
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_
|
||||||
|
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#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_
|
|
||||||
+22
-12
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "NextMap.h"
|
#include "NextMap.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "HalfLife2.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "sourcehook.h"
|
#include "sourcehook.h"
|
||||||
@@ -44,12 +45,18 @@ SH_DECL_HOOK2_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, co
|
|||||||
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
|
SH_DECL_HOOK4_void(IVEngineServer, ChangeLevel, SH_NOATTRIB, 0, const char *, const char *, const char *, bool);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
SH_DECL_EXTERN2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &);
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
|
||||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||||
#else
|
#else
|
||||||
extern bool __SourceHook_FHAddConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
# 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>);
|
extern bool __SourceHook_FHRemoveConCommandDispatch(void *,bool,class fastdelegate::FastDelegate0<void>);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -64,13 +71,13 @@ void NextMapManager::OnSourceModAllInitialized_Post()
|
|||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#else
|
#else
|
||||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ConCommand *pCmd = FindCommand("changelevel");
|
ConCommand *pCmd = FindCommand("changelevel");
|
||||||
if (pCmd != NULL)
|
if (pCmd != NULL)
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CmdChangeLevelCallback, false);
|
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdChangeLevelCallback), false);
|
||||||
changeLevelCmd = pCmd;
|
changeLevelCmd = pCmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,12 +87,12 @@ void NextMapManager::OnSourceModShutdown()
|
|||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#else
|
#else
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, ChangeLevel, engine, this, &NextMapManager::HookChangeLevel, false);
|
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (changeLevelCmd != NULL)
|
if (changeLevelCmd != NULL)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, changeLevelCmd, CmdChangeLevelCallback, false);
|
SH_REMOVE_HOOK(ConCommand, Dispatch, changeLevelCmd, SH_STATIC(CmdChangeLevelCallback), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceHook::List<MapChangeData *>::iterator iter;
|
SourceHook::List<MapChangeData *>::iterator iter;
|
||||||
@@ -105,7 +112,7 @@ const char *NextMapManager::GetNextMap()
|
|||||||
|
|
||||||
bool NextMapManager::SetNextMap(const char *map)
|
bool NextMapManager::SetNextMap(const char *map)
|
||||||
{
|
{
|
||||||
if (!engine->IsMapValid(map))
|
if (!g_HL2.IsMapValid(map))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -129,7 +136,7 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
|
|||||||
|
|
||||||
const char *newmap = sm_nextmap.GetString();
|
const char *newmap = sm_nextmap.GetString();
|
||||||
|
|
||||||
if (newmap[0] == 0 || !engine->IsMapValid(newmap))
|
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
@@ -179,14 +186,14 @@ void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
|||||||
m_tempChangeInfo.m_mapName[0] ='\0';
|
m_tempChangeInfo.m_mapName[0] ='\0';
|
||||||
m_tempChangeInfo.m_changeReason[0] = '\0';
|
m_tempChangeInfo.m_changeReason[0] = '\0';
|
||||||
m_tempChangeInfo.startTime = time(NULL);
|
m_tempChangeInfo.startTime = time(NULL);
|
||||||
UTIL_Format(lastMap, sizeof(lastMap), mapName);
|
UTIL_Format(lastMap, sizeof(lastMap), "%s", mapName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
|
void NextMapManager::ForceChangeLevel( const char *mapName, const char* changeReason )
|
||||||
{
|
{
|
||||||
/* Store the mapname and reason */
|
/* Store the mapname and reason */
|
||||||
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), mapName);
|
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), "%s", mapName);
|
||||||
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), changeReason);
|
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "%s", changeReason);
|
||||||
|
|
||||||
/* Change level and skip our hook */
|
/* Change level and skip our hook */
|
||||||
g_forcedChange = true;
|
g_forcedChange = true;
|
||||||
@@ -200,7 +207,10 @@ NextMapManager::NextMapManager()
|
|||||||
m_mapHistory = SourceHook::List<MapChangeData *>();
|
m_mapHistory = SourceHook::List<MapChangeData *>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command)
|
||||||
|
{
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void CmdChangeLevelCallback(const CCommand &command)
|
void CmdChangeLevelCallback(const CCommand &command)
|
||||||
{
|
{
|
||||||
#else
|
#else
|
||||||
|
|||||||
+7
-3
@@ -53,12 +53,14 @@ struct MapChangeData
|
|||||||
startTime = 0;
|
startTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char m_mapName[32];
|
char m_mapName[PLATFORM_MAX_PATH];
|
||||||
char m_changeReason[100];
|
char m_changeReason[100];
|
||||||
time_t startTime;
|
time_t startTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void CmdChangeLevelCallback(const CCommand &command);
|
void CmdChangeLevelCallback(const CCommand &command);
|
||||||
#else
|
#else
|
||||||
void CmdChangeLevelCallback();
|
void CmdChangeLevelCallback();
|
||||||
@@ -69,7 +71,9 @@ class NextMapManager : public SMGlobalClass
|
|||||||
public:
|
public:
|
||||||
NextMapManager();
|
NextMapManager();
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
friend void CmdChangeLevelCallback(const CCommandContext &context, const CCommand &command);
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
friend void CmdChangeLevelCallback(const CCommand &command);
|
friend void CmdChangeLevelCallback(const CCommand &command);
|
||||||
#else
|
#else
|
||||||
friend void CmdChangeLevelCallback();
|
friend void CmdChangeLevelCallback();
|
||||||
|
|||||||
+854
-166
File diff suppressed because it is too large
Load Diff
+51
-12
@@ -56,7 +56,7 @@ union serial_t
|
|||||||
uint32_t value;
|
uint32_t value;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint8_t index;
|
uint32_t index : 8;
|
||||||
uint32_t serial : 24;
|
uint32_t serial : 24;
|
||||||
} bits;
|
} bits;
|
||||||
};
|
};
|
||||||
@@ -69,25 +69,32 @@ public:
|
|||||||
public:
|
public:
|
||||||
const char *GetName();
|
const char *GetName();
|
||||||
const char *GetIPAddress();
|
const char *GetIPAddress();
|
||||||
const char *GetAuthString();
|
const char *GetAuthString(bool validated = true);
|
||||||
|
unsigned int GetSteamAccountID(bool validated = true);
|
||||||
edict_t *GetEdict();
|
edict_t *GetEdict();
|
||||||
bool IsInGame();
|
bool IsInGame();
|
||||||
bool WasCountedAsInGame();
|
bool WasCountedAsInGame();
|
||||||
bool IsConnected();
|
bool IsConnected();
|
||||||
bool IsAuthorized();
|
bool IsAuthorized();
|
||||||
bool IsFakeClient();
|
bool IsFakeClient();
|
||||||
|
bool IsSourceTV() const;
|
||||||
|
bool IsReplay() const;
|
||||||
void SetAdminId(AdminId id, bool temporary);
|
void SetAdminId(AdminId id, bool temporary);
|
||||||
AdminId GetAdminId();
|
AdminId GetAdminId();
|
||||||
void Kick(const char *str);
|
void Kick(const char *str);
|
||||||
|
bool IsInKickQueue();
|
||||||
IPlayerInfo *GetPlayerInfo();
|
IPlayerInfo *GetPlayerInfo();
|
||||||
unsigned int GetLanguageId();
|
unsigned int GetLanguageId();
|
||||||
|
void SetLanguageId(unsigned int id);
|
||||||
int GetUserId();
|
int GetUserId();
|
||||||
bool RunAdminCacheChecks();
|
bool RunAdminCacheChecks();
|
||||||
void NotifyPostAdminChecks();
|
void NotifyPostAdminChecks();
|
||||||
unsigned int GetSerial();
|
unsigned int GetSerial();
|
||||||
|
int GetIndex() const;
|
||||||
|
void PrintToConsole(const char *pMsg);
|
||||||
|
void ClearAdmin();
|
||||||
public:
|
public:
|
||||||
void DoBasicAdminChecks();
|
void DoBasicAdminChecks();
|
||||||
bool IsInKickQueue();
|
|
||||||
void MarkAsBeingKicked();
|
void MarkAsBeingKicked();
|
||||||
int GetLifeState();
|
int GetLifeState();
|
||||||
private:
|
private:
|
||||||
@@ -96,9 +103,11 @@ private:
|
|||||||
void Disconnect();
|
void Disconnect();
|
||||||
void SetName(const char *name);
|
void SetName(const char *name);
|
||||||
void DumpAdmin(bool deleting);
|
void DumpAdmin(bool deleting);
|
||||||
void Authorize(const char *auth);
|
void SetAuthString(const char *auth);
|
||||||
|
void Authorize();
|
||||||
void Authorize_Post();
|
void Authorize_Post();
|
||||||
void DoPostConnectAuthorization();
|
void DoPostConnectAuthorization();
|
||||||
|
bool IsAuthStringValidated();
|
||||||
private:
|
private:
|
||||||
bool m_IsConnected;
|
bool m_IsConnected;
|
||||||
bool m_IsInGame;
|
bool m_IsInGame;
|
||||||
@@ -118,13 +127,18 @@ private:
|
|||||||
unsigned int m_LangId;
|
unsigned int m_LangId;
|
||||||
int m_UserId;
|
int m_UserId;
|
||||||
bool m_bFakeClient;
|
bool m_bFakeClient;
|
||||||
|
bool m_bIsSourceTV;
|
||||||
|
bool m_bIsReplay;
|
||||||
serial_t m_Serial;
|
serial_t m_Serial;
|
||||||
|
unsigned int m_SteamAccountID;
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
|
QueryCvarCookie_t m_LanguageCookie;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerManager :
|
class PlayerManager :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IPlayerManager,
|
public IPlayerManager
|
||||||
public IConVarChangeListener
|
|
||||||
{
|
{
|
||||||
friend class CPlayer;
|
friend class CPlayer;
|
||||||
public:
|
public:
|
||||||
@@ -139,9 +153,17 @@ public: //SMGlobalClass
|
|||||||
public:
|
public:
|
||||||
CPlayer *GetPlayerByIndex(int client) const;
|
CPlayer *GetPlayerByIndex(int client) const;
|
||||||
void RunAuthChecks();
|
void RunAuthChecks();
|
||||||
void ClearAdminId(AdminId id);
|
|
||||||
void ClearAllAdmins();
|
|
||||||
public:
|
public:
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
bool OnClientConnect(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||||
|
bool OnClientConnect_Post(CEntityIndex index, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||||
|
void OnClientPutInServer(CEntityIndex index, char const *playername);
|
||||||
|
void OnClientDisconnect(CEntityIndex index, int reason);
|
||||||
|
void OnClientDisconnect_Post(CEntityIndex index, int reason);
|
||||||
|
void OnClientCommand(CEntityIndex index, const CCommand &args);
|
||||||
|
void OnClientSettingsChanged(CEntityIndex index);
|
||||||
|
//void OnClientSettingsChanged_Pre(CEntityIndex client);
|
||||||
|
#else
|
||||||
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||||
bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||||
void OnClientPutInServer(edict_t *pEntity, char const *playername);
|
void OnClientPutInServer(edict_t *pEntity, char const *playername);
|
||||||
@@ -154,6 +176,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
void OnClientSettingsChanged(edict_t *pEntity);
|
void OnClientSettingsChanged(edict_t *pEntity);
|
||||||
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
||||||
|
#endif
|
||||||
|
void OnServerHibernationUpdate(bool bHibernating);
|
||||||
public: //IPlayerManager
|
public: //IPlayerManager
|
||||||
void AddClientListener(IClientListener *listener);
|
void AddClientListener(IClientListener *listener);
|
||||||
void RemoveClientListener(IClientListener *listener);
|
void RemoveClientListener(IClientListener *listener);
|
||||||
@@ -169,8 +193,8 @@ public: //IPlayerManager
|
|||||||
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||||
void ProcessCommandTarget(cmd_target_info_t *info);
|
void ProcessCommandTarget(cmd_target_info_t *info);
|
||||||
int GetClientFromSerial(unsigned int serial);
|
int GetClientFromSerial(unsigned int serial);
|
||||||
public: // IConVarChangeListener
|
void ClearAdminId(AdminId id);
|
||||||
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
void RecheckAnyAdmins();
|
||||||
public:
|
public:
|
||||||
inline int MaxClients()
|
inline int MaxClients()
|
||||||
{
|
{
|
||||||
@@ -187,16 +211,23 @@ public:
|
|||||||
bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id);
|
bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id);
|
||||||
bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id);
|
bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id);
|
||||||
const char *GetPassInfoVar();
|
const char *GetPassInfoVar();
|
||||||
void RecheckAnyAdmins();
|
|
||||||
unsigned int GetReplyTo();
|
unsigned int GetReplyTo();
|
||||||
unsigned int SetReplyTo(unsigned int reply);
|
unsigned int SetReplyTo(unsigned int reply);
|
||||||
void MaxPlayersChanged(int newvalue = -1);
|
void MaxPlayersChanged(int newvalue = -1);
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
|
bool HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
||||||
|
#endif
|
||||||
private:
|
private:
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void OnServerActivate();
|
||||||
|
#else
|
||||||
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||||
|
#endif
|
||||||
void InvalidatePlayer(CPlayer *pPlayer);
|
void InvalidatePlayer(CPlayer *pPlayer);
|
||||||
private:
|
private:
|
||||||
List<IClientListener *> m_hooks;
|
List<IClientListener *> m_hooks;
|
||||||
IForward *m_clconnect;
|
IForward *m_clconnect;
|
||||||
|
IForward *m_clconnect_post;
|
||||||
IForward *m_cldisconnect;
|
IForward *m_cldisconnect;
|
||||||
IForward *m_cldisconnect_post;
|
IForward *m_cldisconnect_post;
|
||||||
IForward *m_clputinserver;
|
IForward *m_clputinserver;
|
||||||
@@ -209,15 +240,23 @@ private:
|
|||||||
int *m_UserIdLookUp;
|
int *m_UserIdLookUp;
|
||||||
int m_maxClients;
|
int m_maxClients;
|
||||||
int m_PlayerCount;
|
int m_PlayerCount;
|
||||||
|
int m_PlayersSinceActive;
|
||||||
bool m_FirstPass;
|
bool m_FirstPass;
|
||||||
unsigned int *m_AuthQueue;
|
unsigned int *m_AuthQueue;
|
||||||
String m_PassInfoVar;
|
String m_PassInfoVar;
|
||||||
bool m_QueryLang;
|
bool m_QueryLang;
|
||||||
|
bool m_bAuthstringValidation; // are we validating admins with steam before authorizing?
|
||||||
bool m_bIsListenServer;
|
bool m_bIsListenServer;
|
||||||
int m_ListenClient;
|
int m_ListenClient;
|
||||||
|
bool m_bIsSourceTVActive;
|
||||||
|
bool m_bIsReplayActive;
|
||||||
|
int m_SourceTVUserId;
|
||||||
|
int m_ReplayUserId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
void CmdMaxplayersCallback(const CCommandContext &context, const CCommand &command);
|
||||||
|
#elif SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
void CmdMaxplayersCallback(const CCommand &command);
|
void CmdMaxplayersCallback(const CCommand &command);
|
||||||
#else
|
#else
|
||||||
void CmdMaxplayersCallback();
|
void CmdMaxplayersCallback();
|
||||||
|
|||||||
@@ -1,349 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "PluginInfoDatabase.h"
|
|
||||||
#include "PluginSys.h"
|
|
||||||
|
|
||||||
void PluginSettings::Init()
|
|
||||||
{
|
|
||||||
name = -1;
|
|
||||||
pause_val = false;
|
|
||||||
type_val = PluginType_MapUpdated;
|
|
||||||
optarray = -1;
|
|
||||||
opts_num = 0;
|
|
||||||
opts_size = 0;
|
|
||||||
blockload_val = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* :TODO: write the logger, make these errors log instead of being static
|
|
||||||
* NOTE: once we do that, we will have to change some code to ignore sections
|
|
||||||
*/
|
|
||||||
|
|
||||||
CPluginInfoDatabase::CPluginInfoDatabase()
|
|
||||||
{
|
|
||||||
m_strtab = NULL;
|
|
||||||
m_infodb_count = 0;
|
|
||||||
m_infodb_size = 0;
|
|
||||||
m_infodb = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPluginInfoDatabase::~CPluginInfoDatabase()
|
|
||||||
{
|
|
||||||
delete m_strtab;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginInfoDatabase::ReadSMC_ParseStart()
|
|
||||||
{
|
|
||||||
/* Create or reset our string table */
|
|
||||||
if (m_strtab)
|
|
||||||
{
|
|
||||||
m_strtab->Reset();
|
|
||||||
} else {
|
|
||||||
m_strtab = new BaseStringTable(1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set our internal states to the beginning */
|
|
||||||
in_plugins = false;
|
|
||||||
cur_plugin = -1;
|
|
||||||
in_options = false;
|
|
||||||
m_infodb_size = 0;
|
|
||||||
m_infodb_count = 0;
|
|
||||||
m_infodb = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
char buffer[512];
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
m_errmsg = m_strtab->AddString(buffer);
|
|
||||||
|
|
||||||
return SMCResult_HaltFail;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int CPluginInfoDatabase::GetSettingsNum()
|
|
||||||
{
|
|
||||||
return m_infodb_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
|
|
||||||
{
|
|
||||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
|
||||||
int *table = (int *)memtab->GetAddress(m_infodb);
|
|
||||||
|
|
||||||
if (!table || index >= m_infodb_count)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginSettings *plugin = (PluginSettings *)memtab->GetAddress(table[index]);
|
|
||||||
|
|
||||||
const char *name = m_strtab->GetString(plugin->name);
|
|
||||||
|
|
||||||
if (!name)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_PluginSys.TestAliasMatch(name, filename))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
|
|
||||||
{
|
|
||||||
PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
|
|
||||||
if (!table)
|
|
||||||
{
|
|
||||||
*key = NULL;
|
|
||||||
*val = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_num >= settings->opts_num)
|
|
||||||
{
|
|
||||||
*key = NULL;
|
|
||||||
*val = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*key = m_strtab->GetString(table[opt_num].key);
|
|
||||||
*val = m_strtab->GetString(table[opt_num].val);
|
|
||||||
}
|
|
||||||
|
|
||||||
SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
if (cur_plugin != -1)
|
|
||||||
{
|
|
||||||
PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
|
|
||||||
if (!in_options)
|
|
||||||
{
|
|
||||||
if (strcmp(key, "pause") == 0)
|
|
||||||
{
|
|
||||||
if (strcasecmp(value, "yes") == 0)
|
|
||||||
{
|
|
||||||
plugin->pause_val = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
plugin->pause_val = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(key, "lifetime") == 0)
|
|
||||||
{
|
|
||||||
if (strcasecmp(value, "private") == 0)
|
|
||||||
{
|
|
||||||
plugin->type_val = PluginType_Private;
|
|
||||||
}
|
|
||||||
else if (strcasecmp(value, "mapsync") == 0)
|
|
||||||
{
|
|
||||||
plugin->type_val = PluginType_MapUpdated;
|
|
||||||
}
|
|
||||||
else if (strcasecmp(value, "maponly") == 0)
|
|
||||||
{
|
|
||||||
plugin->type_val = PluginType_MapOnly;
|
|
||||||
}
|
|
||||||
else if (strcasecmp(value, "global") == 0)
|
|
||||||
{
|
|
||||||
plugin->type_val = PluginType_Global;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(key, "blockload") == 0)
|
|
||||||
{
|
|
||||||
plugin->blockload_val = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return MakeError("Unknown property key: \"%s\"", key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Cache every option, valid or not */
|
|
||||||
int keyidx = m_strtab->AddString(key);
|
|
||||||
int validx = m_strtab->AddString(value);
|
|
||||||
PluginOpts *table;
|
|
||||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
|
||||||
plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
|
|
||||||
if (plugin->opts_num + 1 > plugin->opts_size)
|
|
||||||
{
|
|
||||||
unsigned int oldsize = plugin->opts_size;
|
|
||||||
if (oldsize == 0)
|
|
||||||
{
|
|
||||||
//right now we don't have many
|
|
||||||
plugin->opts_size = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
plugin->opts_size *= 2;
|
|
||||||
}
|
|
||||||
int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
|
|
||||||
/* in case it resized */
|
|
||||||
plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
|
|
||||||
if (plugin->optarray != -1)
|
|
||||||
{
|
|
||||||
void *oldtable = memtab->GetAddress(plugin->optarray);
|
|
||||||
memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
|
|
||||||
}
|
|
||||||
plugin->optarray = newidx;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
|
|
||||||
}
|
|
||||||
PluginOpts *opt = &table[plugin->opts_num++];
|
|
||||||
opt->key = keyidx;
|
|
||||||
opt->val = validx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (in_plugins)
|
|
||||||
{
|
|
||||||
return MakeError("Unknown property key: \"%s\"", key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Ignore anything we don't know about! */
|
|
||||||
}
|
|
||||||
|
|
||||||
return SMCResult_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
|
|
||||||
{
|
|
||||||
if (in_plugins)
|
|
||||||
{
|
|
||||||
if (cur_plugin != -1)
|
|
||||||
{
|
|
||||||
if (in_options)
|
|
||||||
{
|
|
||||||
in_options = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* If the plugin is ending, add it to the table */
|
|
||||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
|
||||||
int *table;
|
|
||||||
if (m_infodb_count + 1 > m_infodb_size)
|
|
||||||
{
|
|
||||||
unsigned int oldsize = m_infodb_size;
|
|
||||||
if (!m_infodb_size)
|
|
||||||
{
|
|
||||||
m_infodb_size = 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_infodb_size *= 2;
|
|
||||||
}
|
|
||||||
int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
|
|
||||||
if (m_infodb != -1)
|
|
||||||
{
|
|
||||||
void *oldtable = (int *)memtab->GetAddress(m_infodb);
|
|
||||||
memcpy(table, oldtable, oldsize * sizeof(int));
|
|
||||||
}
|
|
||||||
m_infodb = newidx;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
table = (int *)memtab->GetAddress(m_infodb);
|
|
||||||
}
|
|
||||||
/* Assign to table and scrap the current plugin */
|
|
||||||
table[m_infodb_count++] = cur_plugin;
|
|
||||||
cur_plugin = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
in_plugins = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SMCResult_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SMCResult CPluginInfoDatabase::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
|
||||||
{
|
|
||||||
if (!in_plugins)
|
|
||||||
{
|
|
||||||
/* If we're not in the main Plugins section, and we don't get it for the name, error out */
|
|
||||||
if (strcmp(name, "Plugins") != 0)
|
|
||||||
{
|
|
||||||
return MakeError("Unknown root section: \"%s\"", name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Otherwise set our states */
|
|
||||||
in_plugins = true;
|
|
||||||
cur_plugin = -1;
|
|
||||||
in_options = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (cur_plugin == -1)
|
|
||||||
{
|
|
||||||
/* If we get a plugin node and we don't have a current plugin, create a new one */
|
|
||||||
PluginSettings *plugin;
|
|
||||||
int i_name = m_strtab->AddString(name);
|
|
||||||
cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
|
|
||||||
plugin->Init();
|
|
||||||
plugin->name = i_name;
|
|
||||||
in_options = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!in_options && strcmp(name, "Options") == 0)
|
|
||||||
{
|
|
||||||
in_options = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return MakeError("Unknown plugin sub-section: \"%s\"", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SMCResult_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
|
|
||||||
#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file parses plugin_settings.cfg and stores the information in cached memory.
|
|
||||||
* It provides simplistic abstraction to retrieving the info.
|
|
||||||
* :TODO: currently untested
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sm_memtable.h"
|
|
||||||
#include "ITextParsers.h"
|
|
||||||
#include "IPluginSys.h"
|
|
||||||
#include "sm_globals.h"
|
|
||||||
|
|
||||||
struct PluginOpts
|
|
||||||
{
|
|
||||||
int key;
|
|
||||||
int val;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PluginSettings
|
|
||||||
{
|
|
||||||
void Init();
|
|
||||||
int name;
|
|
||||||
bool pause_val;
|
|
||||||
PluginType type_val;
|
|
||||||
int optarray;
|
|
||||||
size_t opts_num;
|
|
||||||
size_t opts_size;
|
|
||||||
bool blockload_val;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CPluginInfoDatabase : public ITextListener_SMC
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CPluginInfoDatabase();
|
|
||||||
~CPluginInfoDatabase();
|
|
||||||
public: //ITextListener_SMC
|
|
||||||
void ReadSMC_ParseStart();
|
|
||||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
|
||||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
|
||||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Returns the number of plugin settings available.
|
|
||||||
*/
|
|
||||||
unsigned int GetSettingsNum();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an index, returns the plugin settings block if the filename matches.
|
|
||||||
* Otherwise, returns NULL.
|
|
||||||
*/
|
|
||||||
PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a plugin settings struct and an index,
|
|
||||||
* returns the given JIT key/value option pair at that index.
|
|
||||||
* If the input is invalid, key and val will be set to NULL.
|
|
||||||
*/
|
|
||||||
void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
|
|
||||||
private:
|
|
||||||
SMCResult MakeError(const char *fmt, ...);
|
|
||||||
private:
|
|
||||||
BaseStringTable *m_strtab;
|
|
||||||
int m_errmsg;
|
|
||||||
bool in_plugins;
|
|
||||||
bool in_options;
|
|
||||||
int m_infodb;
|
|
||||||
size_t m_infodb_count;
|
|
||||||
size_t m_infodb_size;
|
|
||||||
int cur_plugin;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "TagsSystem.h"
|
|
||||||
#include "sourcemod.h"
|
|
||||||
#include "sourcemm_api.h"
|
|
||||||
#include "sm_stringutil.h"
|
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "compat_wrappers.h"
|
|
||||||
|
|
||||||
TagHandler g_Tags;
|
|
||||||
|
|
||||||
TagHandler::TagHandler()
|
|
||||||
{
|
|
||||||
m_SvTags = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
TagHandler::~TagHandler()
|
|
||||||
{
|
|
||||||
SourceHook::List<char *>::iterator iter = m_TagList.begin();
|
|
||||||
|
|
||||||
while (iter != m_TagList.end())
|
|
||||||
{
|
|
||||||
g_pMemAlloc->Free(*iter);
|
|
||||||
iter = m_TagList.erase(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagHandler::OnSourceModAllInitialized_Post()
|
|
||||||
{
|
|
||||||
g_PluginSys.AddPluginsListener(this);
|
|
||||||
|
|
||||||
m_SvTags = icvar->FindVar("sv_tags");
|
|
||||||
AddTag("sourcemod");
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagHandler::OnSourceModLevelActivated()
|
|
||||||
{
|
|
||||||
SourceHook::List<char *>::iterator iter = m_TagList.begin();
|
|
||||||
|
|
||||||
while (iter != m_TagList.end())
|
|
||||||
{
|
|
||||||
ApplyTag(*iter);
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagHandler::OnSourceModShutdown()
|
|
||||||
{
|
|
||||||
RemoveTag("sourcemod");
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagHandler::OnPluginDestroyed(IPlugin *plugin)
|
|
||||||
{
|
|
||||||
SourceHook::List<char *> *pList = NULL;
|
|
||||||
|
|
||||||
if (!plugin->GetProperty("ServerTags", (void **)&pList, false) || !pList)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceHook::List<char *>::iterator iter = pList->begin();
|
|
||||||
|
|
||||||
while (iter != pList->end())
|
|
||||||
{
|
|
||||||
RemoveTag(*iter);
|
|
||||||
g_pMemAlloc->Free(*iter);
|
|
||||||
iter = pList->erase(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete pList;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TagHandler::AddTag(const char *addTag)
|
|
||||||
{
|
|
||||||
SourceHook::List<char *>::iterator iter = m_TagList.begin();
|
|
||||||
|
|
||||||
while (iter != m_TagList.end())
|
|
||||||
{
|
|
||||||
if (strcmp(*iter, addTag) == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_TagList.push_back(strdup(addTag));
|
|
||||||
ApplyTag(addTag);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TagHandler::RemoveTag(const char *removeTag)
|
|
||||||
{
|
|
||||||
SourceHook::List<char *>::iterator iter = m_TagList.begin();
|
|
||||||
|
|
||||||
while (iter != m_TagList.end())
|
|
||||||
{
|
|
||||||
if (strcmp(*iter, removeTag) == 0)
|
|
||||||
{
|
|
||||||
g_pMemAlloc->Free(*iter);
|
|
||||||
m_TagList.erase(iter);
|
|
||||||
StripTag(removeTag);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagHandler::ApplyTag(const char *addTag)
|
|
||||||
{
|
|
||||||
if (m_SvTags == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *curTags = m_SvTags->GetString();
|
|
||||||
|
|
||||||
if (strstr(curTags, addTag) != NULL)
|
|
||||||
{
|
|
||||||
/* Already tagged */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curTags[0] == '\0')
|
|
||||||
{
|
|
||||||
m_SvTags->SetValue(addTag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* New tags buffer (+2 for , and null char) */
|
|
||||||
size_t newLen = strlen(curTags) + strlen(addTag) + 2;
|
|
||||||
char *newTags = (char *)alloca(newLen);
|
|
||||||
|
|
||||||
g_SourceMod.Format(newTags, newLen, "%s,%s", curTags, addTag);
|
|
||||||
|
|
||||||
m_SvTags->SetValue(newTags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagHandler::StripTag(const char *removeTag)
|
|
||||||
{
|
|
||||||
if (m_SvTags == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *curTags = m_SvTags->GetString();
|
|
||||||
|
|
||||||
if (strcmp(curTags, removeTag) == 0)
|
|
||||||
{
|
|
||||||
m_SvTags->SetValue("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *newTags = strdup(curTags);
|
|
||||||
size_t searchLen = strlen(removeTag) + 2;
|
|
||||||
char *search = (char *)alloca(searchLen);
|
|
||||||
|
|
||||||
if (strncmp(curTags, removeTag, strlen(removeTag)) == 0)
|
|
||||||
{
|
|
||||||
strcpy(search, removeTag);
|
|
||||||
search[searchLen-2] = ',';
|
|
||||||
search[searchLen-1] = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strcpy(search+1, removeTag);
|
|
||||||
search[0] = ',';
|
|
||||||
search[searchLen-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
UTIL_ReplaceAll(newTags, strlen(newTags) + 1, search, "" , true);
|
|
||||||
|
|
||||||
m_SvTags->SetValue(newTags);
|
|
||||||
|
|
||||||
g_pMemAlloc->Free(newTags);
|
|
||||||
}
|
|
||||||
+6
-6
@@ -31,10 +31,10 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "TimerSys.h"
|
#include "TimerSys.h"
|
||||||
#include "ForwardSys.h"
|
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "frame_hooks.h"
|
#include "frame_hooks.h"
|
||||||
#include "ConVarManager.h"
|
#include "ConVarManager.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
#define TIMER_MIN_ACCURACY 0.1
|
#define TIMER_MIN_ACCURACY 0.1
|
||||||
|
|
||||||
@@ -180,9 +180,9 @@ TimerSystem::~TimerSystem()
|
|||||||
|
|
||||||
void TimerSystem::OnSourceModAllInitialized()
|
void TimerSystem::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
sharesys->AddInterface(NULL, this);
|
||||||
m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
|
m_pOnGameFrame = forwardsys->CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
|
||||||
m_pOnMapTimeLeftChanged = g_Forwards.CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
|
m_pOnMapTimeLeftChanged = forwardsys->CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimerSystem::OnSourceModGameInitialized()
|
void TimerSystem::OnSourceModGameInitialized()
|
||||||
@@ -198,8 +198,8 @@ void TimerSystem::OnSourceModGameInitialized()
|
|||||||
void TimerSystem::OnSourceModShutdown()
|
void TimerSystem::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
SetMapTimer(NULL);
|
SetMapTimer(NULL);
|
||||||
g_Forwards.ReleaseForward(m_pOnGameFrame);
|
forwardsys->ReleaseForward(m_pOnGameFrame);
|
||||||
g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged);
|
forwardsys->ReleaseForward(m_pOnMapTimeLeftChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimerSystem::OnSourceModLevelEnd()
|
void TimerSystem::OnSourceModLevelEnd()
|
||||||
|
|||||||
+2
-2
@@ -32,11 +32,11 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_
|
#ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_
|
||||||
#define _INCLUDE_SOURCEMOD_CTIMERSYS_H_
|
#define _INCLUDE_SOURCEMOD_CTIMERSYS_H_
|
||||||
|
|
||||||
#include "ShareSys.h"
|
|
||||||
#include <ITimerSystem.h>
|
#include <ITimerSystem.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
|
#include "sm_globals.h"
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
@@ -78,11 +78,11 @@ public: //ITimerSystem
|
|||||||
float GetTickedTime();
|
float GetTickedTime();
|
||||||
void NotifyOfGameStart(float offset /* = 0.0f */);
|
void NotifyOfGameStart(float offset /* = 0.0f */);
|
||||||
bool GetMapTimeLeft(float *pTime);
|
bool GetMapTimeLeft(float *pTime);
|
||||||
|
IMapTimer *GetMapTimer();
|
||||||
public:
|
public:
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
void RemoveMapChangeTimers();
|
void RemoveMapChangeTimers();
|
||||||
void GameFrame(bool simulating);
|
void GameFrame(bool simulating);
|
||||||
IMapTimer *GetMapTimer();
|
|
||||||
private:
|
private:
|
||||||
List<ITimer *> m_SingleTimers;
|
List<ITimer *> m_SingleTimers;
|
||||||
List<ITimer *> m_LoopTimers;
|
List<ITimer *> m_LoopTimers;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+351
-66
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -31,19 +31,35 @@
|
|||||||
|
|
||||||
#include "UserMessages.h"
|
#include "UserMessages.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
#include <dota_usermessage_helpers.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_CSGO
|
||||||
|
#include <cstrike15_usermessage_helpers.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
UserMessages g_UserMsgs;
|
UserMessages g_UserMsgs;
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||||
|
#else
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
|
SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
|
||||||
#else
|
#else
|
||||||
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
||||||
#endif
|
#endif
|
||||||
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
||||||
|
#endif // ==SE_CSGO
|
||||||
|
|
||||||
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_HookCount = 0;
|
||||||
m_InExec = false;
|
m_InExec = false;
|
||||||
m_InHook = false;
|
m_InHook = false;
|
||||||
@@ -53,8 +69,6 @@ UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
|
|||||||
|
|
||||||
UserMessages::~UserMessages()
|
UserMessages::~UserMessages()
|
||||||
{
|
{
|
||||||
sm_trie_destroy(m_Names);
|
|
||||||
|
|
||||||
CStack<ListenerInfo *>::iterator iter;
|
CStack<ListenerInfo *>::iterator iter;
|
||||||
for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
|
for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
|
||||||
{
|
{
|
||||||
@@ -65,32 +79,46 @@ UserMessages::~UserMessages()
|
|||||||
|
|
||||||
void UserMessages::OnSourceModStartup(bool late)
|
void UserMessages::OnSourceModStartup(bool late)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||||
/* -1 means SourceMM was unable to get the user message list */
|
/* -1 means SourceMM was unable to get the user message list */
|
||||||
m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
|
m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserMessages::OnSourceModAllInitialized()
|
void UserMessages::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
sharesys->AddInterface(NULL, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserMessages::OnSourceModAllShutdown()
|
void UserMessages::OnSourceModAllShutdown()
|
||||||
{
|
{
|
||||||
if (m_HookCount)
|
if (m_HookCount)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
|
#else
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
m_HookCount = 0;
|
m_HookCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UserMessages::GetMessageIndex(const char *msg)
|
int UserMessages::GetMessageIndex(const char *msg)
|
||||||
{
|
{
|
||||||
int msgid;
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
// Can split this per engine and/or game later
|
||||||
|
return g_DotaUsermessageHelpers.GetIndex(msg);
|
||||||
|
#elif SOURCE_ENGINE == SE_CSGO
|
||||||
|
// Can split this per engine and/or game later
|
||||||
|
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
||||||
|
#else
|
||||||
|
|
||||||
if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
|
int msgid;
|
||||||
|
if (!m_Names.retrieve(msg, &msgid))
|
||||||
{
|
{
|
||||||
if (m_FallbackSearch)
|
if (m_FallbackSearch)
|
||||||
{
|
{
|
||||||
@@ -102,7 +130,7 @@ int UserMessages::GetMessageIndex(const char *msg)
|
|||||||
{
|
{
|
||||||
if (strcmp(msgbuf, msg) == 0)
|
if (strcmp(msgbuf, msg) == 0)
|
||||||
{
|
{
|
||||||
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
|
m_Names.insert(msg, msgid);
|
||||||
return msgid;
|
return msgid;
|
||||||
}
|
}
|
||||||
msgid++;
|
msgid++;
|
||||||
@@ -112,16 +140,27 @@ int UserMessages::GetMessageIndex(const char *msg)
|
|||||||
msgid = g_SMAPI->FindUserMessage(msg);
|
msgid = g_SMAPI->FindUserMessage(msg);
|
||||||
|
|
||||||
if (msgid != INVALID_MESSAGE_ID)
|
if (msgid != INVALID_MESSAGE_ID)
|
||||||
{
|
m_Names.insert(msg, msgid);
|
||||||
sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgid;
|
return msgid;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
|
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
|
||||||
{
|
{
|
||||||
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
const char *pszName = g_DotaUsermessageHelpers.GetName(msgid);
|
||||||
|
#elif SOURCE_ENGINE == SE_CSGO
|
||||||
|
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
||||||
|
#endif
|
||||||
|
if (!pszName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
strncopy(buffer, pszName, maxlength);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
if (m_FallbackSearch)
|
if (m_FallbackSearch)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
@@ -137,10 +176,14 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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;
|
bf_write *buffer;
|
||||||
|
|
||||||
if (m_InExec || m_InHook)
|
if (m_InExec || m_InHook)
|
||||||
@@ -168,13 +211,13 @@ bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigne
|
|||||||
|
|
||||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
|
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
|
||||||
#else
|
#else
|
||||||
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
|
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
|
||||||
#else
|
#else
|
||||||
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
|
||||||
@@ -182,6 +225,75 @@ bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigne
|
|||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
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 = GetMessagePrototype(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 = GetMessagePrototype(msg_id)->New();
|
||||||
|
buffer = m_FakeEngineBuffer;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MRES_OVERRIDE:
|
||||||
|
m_FakeEngineBuffer = GetMessagePrototype(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()
|
bool UserMessages::EndMessage()
|
||||||
@@ -191,12 +303,37 @@ bool UserMessages::EndMessage()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||||
|
{
|
||||||
|
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||||
|
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)
|
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||||
{
|
{
|
||||||
ENGINE_CALL(MessageEnd)();
|
ENGINE_CALL(MessageEnd)();
|
||||||
} else {
|
} else {
|
||||||
engine->MessageEnd();
|
engine->MessageEnd();
|
||||||
}
|
}
|
||||||
|
#endif // SE_CSGO || SE_DOTA
|
||||||
|
|
||||||
m_InExec = false;
|
m_InExec = false;
|
||||||
m_CurFlags = 0;
|
m_CurFlags = 0;
|
||||||
@@ -205,31 +342,60 @@ bool UserMessages::EndMessage()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UserMessageType UserMessages::GetUserMessageType() const
|
||||||
|
{
|
||||||
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
return UM_Protobuf;
|
||||||
|
#else
|
||||||
|
return UM_BitBuf;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool UserMessages::HookUserMessage2(int msg_id,
|
bool UserMessages::HookUserMessage2(int msg_id,
|
||||||
IUserMessageListener *pListener,
|
IUserMessageListener *pListener,
|
||||||
bool intercept)
|
bool intercept)
|
||||||
{
|
{
|
||||||
return InternalHook(msg_id, pListener, intercept, true);
|
#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,
|
bool UserMessages::UnhookUserMessage2(int msg_id,
|
||||||
IUserMessageListener *pListener,
|
IUserMessageListener *pListener,
|
||||||
bool intercept)
|
bool intercept)
|
||||||
{
|
{
|
||||||
return InternalUnhook(msg_id, pListener, intercept, true);
|
#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)
|
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
|
||||||
{
|
{
|
||||||
return InternalHook(msg_id, pListener, intercept, false);
|
#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)
|
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
|
||||||
{
|
{
|
||||||
return InternalUnhook(msg_id, pListener, intercept, false);
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
|
||||||
|
#else
|
||||||
|
return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
|
#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)
|
if (msg_id < 0 || msg_id >= 255)
|
||||||
{
|
{
|
||||||
@@ -252,10 +418,15 @@ bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, boo
|
|||||||
|
|
||||||
if (!m_HookCount++)
|
if (!m_HookCount++)
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
|
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
|
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
|
#else
|
||||||
|
SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
|
||||||
|
SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
|
||||||
|
SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
|
||||||
|
SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intercept)
|
if (intercept)
|
||||||
@@ -268,7 +439,22 @@ bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, boo
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UserMessages::InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
|
||||||
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
return g_DotaUsermessageHelpers.GetPrototype(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_CSGO
|
||||||
|
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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;
|
MsgList *pList;
|
||||||
MsgIter iter;
|
MsgIter iter;
|
||||||
@@ -309,14 +495,77 @@ void UserMessages::_DecRefCounter()
|
|||||||
{
|
{
|
||||||
if (--m_HookCount == 0)
|
if (--m_HookCount == 0)
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
|
#else
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
|
||||||
|
SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
||||||
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
|
||||||
|
#elif SOURCE_ENGINE == SE_CSGO
|
||||||
|
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
||||||
|
#endif
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_DOTA
|
||||||
|
OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
|
||||||
|
#elif SOURCE_ENGINE == SE_CSGO
|
||||||
|
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OnMessageEnd_Pre();
|
||||||
|
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||||
|
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 || SOURCE_ENGINE == SE_DOTA
|
||||||
|
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
#else
|
#else
|
||||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
|
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
|
||||||
@@ -329,7 +578,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
|||||||
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
|
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
|
||||||
{
|
{
|
||||||
m_InHook = false;
|
m_InHook = false;
|
||||||
RETURN_META_VALUE(MRES_IGNORED, NULL);
|
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_CurId = msg_type;
|
m_CurId = msg_type;
|
||||||
@@ -339,14 +588,24 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
|||||||
|
|
||||||
if (!is_intercept_empty)
|
if (!is_intercept_empty)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
if (m_InterceptBuffer)
|
||||||
|
delete m_InterceptBuffer;
|
||||||
|
m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
|
||||||
|
|
||||||
|
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
|
||||||
|
#else
|
||||||
m_InterceptBuffer.Reset();
|
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_LEFT4DEAD
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
#else
|
#else
|
||||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
|
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
|
||||||
@@ -354,19 +613,26 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty
|
|||||||
{
|
{
|
||||||
if (!m_InHook)
|
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 *);
|
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()
|
void UserMessages::OnMessageEnd_Post()
|
||||||
{
|
{
|
||||||
if (!m_InHook)
|
if (!m_InHook)
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_IGNORED);
|
UM_RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgList *pList;
|
MsgList *pList;
|
||||||
@@ -434,7 +700,7 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
{
|
{
|
||||||
if (!m_InHook)
|
if (!m_InHook)
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_IGNORED);
|
UM_RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgList *pList;
|
MsgList *pList;
|
||||||
@@ -450,7 +716,11 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
{
|
{
|
||||||
pInfo = (*iter);
|
pInfo = (*iter);
|
||||||
pInfo->IsHooked = true;
|
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);
|
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
|
||||||
|
#endif
|
||||||
|
|
||||||
intercepted = true;
|
intercepted = true;
|
||||||
|
|
||||||
@@ -496,16 +766,13 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handled)
|
if (!handled && intercepted)
|
||||||
{
|
|
||||||
goto supercede;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intercepted)
|
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||||
|
#else
|
||||||
bf_write *engine_bfw;
|
bf_write *engine_bfw;
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
|
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
|
||||||
#else
|
#else
|
||||||
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
|
engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
|
||||||
@@ -513,29 +780,47 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
||||||
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
||||||
ENGINE_CALL(MessageEnd)();
|
ENGINE_CALL(MessageEnd)();
|
||||||
|
#endif // SE_CSGO || SE_DOTA
|
||||||
}
|
}
|
||||||
|
|
||||||
pList = &m_msgHooks[m_CurId];
|
|
||||||
for (iter=pList->begin(); iter!=pList->end(); )
|
|
||||||
{
|
{
|
||||||
pInfo = (*iter);
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
pInfo->IsHooked = true;
|
int size = m_OrigBuffer->ByteSize();
|
||||||
pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
|
uint8 *data = (uint8 *)stackalloc(size);
|
||||||
|
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||||
|
|
||||||
if (pInfo->KillMe)
|
protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
|
||||||
|
pTempMsg->ParsePartialFromArray(data, size);
|
||||||
|
#else
|
||||||
|
bf_write *pTempMsg = m_OrigBuffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pList = &m_msgHooks[m_CurId];
|
||||||
|
for (iter=pList->begin(); iter!=pList->end(); )
|
||||||
{
|
{
|
||||||
iter = pList->erase(iter);
|
pInfo = (*iter);
|
||||||
m_FreeListeners.push(pInfo);
|
pInfo->IsHooked = true;
|
||||||
_DecRefCounter();
|
pInfo->Callback->OnUserMessage(m_CurId, pTempMsg, m_CurRecFilter);
|
||||||
continue;
|
|
||||||
|
if (pInfo->KillMe)
|
||||||
|
{
|
||||||
|
iter = pList->erase(iter);
|
||||||
|
m_FreeListeners.push(pInfo);
|
||||||
|
_DecRefCounter();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pInfo->IsHooked = false;
|
||||||
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pInfo->IsHooked = false;
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
iter++;
|
delete pTempMsg;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
|
UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
|
||||||
supercede:
|
supercede:
|
||||||
m_BlockEndPost = true;
|
m_BlockEndPost = true;
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
UM_RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-11
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -32,20 +32,41 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
#ifndef _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
||||||
#define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
#define _INCLUDE_SOURCEMOD_CUSERMESSAGES_H_
|
||||||
|
|
||||||
#include "ShareSys.h"
|
|
||||||
#include <IUserMessages.h>
|
#include <IUserMessages.h>
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "sm_trie.h"
|
#include <sm_stringhashmap.h>
|
||||||
|
#include "sm_stringutil.h"
|
||||||
#include "CellRecipientFilter.h"
|
#include "CellRecipientFilter.h"
|
||||||
|
#include "sm_globals.h"
|
||||||
|
#include <sh_list.h>
|
||||||
|
#include <sh_stack.h>
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
#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
|
#define INVALID_MESSAGE_ID -1
|
||||||
|
|
||||||
struct ListenerInfo
|
struct ListenerInfo
|
||||||
{
|
{
|
||||||
IUserMessageListener *Callback;
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
|
IProtobufUserMessageListener *Callback;
|
||||||
|
#else
|
||||||
|
IBitBufUserMessageListener *Callback;
|
||||||
|
#endif
|
||||||
bool IsHooked;
|
bool IsHooked;
|
||||||
bool KillMe;
|
bool KillMe;
|
||||||
bool IsNew;
|
bool IsNew;
|
||||||
@@ -70,7 +91,8 @@ public: //IUserMessages
|
|||||||
bool GetMessageName(int msgid, char *buffer, size_t maxlength) const;
|
bool GetMessageName(int msgid, char *buffer, size_t maxlength) const;
|
||||||
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||||
bool UnhookUserMessage(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 EndMessage();
|
||||||
bool HookUserMessage2(int msg_id,
|
bool HookUserMessage2(int msg_id,
|
||||||
IUserMessageListener *pListener,
|
IUserMessageListener *pListener,
|
||||||
@@ -78,8 +100,17 @@ public: //IUserMessages
|
|||||||
bool UnhookUserMessage2(int msg_id,
|
bool UnhookUserMessage2(int msg_id,
|
||||||
IUserMessageListener *pListener,
|
IUserMessageListener *pListener,
|
||||||
bool intercept=false);
|
bool intercept=false);
|
||||||
|
UserMessageType GetUserMessageType() const;
|
||||||
public:
|
public:
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||||
|
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
|
||||||
|
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||||
|
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||||
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
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);
|
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||||
#else
|
#else
|
||||||
@@ -89,24 +120,41 @@ public:
|
|||||||
void OnMessageEnd_Pre();
|
void OnMessageEnd_Pre();
|
||||||
void OnMessageEnd_Post();
|
void OnMessageEnd_Post();
|
||||||
private:
|
private:
|
||||||
bool InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew);
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
bool InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew);
|
const protobuf::Message *GetMessagePrototype(int msg_type);
|
||||||
|
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||||
|
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||||
|
#else
|
||||||
|
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();
|
void _DecRefCounter();
|
||||||
private:
|
private:
|
||||||
List<ListenerInfo *> m_msgHooks[255];
|
List<ListenerInfo *> m_msgHooks[255];
|
||||||
List<ListenerInfo *> m_msgIntercepts[255];
|
List<ListenerInfo *> m_msgIntercepts[255];
|
||||||
CStack<ListenerInfo *> m_FreeListeners;
|
CStack<ListenerInfo *> m_FreeListeners;
|
||||||
unsigned char m_pBase[2500];
|
|
||||||
IRecipientFilter *m_CurRecFilter;
|
IRecipientFilter *m_CurRecFilter;
|
||||||
|
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||||
|
unsigned char m_pBase[2500];
|
||||||
bf_write m_InterceptBuffer;
|
bf_write m_InterceptBuffer;
|
||||||
bf_write *m_OrigBuffer;
|
bf_write *m_OrigBuffer;
|
||||||
bf_read m_ReadBuffer;
|
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;
|
size_t m_HookCount;
|
||||||
bool m_InHook;
|
bool m_InHook;
|
||||||
bool m_BlockEndPost;
|
bool m_BlockEndPost;
|
||||||
|
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||||
bool m_FallbackSearch;
|
bool m_FallbackSearch;
|
||||||
|
|
||||||
Trie *m_Names;
|
StringHashMap<int> m_Names;
|
||||||
|
#endif
|
||||||
CellRecipientFilter m_CellRecFilter;
|
CellRecipientFilter m_CellRecFilter;
|
||||||
bool m_InExec;
|
bool m_InExec;
|
||||||
int m_CurFlags;
|
int m_CurFlags;
|
||||||
|
|||||||
+33
-4
@@ -39,6 +39,9 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
|
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
|
#else
|
||||||
|
SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
@@ -51,29 +54,55 @@ struct ConCommandInfo
|
|||||||
};
|
};
|
||||||
|
|
||||||
List<ConCommandInfo *> tracked_bases;
|
List<ConCommandInfo *> tracked_bases;
|
||||||
|
IConCommandLinkListener *IConCommandLinkListener::head = NULL;
|
||||||
|
|
||||||
ConCommandBase *FindConCommandBase(const char *name);
|
ConCommandBase *FindConCommandBase(const char *name);
|
||||||
|
|
||||||
class ConCommandCleaner : public SMGlobalClass
|
class ConCommandCleaner : public SMGlobalClass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
void OnSourceModAllInitialized()
|
void OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
SH_ADD_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
|
SH_ADD_HOOK(ICvar, UnregisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
|
||||||
|
SH_ADD_HOOK(ICvar, RegisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
|
||||||
|
#else
|
||||||
|
SH_ADD_HOOK(ICvar, RegisterConCommandBase, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSourceModShutdown()
|
void OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
SH_REMOVE_HOOK_MEMFUNC(ICvar, UnregisterConCommand, icvar, this, &ConCommandCleaner::UnlinkConCommandBase, false);
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
}
|
SH_REMOVE_HOOK(ICvar, UnregisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
|
||||||
|
SH_REMOVE_HOOK(ICvar, RegisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
|
||||||
|
#else
|
||||||
|
SH_REMOVE_HOOK(ICvar, RegisterConCommandBase, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkConCommandBase(ConCommandBase *pBase)
|
||||||
|
{
|
||||||
|
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||||
|
while (listener)
|
||||||
|
{
|
||||||
|
listener->OnLinkConCommand(pBase);
|
||||||
|
listener = listener->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UnlinkConCommandBase(ConCommandBase *pBase)
|
void UnlinkConCommandBase(ConCommandBase *pBase)
|
||||||
{
|
{
|
||||||
ConCommandInfo *pInfo;
|
ConCommandInfo *pInfo;
|
||||||
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
|
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
|
||||||
|
|
||||||
|
IConCommandLinkListener *listener = IConCommandLinkListener::head;
|
||||||
|
while (listener)
|
||||||
|
{
|
||||||
|
listener->OnUnlinkConCommand(pBase);
|
||||||
|
listener = listener->next;
|
||||||
|
}
|
||||||
|
|
||||||
if (pBase)
|
if (pBase)
|
||||||
{
|
{
|
||||||
while (iter != tracked_bases.end())
|
while (iter != tracked_bases.end())
|
||||||
|
|||||||
@@ -42,4 +42,26 @@ void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
|||||||
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||||
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
|
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_
|
#endif //_INCLUDE_CONCMD_TRACKER_H_
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define FORCEINLINE_CVAR FORCEINLINE
|
#define FORCEINLINE_CVAR FORCEINLINE
|
||||||
#elif _LINUX
|
#elif defined _LINUX || defined __APPLE__
|
||||||
#define FORCEINLINE_CVAR inline
|
#define FORCEINLINE_CVAR inline
|
||||||
#else
|
#else
|
||||||
#error "implement me"
|
#error "implement me"
|
||||||
@@ -386,6 +386,9 @@ public:
|
|||||||
virtual void SetValue( const char *value );
|
virtual void SetValue( const char *value );
|
||||||
virtual void SetValue( float value );
|
virtual void SetValue( float value );
|
||||||
virtual void SetValue( int value );
|
virtual void SetValue( int value );
|
||||||
|
#if SOURCE_ENGINE >= SE_NUCLEARDAWN
|
||||||
|
virtual void SetValue( Color value );
|
||||||
|
#endif
|
||||||
|
|
||||||
// Reset to default value
|
// Reset to default value
|
||||||
void Revert( void );
|
void Revert( void );
|
||||||
@@ -401,6 +404,9 @@ private:
|
|||||||
// For CVARs marked FCVAR_NEVER_AS_STRING
|
// For CVARs marked FCVAR_NEVER_AS_STRING
|
||||||
virtual void InternalSetFloatValue( float fNewValue );
|
virtual void InternalSetFloatValue( float fNewValue );
|
||||||
virtual void InternalSetIntValue( int nValue );
|
virtual void InternalSetIntValue( int nValue );
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD2
|
||||||
|
virtual void InternalSetColorValue( Color value );
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual bool ClampValue( float& value );
|
virtual bool ClampValue( float& value );
|
||||||
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
|
virtual void ChangeStringValue( const char *tempVal, float flOldValue );
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define FORCEINLINE_CVAR FORCEINLINE
|
#define FORCEINLINE_CVAR FORCEINLINE
|
||||||
#elif _LINUX
|
#elif defined _LINUX || defined __APPLE__
|
||||||
#define FORCEINLINE_CVAR inline
|
#define FORCEINLINE_CVAR inline
|
||||||
#else
|
#else
|
||||||
#error "implement me"
|
#error "implement me"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -30,14 +30,14 @@
|
|||||||
*/
|
*/
|
||||||
#include "frame_hooks.h"
|
#include "frame_hooks.h"
|
||||||
#include "TimerSys.h"
|
#include "TimerSys.h"
|
||||||
#include "Database.h"
|
|
||||||
#include "HalfLife2.h"
|
#include "HalfLife2.h"
|
||||||
#include "MenuStyle_Valve.h"
|
#include "MenuStyle_Valve.h"
|
||||||
#include "MenuStyle_Radio.h"
|
#include "MenuStyle_Radio.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "CoreConfig.h"
|
#include "CoreConfig.h"
|
||||||
#include <sm_queue.h>
|
#include <sm_queue.h>
|
||||||
#include "ThreadSupport.h"
|
#include <IThreader.h>
|
||||||
|
#include "sourcemod.h"
|
||||||
|
|
||||||
static IMutex *frame_mutex;
|
static IMutex *frame_mutex;
|
||||||
static Queue<FrameAction> *frame_queue;
|
static Queue<FrameAction> *frame_queue;
|
||||||
@@ -95,7 +95,6 @@ void RunFrameHooks(bool simulating)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Frame based hooks */
|
/* Frame based hooks */
|
||||||
g_DBMan.RunFrame();
|
|
||||||
g_HL2.ProcessFakeCliCmdQueue();
|
g_HL2.ProcessFakeCliCmdQueue();
|
||||||
g_HL2.ProcessDelayedKicks();
|
g_HL2.ProcessDelayedKicks();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ADTFactory.h"
|
#include "ADTFactory.h"
|
||||||
#include "sm_globals.h"
|
|
||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
|
|
||||||
ADTFactory g_AdtFactory;
|
ADTFactory g_AdtFactory;
|
||||||
@@ -57,32 +56,30 @@ IBasicTrie *ADTFactory::CreateBasicTrie()
|
|||||||
|
|
||||||
BaseTrie::BaseTrie()
|
BaseTrie::BaseTrie()
|
||||||
{
|
{
|
||||||
m_pTrie = sm_trie_create();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseTrie::~BaseTrie()
|
BaseTrie::~BaseTrie()
|
||||||
{
|
{
|
||||||
sm_trie_destroy(m_pTrie);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseTrie::Insert(const char *key, void *value)
|
bool BaseTrie::Insert(const char *key, void *value)
|
||||||
{
|
{
|
||||||
return sm_trie_insert(m_pTrie, key, value);
|
return map_.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseTrie::Retrieve(const char *key, void **value)
|
bool BaseTrie::Retrieve(const char *key, void **value)
|
||||||
{
|
{
|
||||||
return sm_trie_retrieve(m_pTrie, key, value);
|
return map_.retrieve(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseTrie::Delete(const char *key)
|
bool BaseTrie::Delete(const char *key)
|
||||||
{
|
{
|
||||||
return sm_trie_delete(m_pTrie, key);
|
return map_.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTrie::Clear()
|
void BaseTrie::Clear()
|
||||||
{
|
{
|
||||||
sm_trie_clear(m_pTrie);
|
map_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTrie::Destroy()
|
void BaseTrie::Destroy()
|
||||||
@@ -92,5 +89,5 @@ void BaseTrie::Destroy()
|
|||||||
|
|
||||||
bool BaseTrie::Replace(const char *key, void *value)
|
bool BaseTrie::Replace(const char *key, void *value)
|
||||||
{
|
{
|
||||||
return sm_trie_replace(m_pTrie, key, value);
|
return map_.replace(key, value);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
#define _INCLUDE_SOURCEMOD_ADTFACTORY_H_
|
#define _INCLUDE_SOURCEMOD_ADTFACTORY_H_
|
||||||
|
|
||||||
#include <IADTFactory.h>
|
#include <IADTFactory.h>
|
||||||
#include "sm_globals.h"
|
#include "common_logic.h"
|
||||||
#include "sm_trie.h"
|
#include <sm_stringhashmap.h>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
virtual void Clear();
|
virtual void Clear();
|
||||||
virtual void Destroy();
|
virtual void Destroy();
|
||||||
private:
|
private:
|
||||||
Trie *m_pTrie;
|
StringHashMap<void *> map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADTFactory :
|
class ADTFactory :
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
|
import os
|
||||||
|
|
||||||
|
binary = SM.Library(builder, 'sourcemod.logic')
|
||||||
|
binary.compiler.cxxincludes += [
|
||||||
|
os.path.join(builder.sourcePath, 'core', 'logic'),
|
||||||
|
os.path.join(builder.sourcePath, 'public'),
|
||||||
|
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
|
||||||
|
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||||
|
os.path.join(SM.mms_root, 'core', 'sourcehook')
|
||||||
|
]
|
||||||
|
binary.compiler.defines += [
|
||||||
|
'SM_DEFAULT_THREADER',
|
||||||
|
'SM_LOGIC'
|
||||||
|
]
|
||||||
|
|
||||||
|
if builder.target_platform == 'linux':
|
||||||
|
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||||
|
elif builder.target_platform == 'mac':
|
||||||
|
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
||||||
|
binary.compiler.postlink += ['-framework', 'CoreServices']
|
||||||
|
|
||||||
|
if binary.compiler.vendor == 'gcc' or binary.compiler.vendor == 'clang':
|
||||||
|
binary.compiler.cxxflags += ['-fno-rtti']
|
||||||
|
elif binary.compiler.vendor == 'msvc':
|
||||||
|
binary.compiler.cxxflags += ['/GR-']
|
||||||
|
|
||||||
|
binary.sources += [
|
||||||
|
'common_logic.cpp',
|
||||||
|
'smn_adt_array.cpp',
|
||||||
|
'smn_sorting.cpp',
|
||||||
|
'smn_maplists.cpp',
|
||||||
|
'ADTFactory.cpp',
|
||||||
|
'smn_adt_stack.cpp',
|
||||||
|
'thread/ThreadWorker.cpp',
|
||||||
|
'thread/BaseWorker.cpp',
|
||||||
|
'ThreadSupport.cpp',
|
||||||
|
'smn_float.cpp',
|
||||||
|
'TextParsers.cpp',
|
||||||
|
'smn_textparse.cpp',
|
||||||
|
'smn_adt_trie.cpp',
|
||||||
|
'Profiler.cpp',
|
||||||
|
'smn_functions.cpp',
|
||||||
|
'smn_timers.cpp',
|
||||||
|
'smn_players.cpp',
|
||||||
|
'MemoryUtils.cpp',
|
||||||
|
'smn_admin.cpp',
|
||||||
|
'smn_banning.cpp',
|
||||||
|
'smn_filesystem.cpp',
|
||||||
|
'stringutil.cpp',
|
||||||
|
'Translator.cpp',
|
||||||
|
'PhraseCollection.cpp',
|
||||||
|
'smn_lang.cpp',
|
||||||
|
'smn_string.cpp',
|
||||||
|
'smn_handles.cpp',
|
||||||
|
'smn_datapacks.cpp',
|
||||||
|
'smn_gameconfigs.cpp',
|
||||||
|
'smn_fakenatives.cpp',
|
||||||
|
'GameConfigs.cpp',
|
||||||
|
'sm_crc32.cpp',
|
||||||
|
'smn_profiler.cpp',
|
||||||
|
'ShareSys.cpp',
|
||||||
|
'PluginSys.cpp',
|
||||||
|
'HandleSys.cpp',
|
||||||
|
'NativeOwner.cpp',
|
||||||
|
'NativeInvoker.cpp',
|
||||||
|
'ExtensionSys.cpp',
|
||||||
|
'DebugReporter.cpp',
|
||||||
|
'Database.cpp',
|
||||||
|
'smn_database.cpp',
|
||||||
|
'ForwardSys.cpp',
|
||||||
|
'AdminCache.cpp',
|
||||||
|
'sm_trie.cpp',
|
||||||
|
'smn_console.cpp',
|
||||||
|
]
|
||||||
|
if builder.target_platform == 'windows':
|
||||||
|
binary.sources += ['thread/WinThreads.cpp']
|
||||||
|
else:
|
||||||
|
binary.sources += ['thread/PosixThreads.cpp']
|
||||||
|
|
||||||
|
SM.binaries += [builder.Add(binary)]
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,208 +1,226 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* 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
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
* Free Software Foundation.
|
* Free Software Foundation.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* 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
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
* details.
|
* details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
* 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
|
* 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
|
* "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
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
*
|
*
|
||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
#ifndef _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||||
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
#define _INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||||
|
|
||||||
#include "sm_memtable.h"
|
#include "common_logic.h"
|
||||||
#include <sm_trie.h>
|
#include <IAdminSystem.h>
|
||||||
#include <sh_list.h>
|
#include "sm_memtable.h"
|
||||||
#include <sh_string.h>
|
#include <sm_trie.h>
|
||||||
#include <IAdminSystem.h>
|
#include <sh_list.h>
|
||||||
#include "sm_globals.h"
|
#include <sh_string.h>
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
|
#include <sm_stringhashmap.h>
|
||||||
using namespace SourceHook;
|
#include <sm_namehashset.h>
|
||||||
|
|
||||||
#define GRP_MAGIC_SET 0xDEADFADE
|
using namespace SourceHook;
|
||||||
#define GRP_MAGIC_UNSET 0xFACEFACE
|
|
||||||
#define USR_MAGIC_SET 0xDEADFACE
|
#define GRP_MAGIC_SET 0xDEADFADE
|
||||||
#define USR_MAGIC_UNSET 0xFADEDEAD
|
#define GRP_MAGIC_UNSET 0xFACEFACE
|
||||||
|
#define USR_MAGIC_SET 0xDEADFACE
|
||||||
struct AdminGroup
|
#define USR_MAGIC_UNSET 0xFADEDEAD
|
||||||
{
|
|
||||||
uint32_t magic; /* Magic flag, for memory validation (ugh) */
|
typedef StringHashMap<OverrideRule> OverrideMap;
|
||||||
unsigned int immunity_level; /* Immunity level */
|
|
||||||
/* Immune from target table (-1 = nonexistent)
|
struct AdminGroup
|
||||||
* [0] = number of entries
|
{
|
||||||
* [1...N] = immune targets
|
uint32_t magic; /* Magic flag, for memory validation (ugh) */
|
||||||
*/
|
unsigned int immunity_level; /* Immunity level */
|
||||||
int immune_table;
|
/* Immune from target table (-1 = nonexistent)
|
||||||
Trie *pCmdTable; /* Command override table (can be NULL) */
|
* [0] = number of entries
|
||||||
Trie *pCmdGrpTable; /* Command group override table (can be NULL) */
|
* [1...N] = immune targets
|
||||||
int next_grp; /* Next group in the chain */
|
*/
|
||||||
int prev_grp; /* Previous group in the chain */
|
int immune_table;
|
||||||
int nameidx; /* Name */
|
OverrideMap *pCmdTable; /* Command override table (can be NULL) */
|
||||||
FlagBits addflags; /* Additive flags */
|
OverrideMap *pCmdGrpTable; /* Command group override table (can be NULL) */
|
||||||
};
|
int next_grp; /* Next group in the chain */
|
||||||
|
int prev_grp; /* Previous group in the chain */
|
||||||
struct AuthMethod
|
int nameidx; /* Name */
|
||||||
{
|
FlagBits addflags; /* Additive flags */
|
||||||
String name;
|
};
|
||||||
Trie *table;
|
|
||||||
};
|
struct AuthMethod
|
||||||
|
{
|
||||||
struct UserAuth
|
String name;
|
||||||
{
|
StringHashMap<AdminId> identities;
|
||||||
unsigned int index; /* Index into auth table */
|
|
||||||
int identidx; /* Index into the string table */
|
AuthMethod(const char *name)
|
||||||
};
|
: name(name)
|
||||||
|
{
|
||||||
struct AdminUser
|
}
|
||||||
{
|
|
||||||
uint32_t magic; /* Magic flag, for memory validation */
|
static inline bool matches(const char *name, const AuthMethod *method)
|
||||||
FlagBits flags; /* Flags */
|
{
|
||||||
FlagBits eflags; /* Effective flags */
|
return strcmp(name, method->name.c_str()) == 0;
|
||||||
int nameidx; /* Name index */
|
}
|
||||||
int password; /* Password index */
|
};
|
||||||
unsigned int grp_count; /* Number of groups */
|
|
||||||
unsigned int grp_size; /* Size of groups table */
|
struct UserAuth
|
||||||
int grp_table; /* Group table itself */
|
{
|
||||||
int next_user; /* Next user in the list */
|
unsigned int index; /* Index into auth table */
|
||||||
int prev_user; /* Previous user in the list */
|
int identidx; /* Index into the string table */
|
||||||
UserAuth auth; /* Auth method for this user */
|
};
|
||||||
unsigned int immunity_level; /* Immunity level */
|
|
||||||
unsigned int serialchange; /* Serial # for changes */
|
struct AdminUser
|
||||||
};
|
{
|
||||||
|
uint32_t magic; /* Magic flag, for memory validation */
|
||||||
class AdminCache :
|
FlagBits flags; /* Flags */
|
||||||
public IAdminSystem,
|
FlagBits eflags; /* Effective flags */
|
||||||
public SMGlobalClass
|
int nameidx; /* Name index */
|
||||||
{
|
int password; /* Password index */
|
||||||
public:
|
unsigned int grp_count; /* Number of groups */
|
||||||
AdminCache();
|
unsigned int grp_size; /* Size of groups table */
|
||||||
~AdminCache();
|
int grp_table; /* Group table itself */
|
||||||
public: //SMGlobalClass
|
int next_user; /* Next user in the list */
|
||||||
void OnSourceModStartup(bool late);
|
int prev_user; /* Previous user in the list */
|
||||||
void OnSourceModAllInitialized();
|
UserAuth auth; /* Auth method for this user */
|
||||||
void OnSourceModLevelChange(const char *mapName);
|
unsigned int immunity_level; /* Immunity level */
|
||||||
void OnSourceModShutdown();
|
unsigned int serialchange; /* Serial # for changes */
|
||||||
void OnSourceModPluginsLoaded();
|
};
|
||||||
public: //IAdminSystem
|
|
||||||
/** Command cache stuff */
|
class AdminCache :
|
||||||
void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags);
|
public IAdminSystem,
|
||||||
bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *flags);
|
public SMGlobalClass
|
||||||
void UnsetCommandOverride(const char *cmd, OverrideType type);
|
{
|
||||||
/** Group cache stuff */
|
public:
|
||||||
GroupId AddGroup(const char *group_name);
|
AdminCache();
|
||||||
GroupId FindGroupByName(const char *group_name);
|
~AdminCache();
|
||||||
void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled);
|
public: //SMGlobalClass
|
||||||
bool GetGroupAddFlag(GroupId id, AdminFlag flag);
|
void OnSourceModStartup(bool late);
|
||||||
FlagBits GetGroupAddFlags(GroupId id);
|
void OnSourceModAllInitialized();
|
||||||
void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled);
|
void OnSourceModLevelChange(const char *mapName);
|
||||||
bool GetGroupGenericImmunity(GroupId id, ImmunityType type);
|
void OnSourceModShutdown();
|
||||||
void InvalidateGroup(GroupId id);
|
void OnSourceModPluginsLoaded();
|
||||||
void AddGroupImmunity(GroupId id, GroupId other_id);
|
public: //IAdminSystem
|
||||||
unsigned int GetGroupImmunityCount(GroupId id);
|
/** Command cache stuff */
|
||||||
GroupId GetGroupImmunity(GroupId id, unsigned int number);
|
void AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags);
|
||||||
void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule);
|
bool GetCommandOverride(const char *cmd, OverrideType type, FlagBits *flags);
|
||||||
bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule);
|
void UnsetCommandOverride(const char *cmd, OverrideType type);
|
||||||
void DumpAdminCache(AdminCachePart part, bool rebuild);
|
/** Group cache stuff */
|
||||||
void AddAdminListener(IAdminListener *pListener);
|
GroupId AddGroup(const char *group_name);
|
||||||
void RemoveAdminListener(IAdminListener *pListener);
|
GroupId FindGroupByName(const char *group_name);
|
||||||
/** User stuff */
|
void SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled);
|
||||||
void RegisterAuthIdentType(const char *name);
|
bool GetGroupAddFlag(GroupId id, AdminFlag flag);
|
||||||
AdminId CreateAdmin(const char *name);
|
FlagBits GetGroupAddFlags(GroupId id);
|
||||||
const char *GetAdminName(AdminId id);
|
void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled);
|
||||||
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
|
bool GetGroupGenericImmunity(GroupId id, ImmunityType type);
|
||||||
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
|
void InvalidateGroup(GroupId id);
|
||||||
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
|
void AddGroupImmunity(GroupId id, GroupId other_id);
|
||||||
FlagBits GetAdminFlags(AdminId id, AccessMode mode);
|
unsigned int GetGroupImmunityCount(GroupId id);
|
||||||
bool AdminInheritGroup(AdminId id, GroupId gid);
|
GroupId GetGroupImmunity(GroupId id, unsigned int number);
|
||||||
unsigned int GetAdminGroupCount(AdminId id);
|
void AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule);
|
||||||
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
|
bool GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule);
|
||||||
void SetAdminPassword(AdminId id, const char *password);
|
void DumpAdminCache(AdminCachePart part, bool rebuild);
|
||||||
const char *GetAdminPassword(AdminId id);
|
void AddAdminListener(IAdminListener *pListener);
|
||||||
AdminId FindAdminByIdentity(const char *auth, const char *identity);
|
void RemoveAdminListener(IAdminListener *pListener);
|
||||||
bool InvalidateAdmin(AdminId id);
|
/** User stuff */
|
||||||
unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize);
|
void RegisterAuthIdentType(const char *name);
|
||||||
FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize);
|
AdminId CreateAdmin(const char *name);
|
||||||
FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags);
|
const char *GetAdminName(AdminId id);
|
||||||
unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize);
|
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
|
||||||
bool CheckAdminFlags(AdminId id, FlagBits bits);
|
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
|
||||||
bool CanAdminTarget(AdminId id, AdminId target);
|
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
|
||||||
void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
|
FlagBits GetAdminFlags(AdminId id, AccessMode mode);
|
||||||
bool FindFlag(const char *str, AdminFlag *pFlag);
|
bool AdminInheritGroup(AdminId id, GroupId gid);
|
||||||
bool FindFlag(char c, AdminFlag *pAdmFlag);
|
unsigned int GetAdminGroupCount(AdminId id);
|
||||||
FlagBits ReadFlagString(const char *flags, const char **end);
|
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
|
||||||
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
|
void SetAdminPassword(AdminId id, const char *password);
|
||||||
unsigned int GetAdminSerialChange(AdminId id);
|
const char *GetAdminPassword(AdminId id);
|
||||||
bool CanAdminUseCommand(int client, const char *cmd);
|
AdminId FindAdminByIdentity(const char *auth, const char *identity);
|
||||||
const char *GetGroupName(GroupId gid);
|
bool InvalidateAdmin(AdminId id);
|
||||||
unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
|
unsigned int FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize);
|
||||||
unsigned int GetGroupImmunityLevel(GroupId gid);
|
FlagBits FlagBitArrayToBits(const bool array[], unsigned int maxSize);
|
||||||
unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
|
FlagBits FlagArrayToBits(const AdminFlag array[], unsigned int numFlags);
|
||||||
unsigned int GetAdminImmunityLevel(AdminId id);
|
unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize);
|
||||||
bool CheckAccess(int client,
|
bool CheckAdminFlags(AdminId id, FlagBits bits);
|
||||||
const char *cmd,
|
bool CanAdminTarget(AdminId id, AdminId target);
|
||||||
FlagBits flags,
|
void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
|
||||||
bool override_only);
|
bool FindFlag(const char *str, AdminFlag *pFlag);
|
||||||
bool FindFlagChar(AdminFlag flag, char *c);
|
bool FindFlag(char c, AdminFlag *pAdmFlag);
|
||||||
public:
|
FlagBits ReadFlagString(const char *flags, const char **end);
|
||||||
bool IsValidAdmin(AdminId id);
|
size_t FillFlagString(FlagBits bits, char *buffer, size_t maxlen);
|
||||||
void DumpCache(FILE *fp);
|
unsigned int GetAdminSerialChange(AdminId id);
|
||||||
AdminGroup *GetGroup(GroupId gid);
|
bool CanAdminUseCommand(int client, const char *cmd);
|
||||||
AdminUser *GetUser(AdminId id);
|
const char *GetGroupName(GroupId gid);
|
||||||
const char *GetString(int idx);
|
unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
|
||||||
private:
|
unsigned int GetGroupImmunityLevel(GroupId gid);
|
||||||
void _UnsetCommandOverride(const char *cmd);
|
unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
|
||||||
void _UnsetCommandGroupOverride(const char *group);
|
unsigned int GetAdminImmunityLevel(AdminId id);
|
||||||
void InvalidateGroupCache();
|
bool CheckAccess(int client,
|
||||||
void InvalidateAdminCache(bool unlink_admins);
|
const char *cmd,
|
||||||
void DumpCommandOverrideCache(OverrideType type);
|
FlagBits flags,
|
||||||
Trie *GetMethodByIndex(unsigned int index);
|
bool override_only);
|
||||||
bool GetMethodIndex(const char *name, unsigned int *_index);
|
bool FindFlagChar(AdminFlag flag, char *c);
|
||||||
const char *GetMethodName(unsigned int index);
|
bool IsValidAdmin(AdminId id);
|
||||||
void NameFlag(const char *str, AdminFlag flag);
|
bool CheckClientCommandAccess(int client, const char *cmd, FlagBits cmdflags);
|
||||||
public:
|
public:
|
||||||
BaseStringTable *m_pStrings;
|
void DumpCache(FILE *fp);
|
||||||
BaseMemTable *m_pMemory;
|
AdminGroup *GetGroup(GroupId gid);
|
||||||
Trie *m_pCmdOverrides;
|
AdminUser *GetUser(AdminId id);
|
||||||
Trie *m_pCmdGrpOverrides;
|
const char *GetString(int idx);
|
||||||
int m_FirstGroup;
|
bool CheckAdminCommandAccess(AdminId adm, const char *cmd, FlagBits flags);
|
||||||
int m_LastGroup;
|
private:
|
||||||
int m_FreeGroupList;
|
void _UnsetCommandOverride(const char *cmd);
|
||||||
Trie *m_pGroups;
|
void _UnsetCommandGroupOverride(const char *group);
|
||||||
List<IAdminListener *> m_hooks;
|
void InvalidateGroupCache();
|
||||||
List<AuthMethod> m_AuthMethods;
|
void InvalidateAdminCache(bool unlink_admins);
|
||||||
Trie *m_pAuthTables;
|
void DumpCommandOverrideCache(OverrideType type);
|
||||||
IForward *m_pCacheFwd;
|
AuthMethod *GetMethodByIndex(unsigned int index);
|
||||||
int m_FirstUser;
|
bool GetMethodIndex(const char *name, unsigned int *_index);
|
||||||
int m_LastUser;
|
const char *GetMethodName(unsigned int index);
|
||||||
int m_FreeUserList;
|
void NameFlag(const char *str, AdminFlag flag);
|
||||||
bool m_InvalidatingAdmins;
|
public:
|
||||||
bool m_destroying;
|
typedef StringHashMap<FlagBits> FlagMap;
|
||||||
Trie *m_pLevelNames;
|
|
||||||
};
|
BaseStringTable *m_pStrings;
|
||||||
|
BaseMemTable *m_pMemory;
|
||||||
extern AdminCache g_Admins;
|
FlagMap m_CmdOverrides;
|
||||||
|
FlagMap m_CmdGrpOverrides;
|
||||||
#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
int m_FirstGroup;
|
||||||
|
int m_LastGroup;
|
||||||
|
int m_FreeGroupList;
|
||||||
|
StringHashMap<GroupId> m_Groups;
|
||||||
|
List<IAdminListener *> m_hooks;
|
||||||
|
List<AuthMethod *> m_AuthMethods;
|
||||||
|
NameHashSet<AuthMethod *> m_AuthTables;
|
||||||
|
IForward *m_pCacheFwd;
|
||||||
|
int m_FirstUser;
|
||||||
|
int m_LastUser;
|
||||||
|
int m_FreeUserList;
|
||||||
|
bool m_InvalidatingAdmins;
|
||||||
|
bool m_destroying;
|
||||||
|
StringHashMap<AdminFlag> m_LevelNames;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern AdminCache g_Admins;
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_ADMINCACHE_H_
|
||||||
@@ -29,6 +29,9 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CELLARRAY_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CELLARRAY_H_
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -204,3 +207,6 @@ private:
|
|||||||
size_t m_AllocSize;
|
size_t m_AllocSize;
|
||||||
size_t m_Size;
|
size_t m_Size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif /* _INCLUDE_SOURCEMOD_CELLARRAY_H_ */
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -30,14 +30,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
|
#include "ISourceMod.h"
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include "ShareSys.h"
|
|
||||||
#include "sourcemod.h"
|
|
||||||
#include "sm_stringutil.h"
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
|
#include "PluginSys.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "ThreadSupport.h"
|
#include <IThreader.h>
|
||||||
|
|
||||||
#define DBPARSE_LEVEL_NONE 0
|
#define DBPARSE_LEVEL_NONE 0
|
||||||
#define DBPARSE_LEVEL_MAIN 1
|
#define DBPARSE_LEVEL_MAIN 1
|
||||||
@@ -47,10 +45,18 @@ DBManager g_DBMan;
|
|||||||
static bool s_OneTimeThreaderErrorMsg = false;
|
static bool s_OneTimeThreaderErrorMsg = false;
|
||||||
|
|
||||||
DBManager::DBManager()
|
DBManager::DBManager()
|
||||||
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
|
: m_Terminate(false),
|
||||||
|
m_ParseLevel(0),
|
||||||
|
m_ParseState(0),
|
||||||
|
m_pDefault(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FrameHook(bool simulating)
|
||||||
|
{
|
||||||
|
g_DBMan.RunFrame();
|
||||||
|
}
|
||||||
|
|
||||||
void DBManager::OnSourceModAllInitialized()
|
void DBManager::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
HandleAccess sec;
|
HandleAccess sec;
|
||||||
@@ -64,13 +70,11 @@ void DBManager::OnSourceModAllInitialized()
|
|||||||
|
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
g_ShareSys.AddInterface(NULL, this);
|
||||||
|
|
||||||
g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
|
g_pSM->BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
|
||||||
|
|
||||||
m_pConfigLock = g_pThreader->MakeMutex();
|
|
||||||
m_pThinkLock = g_pThreader->MakeMutex();
|
|
||||||
m_pQueueLock = g_pThreader->MakeMutex();
|
|
||||||
|
|
||||||
g_PluginSys.AddPluginsListener(this);
|
g_PluginSys.AddPluginsListener(this);
|
||||||
|
|
||||||
|
g_pSM->AddGameFrameHook(&FrameHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::OnSourceModLevelChange(const char *mapName)
|
void DBManager::OnSourceModLevelChange(const char *mapName)
|
||||||
@@ -82,28 +86,26 @@ void DBManager::OnSourceModLevelChange(const char *mapName)
|
|||||||
* This way the thread's search won't be searching through a
|
* This way the thread's search won't be searching through a
|
||||||
* potentially empty/corrupt list, which would be very bad.
|
* potentially empty/corrupt list, which would be very bad.
|
||||||
*/
|
*/
|
||||||
m_pConfigLock->Lock();
|
ke::AutoLock lock(&m_ConfigLock);
|
||||||
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
|
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
smcore.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
||||||
if (err != SMCError_Custom)
|
if (err != SMCError_Custom)
|
||||||
{
|
{
|
||||||
const char *txt = textparsers->GetSMCErrorString(err);
|
const char *txt = textparsers->GetSMCErrorString(err);
|
||||||
g_Logger.LogError("[SM] Line %d: %s", states.line, txt);
|
smcore.LogError("[SM] Line %d: %s", states.line, txt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_pConfigLock->Unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::OnSourceModShutdown()
|
void DBManager::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
|
g_pSM->RemoveGameFrameHook(&FrameHook);
|
||||||
KillWorkerThread();
|
KillWorkerThread();
|
||||||
g_PluginSys.RemovePluginsListener(this);
|
g_PluginSys.RemovePluginsListener(this);
|
||||||
m_pConfigLock->DestroyThis();
|
|
||||||
m_pThinkLock->DestroyThis();
|
|
||||||
m_pQueueLock->DestroyThis();
|
|
||||||
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
|
g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
|
||||||
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
|
g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
|
||||||
|
ClearConfigs();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int DBManager::GetInterfaceVersion()
|
unsigned int DBManager::GetInterfaceVersion()
|
||||||
@@ -133,13 +135,20 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
|||||||
|
|
||||||
void DBManager::ReadSMC_ParseStart()
|
void DBManager::ReadSMC_ParseStart()
|
||||||
{
|
{
|
||||||
m_confs.clear();
|
ClearConfigs();
|
||||||
m_ParseLevel = 0;
|
m_ParseLevel = 0;
|
||||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||||
m_StrTab.Reset();
|
|
||||||
m_DefDriver.clear();
|
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;
|
ConfDbInfo s_CurInfo;
|
||||||
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
@@ -159,7 +168,7 @@ SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *nam
|
|||||||
}
|
}
|
||||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||||
s_CurInfo = ConfDbInfo();
|
s_CurInfo = ConfDbInfo();
|
||||||
s_CurInfo.name = m_StrTab.AddString(name);
|
s_CurInfo.name = name;
|
||||||
m_ParseState = DBPARSE_LEVEL_DATABASE;
|
m_ParseState = DBPARSE_LEVEL_DATABASE;
|
||||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||||
m_ParseLevel++;
|
m_ParseLevel++;
|
||||||
@@ -186,16 +195,16 @@ SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
|||||||
{
|
{
|
||||||
if (strcmp(value, "default") != 0)
|
if (strcmp(value, "default") != 0)
|
||||||
{
|
{
|
||||||
s_CurInfo.driver = m_StrTab.AddString(value);
|
s_CurInfo.driver = value;
|
||||||
}
|
}
|
||||||
} else if (strcmp(key, "database") == 0) {
|
} else if (strcmp(key, "database") == 0) {
|
||||||
s_CurInfo.database = m_StrTab.AddString(value);
|
s_CurInfo.database = value;
|
||||||
} else if (strcmp(key, "host") == 0) {
|
} else if (strcmp(key, "host") == 0) {
|
||||||
s_CurInfo.host = m_StrTab.AddString(value);
|
s_CurInfo.host = value;
|
||||||
} else if (strcmp(key, "user") == 0) {
|
} else if (strcmp(key, "user") == 0) {
|
||||||
s_CurInfo.user = m_StrTab.AddString(value);
|
s_CurInfo.user = value;
|
||||||
} else if (strcmp(key, "pass") == 0) {
|
} else if (strcmp(key, "pass") == 0) {
|
||||||
s_CurInfo.pass = m_StrTab.AddString(value);
|
s_CurInfo.pass = value;
|
||||||
} else if (strcmp(key, "timeout") == 0) {
|
} else if (strcmp(key, "timeout") == 0) {
|
||||||
s_CurInfo.info.maxTimeout = atoi(value);
|
s_CurInfo.info.maxTimeout = atoi(value);
|
||||||
} else if (strcmp(key, "port") == 0) {
|
} else if (strcmp(key, "port") == 0) {
|
||||||
@@ -206,13 +215,6 @@ SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key,
|
|||||||
return SMCResult_Continue;
|
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)
|
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (m_ParseLevel)
|
if (m_ParseLevel)
|
||||||
@@ -223,17 +225,26 @@ SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
|
|
||||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||||
{
|
{
|
||||||
/* Set all of the info members to either a blank string
|
ConfDbInfo *cdb = new ConfDbInfo();
|
||||||
* or the string pointer from the string table.
|
|
||||||
*/
|
cdb->name = s_CurInfo.name;
|
||||||
ASSIGN_VAR(driver);
|
cdb->driver = s_CurInfo.driver;
|
||||||
ASSIGN_VAR(database);
|
cdb->host = s_CurInfo.host;
|
||||||
ASSIGN_VAR(host);
|
cdb->user = s_CurInfo.user;
|
||||||
ASSIGN_VAR(user);
|
cdb->pass = s_CurInfo.pass;
|
||||||
ASSIGN_VAR(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.. */
|
/* Save it.. */
|
||||||
m_confs.push_back(s_CurInfo);
|
m_confs.push_back(cdb);
|
||||||
|
|
||||||
/* Go up one level */
|
/* Go up one level */
|
||||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||||
@@ -244,7 +255,6 @@ SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
|
|
||||||
return SMCResult_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
#undef ASSIGN_VAR
|
|
||||||
|
|
||||||
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
|
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||||
{
|
{
|
||||||
@@ -261,7 +271,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
|||||||
*pdr = NULL;
|
*pdr = NULL;
|
||||||
}
|
}
|
||||||
*pdb = NULL;
|
*pdb = NULL;
|
||||||
UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
|
g_pSM->Format(error, maxlength, "Configuration \"%s\" not found", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +308,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
|||||||
}
|
}
|
||||||
*pdb = NULL;
|
*pdb = NULL;
|
||||||
|
|
||||||
UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
|
g_pSM->Format(error, maxlength, "Driver \"%s\" not found", dname);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -333,16 +343,22 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure NOTHING references this! */
|
/* Make sure NOTHING references this! */
|
||||||
List<ConfDbInfo>::iterator iter;
|
List<ConfDbInfo *>::iterator iter;
|
||||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||||
{
|
{
|
||||||
ConfDbInfo &db = (*iter);
|
ConfDbInfo &db = *(*iter);
|
||||||
if (db.realDriver == pDriver)
|
if (db.realDriver == pDriver)
|
||||||
{
|
{
|
||||||
db.realDriver = NULL;
|
db.realDriver = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Someone unloaded the default driver? Silly.. */
|
||||||
|
if (pDriver == m_pDefault)
|
||||||
|
{
|
||||||
|
m_pDefault = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now that the driver is gone, we have to test the think queue.
|
/* Now that the driver is gone, we have to test the think queue.
|
||||||
* Whatever happens therein is up to the db op!
|
* Whatever happens therein is up to the db op!
|
||||||
*/
|
*/
|
||||||
@@ -448,12 +464,12 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
|||||||
|
|
||||||
ConfDbInfo *DBManager::GetDatabaseConf(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++)
|
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||||
{
|
{
|
||||||
ConfDbInfo &conf = (*iter);
|
ConfDbInfo &conf = *(*iter);
|
||||||
if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
|
if (conf.name == name)
|
||||||
{
|
{
|
||||||
return &conf;
|
return &conf;
|
||||||
}
|
}
|
||||||
@@ -474,7 +490,7 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char filename[PLATFORM_MAX_PATH];
|
char filename[PLATFORM_MAX_PATH];
|
||||||
UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
|
g_pSM->Format(filename, sizeof(filename), "dbi.%s.ext", name);
|
||||||
|
|
||||||
IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
|
IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
|
||||||
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
|
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
|
||||||
@@ -495,12 +511,17 @@ IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
|||||||
|
|
||||||
void DBManager::KillWorkerThread()
|
void DBManager::KillWorkerThread()
|
||||||
{
|
{
|
||||||
if (m_pWorker)
|
if (m_Worker)
|
||||||
{
|
{
|
||||||
m_pWorker->Stop(false);
|
{
|
||||||
g_pThreader->DestroyWorker(m_pWorker);
|
ke::AutoLock lock(&m_QueueEvent);
|
||||||
m_pWorker = NULL;
|
m_Terminate = true;
|
||||||
|
m_QueueEvent.Notify();
|
||||||
|
}
|
||||||
|
m_Worker->Join();
|
||||||
|
m_Worker = NULL;
|
||||||
s_OneTimeThreaderErrorMsg = false;
|
s_OneTimeThreaderErrorMsg = false;
|
||||||
|
m_Terminate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,99 +534,106 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_pWorker)
|
if (!m_Worker)
|
||||||
{
|
{
|
||||||
m_pWorker = g_pThreader->MakeWorker(this, true);
|
m_Worker = new ke::Thread(this, "SM SQL Worker");
|
||||||
if (!m_pWorker)
|
if (!m_Worker->Succeeded())
|
||||||
{
|
{
|
||||||
if (!s_OneTimeThreaderErrorMsg)
|
if (!s_OneTimeThreaderErrorMsg)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Unable to create db threader (error unknown)");
|
smcore.LogError("[SM] Unable to create db threader (error unknown)");
|
||||||
s_OneTimeThreaderErrorMsg = true;
|
s_OneTimeThreaderErrorMsg = true;
|
||||||
}
|
}
|
||||||
return false;
|
m_Worker = NULL;
|
||||||
}
|
|
||||||
if (!m_pWorker->Start())
|
|
||||||
{
|
|
||||||
if (!s_OneTimeThreaderErrorMsg)
|
|
||||||
{
|
|
||||||
g_Logger.LogError("[SM] Unable to start db threader (error unknown)");
|
|
||||||
s_OneTimeThreaderErrorMsg = true;
|
|
||||||
}
|
|
||||||
g_pThreader->DestroyWorker(m_pWorker);
|
|
||||||
m_pWorker = NULL;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add to the queue */
|
/* Add to the queue */
|
||||||
{
|
{
|
||||||
m_pQueueLock->Lock();
|
ke::AutoLock lock(&m_QueueEvent);
|
||||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
||||||
queue.push(op);
|
queue.push(op);
|
||||||
m_pQueueLock->Unlock();
|
m_QueueEvent.Notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the thread */
|
|
||||||
m_pWorker->MakeThread(this);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::OnWorkerStart(IThreadWorker *pWorker)
|
void DBManager::Run()
|
||||||
{
|
{
|
||||||
m_drSafety.clear();
|
// Initialize DB threadsafety.
|
||||||
for (size_t i=0; i<m_drivers.size(); i++)
|
for (size_t i=0; i < m_drivers.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_drivers[i]->IsThreadSafe())
|
if (m_drivers[i]->IsThreadSafe())
|
||||||
{
|
|
||||||
m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
|
m_drSafety.push_back(m_drivers[i]->InitializeThreadSafety());
|
||||||
} else {
|
else
|
||||||
m_drSafety.push_back(false);
|
m_drSafety.push_back(false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void DBManager::OnWorkerStop(IThreadWorker *pWorker)
|
// Run actual worker thread logic.
|
||||||
{
|
ThreadMain();
|
||||||
|
|
||||||
|
// Shutdown DB threadsafety.
|
||||||
for (size_t i=0; i<m_drivers.size(); i++)
|
for (size_t i=0; i<m_drivers.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_drSafety[i])
|
if (m_drSafety[i])
|
||||||
{
|
|
||||||
m_drivers[i]->ShutdownThreadSafety();
|
m_drivers[i]->ShutdownThreadSafety();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_drSafety.clear();
|
m_drSafety.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::RunThread(IThreadHandle *pThread)
|
void DBManager::ThreadMain()
|
||||||
{
|
{
|
||||||
IDBThreadOperation *op = NULL;
|
ke::AutoLock lock(&m_QueueEvent);
|
||||||
|
|
||||||
/* Get something from the queue */
|
while (true) {
|
||||||
{
|
// The lock has been acquired. Grab everything we can out of the
|
||||||
m_pQueueLock->Lock();
|
// queue. Since we want to flush the queue even if we're terminated,
|
||||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
|
// we process all operations we can before checking to terminate.
|
||||||
if (!queue.empty())
|
// There's no risk of starvation since the main thread blocks on us
|
||||||
|
// terminating.
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
op = queue.first();
|
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
|
||||||
|
if (queue.empty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
IDBThreadOperation *op = queue.first();
|
||||||
queue.pop();
|
queue.pop();
|
||||||
|
|
||||||
|
// Unlock the queue when we run the query, so the main thread can
|
||||||
|
// keep pumping events. We re-acquire the lock to check for more
|
||||||
|
// items. It's okay if we terminate while unlocked; the main
|
||||||
|
// thread would be blocked and we'd need to flush the queue
|
||||||
|
// anyway, so after we've depleted the queue here, we'll just
|
||||||
|
// reach the terminate at the top of the loop.
|
||||||
|
{
|
||||||
|
ke::AutoUnlock unlock(&m_QueueEvent);
|
||||||
|
op->RunThreadPart();
|
||||||
|
|
||||||
|
ke::AutoLock lock(&m_ThinkLock);
|
||||||
|
m_ThinkQueue.push(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!m_Terminate)
|
||||||
|
{
|
||||||
|
ke::AutoUnlock unlock(&m_QueueEvent);
|
||||||
|
#ifdef _WIN32
|
||||||
|
Sleep(20);
|
||||||
|
#else
|
||||||
|
usleep(20000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_pQueueLock->Unlock();
|
|
||||||
|
if (m_Terminate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Release the lock and wait for a signal.
|
||||||
|
m_QueueEvent.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* whoa. hi. did we get something? we should have. */
|
|
||||||
if (!op)
|
|
||||||
{
|
|
||||||
/* wtf? */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
op->RunThreadPart();
|
|
||||||
|
|
||||||
m_pThinkLock->Lock();
|
|
||||||
m_ThinkQueue.push(op);
|
|
||||||
m_pThinkLock->Unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::RunFrame()
|
void DBManager::RunFrame()
|
||||||
@@ -617,19 +645,16 @@ void DBManager::RunFrame()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Dump one thing per-frame so the server stays sane. */
|
/* Dump one thing per-frame so the server stays sane. */
|
||||||
m_pThinkLock->Lock();
|
IDBThreadOperation *op;
|
||||||
IDBThreadOperation *op = m_ThinkQueue.first();
|
{
|
||||||
m_ThinkQueue.pop();
|
ke::AutoLock lock(&m_ThinkLock);
|
||||||
m_pThinkLock->Unlock();
|
op = m_ThinkQueue.first();
|
||||||
|
m_ThinkQueue.pop();
|
||||||
|
}
|
||||||
op->RunThinkPart();
|
op->RunThinkPart();
|
||||||
op->Destroy();
|
op->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::OnTerminate(IThreadHandle *pThread, bool cancel)
|
|
||||||
{
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
|
void DBManager::OnSourceModIdentityDropped(IdentityToken_t *pToken)
|
||||||
{
|
{
|
||||||
s_pAddBlock = pToken;
|
s_pAddBlock = pToken;
|
||||||
@@ -705,12 +730,12 @@ void DBManager::OnPluginUnloaded(IPlugin *plugin)
|
|||||||
|
|
||||||
void DBManager::LockConfig()
|
void DBManager::LockConfig()
|
||||||
{
|
{
|
||||||
m_pConfigLock->Lock();
|
m_ConfigLock.Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::UnlockConfig()
|
void DBManager::UnlockConfig()
|
||||||
{
|
{
|
||||||
m_pConfigLock->Unlock();
|
m_ConfigLock.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DBManager::GetDefaultDriverName()
|
const char *DBManager::GetDefaultDriverName()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -33,30 +33,29 @@
|
|||||||
#define _INCLUDE_DATABASE_MANAGER_H_
|
#define _INCLUDE_DATABASE_MANAGER_H_
|
||||||
|
|
||||||
#include <IDBDriver.h>
|
#include <IDBDriver.h>
|
||||||
#include "sm_globals.h"
|
#include "common_logic.h"
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <ITextParsers.h>
|
#include <ITextParsers.h>
|
||||||
#include "sm_memtable.h"
|
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
|
#include <IPluginSys.h>
|
||||||
|
#include <am-thread-utils.h>
|
||||||
#include "sm_simple_prioqueue.h"
|
#include "sm_simple_prioqueue.h"
|
||||||
#include "PluginSys.h"
|
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
struct ConfDbInfo
|
struct ConfDbInfo
|
||||||
{
|
{
|
||||||
ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
|
ConfDbInfo() : realDriver(NULL)
|
||||||
database(-1), realDriver(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
int name;
|
String name;
|
||||||
int driver;
|
String driver;
|
||||||
int host;
|
String host;
|
||||||
int user;
|
String user;
|
||||||
int pass;
|
String pass;
|
||||||
int database;
|
String database;
|
||||||
IDBDriver *realDriver;
|
IDBDriver *realDriver;
|
||||||
DatabaseInfo info;
|
DatabaseInfo info;
|
||||||
};
|
};
|
||||||
@@ -66,9 +65,8 @@ class DBManager :
|
|||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IHandleTypeDispatch,
|
public IHandleTypeDispatch,
|
||||||
public ITextListener_SMC,
|
public ITextListener_SMC,
|
||||||
public IThread,
|
public IPluginsListener,
|
||||||
public IThreadWorkerCallbacks,
|
public ke::IRunnable
|
||||||
public IPluginsListener
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DBManager();
|
DBManager();
|
||||||
@@ -99,12 +97,9 @@ public: //ITextListener_SMC
|
|||||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
void ReadSMC_ParseEnd(bool halted, bool failed);
|
void ReadSMC_ParseEnd(bool halted, bool failed);
|
||||||
public: //IThread
|
public: //ke::IRunnable
|
||||||
void RunThread(IThreadHandle *pThread);
|
void Run();
|
||||||
void OnTerminate(IThreadHandle *pThread, bool cancel);
|
void ThreadMain();
|
||||||
public: //IThreadWorkerCallbacks
|
|
||||||
void OnWorkerStart(IThreadWorker *pWorker);
|
|
||||||
void OnWorkerStop(IThreadWorker *pWorker);
|
|
||||||
public: //IPluginsListener
|
public: //IPluginsListener
|
||||||
void OnPluginUnloaded(IPlugin *plugin);
|
void OnPluginUnloaded(IPlugin *plugin);
|
||||||
public:
|
public:
|
||||||
@@ -121,6 +116,7 @@ public:
|
|||||||
return m_DatabaseType;
|
return m_DatabaseType;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
void ClearConfigs();
|
||||||
void KillWorkerThread();
|
void KillWorkerThread();
|
||||||
private:
|
private:
|
||||||
CVector<IDBDriver *> m_drivers;
|
CVector<IDBDriver *> m_drivers;
|
||||||
@@ -129,16 +125,16 @@ private:
|
|||||||
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
||||||
Queue<IDBThreadOperation *> m_ThinkQueue;
|
Queue<IDBThreadOperation *> m_ThinkQueue;
|
||||||
CVector<bool> m_drSafety; /* which drivers are safe? */
|
CVector<bool> m_drSafety; /* which drivers are safe? */
|
||||||
IThreadWorker *m_pWorker; /* Worker thread object */
|
ke::AutoPtr<ke::Thread> m_Worker;
|
||||||
IMutex *m_pConfigLock; /* Configuration lock */
|
ke::ConditionVariable m_QueueEvent;
|
||||||
IMutex *m_pQueueLock; /* Queue safety lock */
|
ke::Mutex m_ConfigLock;
|
||||||
IMutex *m_pThinkLock; /* Think-queue lock */
|
ke::Mutex m_ThinkLock;
|
||||||
|
bool m_Terminate;
|
||||||
|
|
||||||
List<ConfDbInfo> m_confs;
|
List<ConfDbInfo *> m_confs;
|
||||||
HandleType_t m_DriverType;
|
HandleType_t m_DriverType;
|
||||||
HandleType_t m_DatabaseType;
|
HandleType_t m_DatabaseType;
|
||||||
String m_DefDriver;
|
String m_DefDriver;
|
||||||
BaseStringTable m_StrTab;
|
|
||||||
char m_Filename[PLATFORM_MAX_PATH];
|
char m_Filename[PLATFORM_MAX_PATH];
|
||||||
unsigned int m_ParseLevel;
|
unsigned int m_ParseLevel;
|
||||||
unsigned int m_ParseState;
|
unsigned int m_ParseState;
|
||||||
@@ -29,10 +29,9 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <IPluginSys.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "DebugReporter.h"
|
#include "DebugReporter.h"
|
||||||
#include "Logger.h"
|
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "sm_stringutil.h"
|
|
||||||
|
|
||||||
DebugReport g_DbgReporter;
|
DebugReport g_DbgReporter;
|
||||||
|
|
||||||
@@ -47,32 +46,37 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
|
|||||||
char buffer[512];
|
char buffer[512];
|
||||||
|
|
||||||
va_start(ap, msg);
|
va_start(ap, msg);
|
||||||
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
|
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
g_Logger.LogMessage("[SM] %s", buffer);
|
smcore.Log("[SM] %s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char buffer[512];
|
|
||||||
|
|
||||||
va_start(ap, message);
|
va_start(ap, message);
|
||||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
|
GenerateErrorVA(ctx, func_idx, err, message, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
|
void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap)
|
||||||
|
{
|
||||||
|
char buffer[512];
|
||||||
|
smcore.FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||||
|
|
||||||
|
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
smcore.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||||
} else {
|
} else {
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
smcore.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] %s", buffer);
|
smcore.LogError("[SM] %s", buffer);
|
||||||
|
|
||||||
if (func_idx != -1)
|
if (func_idx != -1)
|
||||||
{
|
{
|
||||||
@@ -82,7 +86,7 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c
|
|||||||
sp_public_t *function;
|
sp_public_t *function;
|
||||||
if (ctx->GetRuntime()->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);
|
smcore.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,26 +98,26 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
|||||||
char buffer[512];
|
char buffer[512];
|
||||||
|
|
||||||
va_start(ap, message);
|
va_start(ap, message);
|
||||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
|
smcore.FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
|
const char *plname = pluginsys->FindPluginByContext(pContext->GetContext())->GetFilename();
|
||||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
smcore.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||||
} else {
|
} else {
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
smcore.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] %s", buffer);
|
smcore.LogError("[SM] %s", buffer);
|
||||||
|
|
||||||
IPluginDebugInfo *pDebug;
|
IPluginDebugInfo *pDebug;
|
||||||
if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL)
|
if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
smcore.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
||||||
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
smcore.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
||||||
_GetPluginIndex(pContext));
|
_GetPluginIndex(pContext));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,21 +125,21 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
|
|||||||
const char *name;
|
const char *name;
|
||||||
if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE)
|
if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
|
smcore.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
|
||||||
} else {
|
} else {
|
||||||
g_Logger.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
|
smcore.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
||||||
{
|
{
|
||||||
const char *lastname;
|
const char *lastname;
|
||||||
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
|
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||||
int n_err = error->GetErrorCode();
|
int n_err = error->GetErrorCode();
|
||||||
|
|
||||||
if (n_err != SP_ERROR_NATIVE)
|
if (n_err != SP_ERROR_NATIVE)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Plugin encountered error %d: %s",
|
smcore.LogError("[SM] Plugin encountered error %d: %s",
|
||||||
n_err,
|
n_err,
|
||||||
error->GetErrorString());
|
error->GetErrorString());
|
||||||
}
|
}
|
||||||
@@ -145,26 +149,26 @@ void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *erro
|
|||||||
const char *custerr;
|
const char *custerr;
|
||||||
if ((custerr=error->GetCustomErrorString()) != NULL)
|
if ((custerr=error->GetCustomErrorString()) != NULL)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
|
smcore.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
|
||||||
} else {
|
} else {
|
||||||
g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
|
smcore.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error->DebugInfoAvailable())
|
if (!error->DebugInfoAvailable())
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
smcore.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
|
||||||
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
smcore.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
|
||||||
_GetPluginIndex(ctx));
|
_GetPluginIndex(ctx));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallStackInfo stk_info;
|
CallStackInfo stk_info;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
g_Logger.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
|
smcore.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
|
||||||
while (error->GetTraceInfo(&stk_info))
|
while (error->GetTraceInfo(&stk_info))
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] [%d] Line %d, %s::%s()",
|
smcore.LogError("[SM] [%d] Line %d, %s::%s()",
|
||||||
i++,
|
i++,
|
||||||
stk_info.line,
|
stk_info.line,
|
||||||
stk_info.filename,
|
stk_info.filename,
|
||||||
@@ -175,7 +179,7 @@ void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *erro
|
|||||||
int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
||||||
{
|
{
|
||||||
int id = 1;
|
int id = 1;
|
||||||
IPluginIterator *iter = g_PluginSys.GetPluginIterator();
|
IPluginIterator *iter = pluginsys->GetPluginIterator();
|
||||||
|
|
||||||
for (; iter->MorePlugins(); iter->NextPlugin(), id++)
|
for (; iter->MorePlugins(); iter->NextPlugin(), id++)
|
||||||
{
|
{
|
||||||
@@ -191,6 +195,6 @@ int DebugReport::_GetPluginIndex(IPluginContext *ctx)
|
|||||||
|
|
||||||
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
|
/* If we don't know which plugin this is, it's one being loaded. Fake its index for now. */
|
||||||
|
|
||||||
return g_PluginSys.GetPluginCount() + 1;
|
return pluginsys->GetPluginCount() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_
|
#define _INCLUDE_SOURCEMOD_CDBGREPORTER_H_
|
||||||
|
|
||||||
#include "sp_vm_api.h"
|
#include "sp_vm_api.h"
|
||||||
#include "sm_globals.h"
|
#include "common_logic.h"
|
||||||
|
|
||||||
class DebugReport :
|
class DebugReport :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
@@ -46,6 +46,7 @@ public: // IDebugListener
|
|||||||
void OnDebugSpew(const char *msg, ...);
|
void OnDebugSpew(const char *msg, ...);
|
||||||
public:
|
public:
|
||||||
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
||||||
|
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
|
||||||
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
||||||
private:
|
private:
|
||||||
int _GetPluginIndex(IPluginContext *ctx);
|
int _GetPluginIndex(IPluginContext *ctx);
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -31,12 +31,11 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include "LibrarySys.h"
|
#include <ILibrarySys.h>
|
||||||
#include "ShareSys.h"
|
#include <ISourceMod.h>
|
||||||
#include "Logger.h"
|
#include "common_logic.h"
|
||||||
#include "sourcemm_api.h"
|
#include "PluginSys.h"
|
||||||
#include "sm_srvcmds.h"
|
#include <am-utility.h>
|
||||||
#include "sm_stringutil.h"
|
|
||||||
|
|
||||||
CExtensionManager g_Extensions;
|
CExtensionManager g_Extensions;
|
||||||
IdentityType_t g_ExtType;
|
IdentityType_t g_ExtType;
|
||||||
@@ -49,6 +48,9 @@ void CExtension::Initialize(const char *filename, const char *path)
|
|||||||
m_bFullyLoaded = false;
|
m_bFullyLoaded = false;
|
||||||
m_File.assign(filename);
|
m_File.assign(filename);
|
||||||
m_Path.assign(path);
|
m_Path.assign(path);
|
||||||
|
char real_name[PLATFORM_MAX_PATH];
|
||||||
|
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)
|
CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
|
||||||
@@ -64,31 +66,76 @@ CLocalExtension::CLocalExtension(const char *filename)
|
|||||||
|
|
||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
/* First see if there is an engine specific build! */
|
/* Special case for new bintools binary */
|
||||||
g_SourceMod.BuildPath(Path_SM,
|
if (strcmp(filename, "bintools.ext") == 0)
|
||||||
path,
|
|
||||||
PLATFORM_MAX_PATH,
|
|
||||||
#if defined METAMOD_PLAPI_VERSION
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
"extensions/auto.2.l4d/%s",
|
|
||||||
#elif SOURCE_ENGINE == SE_ORANGEBOX
|
|
||||||
"extensions/auto.2.ep2/%s",
|
|
||||||
#elif SOURCE_ENGINE == SE_DARKMESSIAH
|
|
||||||
"extensions/auto.2.darkm/%s",
|
|
||||||
#else
|
|
||||||
"extensions/auto.2.ep1/%s",
|
|
||||||
#endif //SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
#else //METAMOD_PLAPI_VERSION
|
|
||||||
"extensions/auto.1.ep1/%s",
|
|
||||||
#endif //METAMOD_PLAPI_VERSION
|
|
||||||
filename);
|
|
||||||
|
|
||||||
/* Try the "normal" version */
|
|
||||||
if (!g_LibSys.IsPathFile(path))
|
|
||||||
{
|
{
|
||||||
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
|
goto normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Zeroth, see if there is an engine specific build in the new place. */
|
||||||
|
g_pSM->BuildPath(Path_SM,
|
||||||
|
path,
|
||||||
|
PLATFORM_MAX_PATH,
|
||||||
|
"extensions/%s.%s." PLATFORM_LIB_EXT,
|
||||||
|
filename,
|
||||||
|
smcore.gamesuffix);
|
||||||
|
|
||||||
|
if (libsys->IsPathFile(path))
|
||||||
|
{
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* COMPAT HACK: One-halfth, if ep2v, see if there is an engine specific build in the new place with old naming */
|
||||||
|
if (strcmp(smcore.gamesuffix, "2.tf2") == 0
|
||||||
|
|| strcmp(smcore.gamesuffix, "2.dods") == 0
|
||||||
|
|| strcmp(smcore.gamesuffix, "2.hl2dm") == 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_pSM->BuildPath(Path_SM,
|
||||||
|
path,
|
||||||
|
PLATFORM_MAX_PATH,
|
||||||
|
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
|
||||||
|
filename);
|
||||||
|
|
||||||
|
if (libsys->IsPathFile(path))
|
||||||
|
{
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(smcore.gamesuffix, "2.nd") == 0)
|
||||||
|
{
|
||||||
|
g_pSM->BuildPath(Path_SM,
|
||||||
|
path,
|
||||||
|
PLATFORM_MAX_PATH,
|
||||||
|
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
|
||||||
|
filename);
|
||||||
|
|
||||||
|
if (libsys->IsPathFile(path))
|
||||||
|
{
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First see if there is an engine specific build! */
|
||||||
|
g_pSM->BuildPath(Path_SM,
|
||||||
|
path,
|
||||||
|
PLATFORM_MAX_PATH,
|
||||||
|
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
|
||||||
|
filename,
|
||||||
|
smcore.gamesuffix);
|
||||||
|
|
||||||
|
/* Try the "normal" version */
|
||||||
|
if (!libsys->IsPathFile(path))
|
||||||
|
{
|
||||||
|
normal:
|
||||||
|
g_pSM->BuildPath(Path_SM,
|
||||||
|
path,
|
||||||
|
PLATFORM_MAX_PATH,
|
||||||
|
"extensions/%s." PLATFORM_LIB_EXT,
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
Initialize(filename, path);
|
Initialize(filename, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +158,7 @@ bool CRemoteExtension::Load(char *error, size_t maxlength)
|
|||||||
|
|
||||||
bool CLocalExtension::Load(char *error, size_t maxlength)
|
bool CLocalExtension::Load(char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
|
m_pLib = libsys->OpenLibrary(m_Path.c_str(), error, maxlength);
|
||||||
|
|
||||||
if (m_pLib == NULL)
|
if (m_pLib == NULL)
|
||||||
{
|
{
|
||||||
@@ -143,8 +190,16 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
|
|||||||
/* Load as MM:S */
|
/* Load as MM:S */
|
||||||
if (m_pAPI->IsMetamodExtension())
|
if (m_pAPI->IsMetamodExtension())
|
||||||
{
|
{
|
||||||
bool already;
|
bool ok;
|
||||||
m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
|
m_PlId = smcore.LoadMMSPlugin(m_Path.c_str(), &ok, error, maxlength);
|
||||||
|
|
||||||
|
if (!m_PlId || !ok)
|
||||||
|
{
|
||||||
|
m_pLib->CloseLibrary();
|
||||||
|
m_pLib = NULL;
|
||||||
|
m_pAPI = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CExtension::Load(error, maxlength))
|
if (!CExtension::Load(error, maxlength))
|
||||||
@@ -153,8 +208,7 @@ bool CLocalExtension::Load(char *error, size_t maxlength)
|
|||||||
{
|
{
|
||||||
if (m_PlId)
|
if (m_PlId)
|
||||||
{
|
{
|
||||||
char dummy[255];
|
smcore.UnloadMMSPlugin(m_PlId);
|
||||||
g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
|
|
||||||
m_PlId = 0;
|
m_PlId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,8 +229,7 @@ void CLocalExtension::Unload()
|
|||||||
{
|
{
|
||||||
if (m_pAPI != NULL && m_PlId)
|
if (m_pAPI != NULL && m_PlId)
|
||||||
{
|
{
|
||||||
char temp_buffer[255];
|
smcore.UnloadMMSPlugin(m_PlId);
|
||||||
g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
|
|
||||||
m_PlId = 0;
|
m_PlId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +240,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()
|
bool CRemoteExtension::IsExternal()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -222,7 +292,7 @@ bool CExtension::PerformAPICheck(char *error, size_t maxlength)
|
|||||||
bool CExtension::Load(char *error, size_t maxlength)
|
bool CExtension::Load(char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
CreateIdentity();
|
CreateIdentity();
|
||||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
|
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !smcore.IsMapLoading()))
|
||||||
{
|
{
|
||||||
DestroyIdentity();
|
DestroyIdentity();
|
||||||
return false;
|
return false;
|
||||||
@@ -230,7 +300,7 @@ bool CExtension::Load(char *error, size_t maxlength)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Check if we're past load time */
|
/* Check if we're past load time */
|
||||||
if (!g_SourceMod.IsMapLoading())
|
if (!smcore.IsMapLoading())
|
||||||
{
|
{
|
||||||
m_pAPI->OnExtensionsAllLoaded();
|
m_pAPI->OnExtensionsAllLoaded();
|
||||||
}
|
}
|
||||||
@@ -273,7 +343,7 @@ void CExtension::MarkAllLoaded()
|
|||||||
void CExtension::AddPlugin(CPlugin *pPlugin)
|
void CExtension::AddPlugin(CPlugin *pPlugin)
|
||||||
{
|
{
|
||||||
/* Unfortunately we have to do this :( */
|
/* Unfortunately we have to do this :( */
|
||||||
if (m_Dependents.find(pPlugin) != m_Dependents.end())
|
if (m_Dependents.find(pPlugin) == m_Dependents.end())
|
||||||
{
|
{
|
||||||
m_Dependents.push_back(pPlugin);
|
m_Dependents.push_back(pPlugin);
|
||||||
}
|
}
|
||||||
@@ -291,7 +361,12 @@ IExtensionInterface *CExtension::GetAPI()
|
|||||||
|
|
||||||
const char *CExtension::GetFilename()
|
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()
|
IdentityToken_t *CExtension::GetIdentity()
|
||||||
@@ -435,14 +510,15 @@ void CExtension::AddLibrary(const char *library)
|
|||||||
void CExtensionManager::OnSourceModAllInitialized()
|
void CExtensionManager::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
|
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
|
||||||
g_PluginSys.AddPluginsListener(this);
|
pluginsys->AddPluginsListener(this);
|
||||||
g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
|
rootmenu->AddRootConsoleCommand("exts", "Manage extensions", this);
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
g_ShareSys.AddInterface(NULL, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CExtensionManager::OnSourceModShutdown()
|
void CExtensionManager::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
g_RootMenu.RemoveRootConsoleCommand("exts", this);
|
rootmenu->RemoveRootConsoleCommand("exts", this);
|
||||||
|
pluginsys->RemovePluginsListener(this);
|
||||||
g_ShareSys.DestroyIdentType(g_ExtType);
|
g_ShareSys.DestroyIdentType(g_ExtType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,13 +536,11 @@ void CExtensionManager::TryAutoload()
|
|||||||
{
|
{
|
||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
|
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
|
||||||
|
|
||||||
IDirectory *pDir = g_LibSys.OpenDirectory(path);
|
ke::AutoPtr<IDirectory> pDir(libsys->OpenDirectory(path));
|
||||||
if (!pDir)
|
if (!pDir)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const char *lfile;
|
const char *lfile;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -493,8 +567,8 @@ void CExtensionManager::TryAutoload()
|
|||||||
}
|
}
|
||||||
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
char file[PLATFORM_MAX_PATH];
|
||||||
len = UTIL_Format(file, sizeof(file), "%s", lfile);
|
len = smcore.Format(file, sizeof(file), "%s", lfile);
|
||||||
strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
|
strcpy(&file[len - 9], ".ext");
|
||||||
|
|
||||||
LoadAutoExtension(file);
|
LoadAutoExtension(file);
|
||||||
|
|
||||||
@@ -502,13 +576,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 = libsys->GetFileExtension(path);
|
||||||
|
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||||
{
|
{
|
||||||
char newpath[PLATFORM_MAX_PATH];
|
char path2[PLATFORM_MAX_PATH];
|
||||||
g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
|
smcore.Format(path2, sizeof(path2), "%s", path);
|
||||||
return LoadAutoExtension(newpath);
|
path2[strlen(path) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
|
||||||
|
return LoadAutoExtension(path2, bErrorOnMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
IExtension *pAlready;
|
IExtension *pAlready;
|
||||||
@@ -527,7 +604,11 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
|||||||
|
|
||||||
if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
|
if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
|
if (bErrorOnMissing || libsys->IsPathFile(p->GetPath()))
|
||||||
|
{
|
||||||
|
smcore.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
|
||||||
|
}
|
||||||
|
|
||||||
p->SetError(error);
|
p->SetError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,29 +622,17 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
|
|||||||
|
|
||||||
/* Chomp off the path */
|
/* Chomp off the path */
|
||||||
char lookup[PLATFORM_MAX_PATH];
|
char lookup[PLATFORM_MAX_PATH];
|
||||||
g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
|
libsys->GetFileFromPath(lookup, sizeof(lookup), file);
|
||||||
|
|
||||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
||||||
{
|
{
|
||||||
pExt = (*iter);
|
pExt = (*iter);
|
||||||
char short_file[PLATFORM_MAX_PATH];
|
if (pExt->IsSameFile(lookup))
|
||||||
g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
|
|
||||||
if (strcmp(lookup, short_file) == 0)
|
|
||||||
{
|
{
|
||||||
return pExt;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,6 +670,16 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
|||||||
|
|
||||||
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
|
/* Remove platform extension if it's there. Compat hack. */
|
||||||
|
const char *ext = libsys->GetFileExtension(file);
|
||||||
|
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||||
|
{
|
||||||
|
char path2[PLATFORM_MAX_PATH];
|
||||||
|
smcore.Format(path2, sizeof(path2), "%s", file);
|
||||||
|
path2[strlen(file) - strlen(PLATFORM_LIB_EXT) - 1] = '\0';
|
||||||
|
return LoadExtension(path2, error, maxlength);
|
||||||
|
}
|
||||||
|
|
||||||
IExtension *pAlready;
|
IExtension *pAlready;
|
||||||
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -658,11 +737,11 @@ void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface
|
|||||||
pExt->AddInterface(pInterface);
|
pExt->AddInterface(pInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
|
void CExtensionManager::BindChildPlugin(IExtension *pParent, SMPlugin *pPlugin)
|
||||||
{
|
{
|
||||||
CExtension *pExt = (CExtension *)pParent;
|
CExtension *pExt = (CExtension *)pParent;
|
||||||
|
|
||||||
pExt->AddPlugin(pPlugin);
|
pExt->AddPlugin(static_cast<CPlugin *>(pPlugin));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
|
void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
|
||||||
@@ -671,7 +750,7 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
|
|||||||
|
|
||||||
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
|
||||||
{
|
{
|
||||||
(*iter)->DropRefsTo((CPlugin *)plugin);
|
(*iter)->DropRefsTo(static_cast<CPlugin *>(plugin));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,18 +778,21 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num)
|
|||||||
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||||
{
|
{
|
||||||
if (!_pExt)
|
if (!_pExt)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
CExtension *pExt = (CExtension *)_pExt;
|
CExtension *pExt = (CExtension *)_pExt;
|
||||||
|
|
||||||
if (m_Libs.find(pExt) == m_Libs.end())
|
if (m_Libs.find(pExt) == m_Libs.end())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
/* First remove us from internal lists */
|
/* Tell it to unload */
|
||||||
|
if (pExt->IsLoaded())
|
||||||
|
pExt->GetAPI()->OnExtensionUnload();
|
||||||
|
|
||||||
|
// Remove us from internal lists. Note that because we do this, it's
|
||||||
|
// possible that our extension could be added back if another plugin
|
||||||
|
// tries to load during this process. If we ever find this to happen,
|
||||||
|
// we can just block plugin loading.
|
||||||
g_ShareSys.RemoveInterfaces(_pExt);
|
g_ShareSys.RemoveInterfaces(_pExt);
|
||||||
m_Libs.remove(pExt);
|
m_Libs.remove(pExt);
|
||||||
|
|
||||||
@@ -724,7 +806,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
while (p_iter != pExt->m_Dependents.end())
|
while (p_iter != pExt->m_Dependents.end())
|
||||||
{
|
{
|
||||||
/* We have to manually unlink ourselves here, since we're no longer being managed */
|
/* We have to manually unlink ourselves here, since we're no longer being managed */
|
||||||
g_PluginSys.UnloadPlugin((*p_iter));
|
scripts->UnloadPlugin((*p_iter));
|
||||||
p_iter = pExt->m_Dependents.erase(p_iter);
|
p_iter = pExt->m_Dependents.erase(p_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,7 +815,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
s_iter != pExt->m_Libraries.end();
|
s_iter != pExt->m_Libraries.end();
|
||||||
s_iter++)
|
s_iter++)
|
||||||
{
|
{
|
||||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
scripts->OnLibraryAction((*s_iter).c_str(), LibraryAction_Removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify and/or unload all dependencies */
|
/* Notify and/or unload all dependencies */
|
||||||
@@ -744,13 +826,9 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
{
|
{
|
||||||
pDep = (*c_iter);
|
pDep = (*c_iter);
|
||||||
if ((pAPI=pDep->GetAPI()) == NULL)
|
if ((pAPI=pDep->GetAPI()) == NULL)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (pDep == pExt)
|
if (pDep == pExt)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
/* Now, get its dependency list */
|
/* Now, get its dependency list */
|
||||||
bool dropped = false;
|
bool dropped = false;
|
||||||
List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
|
List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
|
||||||
@@ -779,13 +857,9 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
while (i_iter != pDep->m_ChildDeps.end())
|
while (i_iter != pDep->m_ChildDeps.end())
|
||||||
{
|
{
|
||||||
if ((*i_iter).owner == pExt)
|
if ((*i_iter).owner == pExt)
|
||||||
{
|
|
||||||
i_iter = pDep->m_ChildDeps.erase(i_iter);
|
i_iter = pDep->m_ChildDeps.erase(i_iter);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
i_iter++;
|
i_iter++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,12 +878,10 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell it to unload */
|
// Everything has been informed that we're unloading, so give the
|
||||||
if (pExt->IsLoaded())
|
// extension one last notification.
|
||||||
{
|
if (pExt->IsLoaded() && pExt->GetAPI()->GetExtensionVersion() >= 7)
|
||||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
pExt->GetAPI()->OnDependenciesDropped();
|
||||||
pAPI->OnExtensionUnload();
|
|
||||||
}
|
|
||||||
|
|
||||||
pExt->Unload();
|
pExt->Unload();
|
||||||
delete pExt;
|
delete pExt;
|
||||||
@@ -858,10 +930,10 @@ void CExtensionManager::AddDependency(IExtension *pSource, const char *file, boo
|
|||||||
|
|
||||||
void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||||
{
|
{
|
||||||
int argcount = command.ArgC();
|
int argcount = smcore.Argc(command);
|
||||||
if (argcount >= 3)
|
if (argcount >= 3)
|
||||||
{
|
{
|
||||||
const char *cmd = command.Arg(2);
|
const char *cmd = smcore.Arg(command, 2);
|
||||||
if (strcmp(cmd, "list") == 0)
|
if (strcmp(cmd, "list") == 0)
|
||||||
{
|
{
|
||||||
List<CExtension *>::iterator iter;
|
List<CExtension *>::iterator iter;
|
||||||
@@ -871,17 +943,17 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
|
rootmenu->ConsolePrint("[SM] Displaying 1 extension:");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
|
rootmenu->ConsolePrint("[SM] No extensions are loaded.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
|
rootmenu->ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -893,7 +965,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
char error[255];
|
char error[255];
|
||||||
if (!pExt->IsRunning(error, sizeof(error)))
|
if (!pExt->IsRunning(error, sizeof(error)))
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
|
rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -901,39 +973,70 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
const char *name = pAPI->GetExtensionName();
|
const char *name = pAPI->GetExtensionName();
|
||||||
const char *version = pAPI->GetExtensionVerString();
|
const char *version = pAPI->GetExtensionVerString();
|
||||||
const char *descr = pAPI->GetExtensionDescription();
|
const char *descr = pAPI->GetExtensionDescription();
|
||||||
g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
|
rootmenu->ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
|
rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(cmd, "load") == 0)
|
||||||
|
{
|
||||||
|
if (argcount < 4)
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Usage: sm exts load <file>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *filename = smcore.Arg(command, 3);
|
||||||
|
char path[PLATFORM_MAX_PATH];
|
||||||
|
char error[256];
|
||||||
|
|
||||||
|
smcore.Format(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "",
|
||||||
|
!strstr(filename, "." PLATFORM_LIB_EXT) ? "." PLATFORM_LIB_EXT : "");
|
||||||
|
|
||||||
|
if (FindExtensionByFile(path) != NULL)
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Extension %s is already loaded.", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoadExtension(path, error, sizeof(error)))
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Loaded extension %s successfully.", path);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Extension %s failed to load: %s", path, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if (strcmp(cmd, "info") == 0)
|
else if (strcmp(cmd, "info") == 0)
|
||||||
{
|
{
|
||||||
if (argcount < 4)
|
if (argcount < 4)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
|
rootmenu->ConsolePrint("[SM] Usage: sm exts info <#>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *sId = command.Arg(3);
|
const char *sId = smcore.Arg(command, 3);
|
||||||
unsigned int id = atoi(sId);
|
unsigned int id = atoi(sId);
|
||||||
if (id <= 0)
|
if (id <= 0)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
|
rootmenu->ConsolePrint("[SM] Usage: sm exts info <#>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Libs.size() == 0)
|
if (m_Libs.size() == 0)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
|
rootmenu->ConsolePrint("[SM] No extensions are loaded.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id > m_Libs.size())
|
if (id > m_Libs.size())
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
|
rootmenu->ConsolePrint("[SM] No extension was found with id %d.", id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -951,44 +1054,44 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
/* This should never happen */
|
/* This should never happen */
|
||||||
if (!pExt)
|
if (!pExt)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
|
rootmenu->ConsolePrint("[SM] No extension was found with id %d.", id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pExt->IsLoaded())
|
if (!pExt->IsLoaded())
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
rootmenu->ConsolePrint(" File: %s", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
|
rootmenu->ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char error[255];
|
char error[255];
|
||||||
if (!pExt->IsRunning(error, sizeof(error)))
|
if (!pExt->IsRunning(error, sizeof(error)))
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
rootmenu->ConsolePrint(" File: %s", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint(" Loaded: Yes");
|
rootmenu->ConsolePrint(" Loaded: Yes");
|
||||||
g_RootMenu.ConsolePrint(" Running: No (%s)", error);
|
rootmenu->ConsolePrint(" Running: No (%s)", error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
rootmenu->ConsolePrint(" File: %s", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
|
rootmenu->ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
|
||||||
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
|
rootmenu->ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
|
||||||
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
|
rootmenu->ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
|
||||||
g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
|
rootmenu->ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
|
||||||
|
|
||||||
if (pExt->IsExternal())
|
if (pExt->IsExternal())
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
|
rootmenu->ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
|
||||||
}
|
}
|
||||||
else if (pAPI->IsMetamodExtension())
|
else if (pAPI->IsMetamodExtension())
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
|
rootmenu->ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
|
rootmenu->ConsolePrint(" Method: Loaded by SourceMod");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -998,33 +1101,33 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
{
|
{
|
||||||
if (argcount < 4)
|
if (argcount < 4)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
|
rootmenu->ConsolePrint("[SM] Usage: sm exts unload <#> [code]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *arg = command.Arg(3);
|
const char *arg = smcore.Arg(command, 3);
|
||||||
unsigned int num = atoi(arg);
|
unsigned int num = atoi(arg);
|
||||||
CExtension *pExt = FindByOrder(num);
|
CExtension *pExt = FindByOrder(num);
|
||||||
|
|
||||||
if (!pExt)
|
if (!pExt)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
|
rootmenu->ConsolePrint("[SM] Extension number %d was not found.", num);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argcount > 4 && pExt->unload_code)
|
if (argcount > 4 && pExt->unload_code)
|
||||||
{
|
{
|
||||||
const char *unload = command.Arg(4);
|
const char *unload = smcore.Arg(command, 4);
|
||||||
if (pExt->unload_code == (unsigned)atoi(unload))
|
if (pExt->unload_code == (unsigned)atoi(unload))
|
||||||
{
|
{
|
||||||
char filename[PLATFORM_MAX_PATH];
|
char filename[PLATFORM_MAX_PATH];
|
||||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||||
UnloadExtension(pExt);
|
UnloadExtension(pExt);
|
||||||
g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
|
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
|
rootmenu->ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1035,7 +1138,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
char filename[PLATFORM_MAX_PATH];
|
char filename[PLATFORM_MAX_PATH];
|
||||||
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
|
||||||
UnloadExtension(pExt);
|
UnloadExtension(pExt);
|
||||||
g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
|
rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1043,7 +1146,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
List<CPlugin *> plugins;
|
List<CPlugin *> plugins;
|
||||||
if (pExt->m_ChildDeps.size())
|
if (pExt->m_ChildDeps.size())
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
|
rootmenu->ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
|
||||||
List<CExtension *>::iterator iter;
|
List<CExtension *>::iterator iter;
|
||||||
CExtension *pOther;
|
CExtension *pOther;
|
||||||
/* Get list of all extensions */
|
/* Get list of all extensions */
|
||||||
@@ -1068,7 +1171,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
/* Will our dependent care? */
|
/* Will our dependent care? */
|
||||||
if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
|
if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
|
rootmenu->ConsolePrint(" -> %s", pExt->GetFilename());
|
||||||
/* Add to plugin unload list */
|
/* Add to plugin unload list */
|
||||||
List<CPlugin *>::iterator p_iter;
|
List<CPlugin *>::iterator p_iter;
|
||||||
for (p_iter=pOther->m_Dependents.begin();
|
for (p_iter=pOther->m_Dependents.begin();
|
||||||
@@ -1086,7 +1189,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
}
|
}
|
||||||
if (pExt->m_Dependents.size())
|
if (pExt->m_Dependents.size())
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
|
rootmenu->ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
|
||||||
List<CPlugin *>::iterator iter;
|
List<CPlugin *>::iterator iter;
|
||||||
CPlugin *pPlugin;
|
CPlugin *pPlugin;
|
||||||
for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
|
for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
|
||||||
@@ -1100,23 +1203,69 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
for (iter = plugins.begin(); iter != plugins.end(); iter++)
|
for (iter = plugins.begin(); iter != plugins.end(); iter++)
|
||||||
{
|
{
|
||||||
pPlugin = (*iter);
|
pPlugin = (*iter);
|
||||||
g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
|
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srand(static_cast<int>(time(NULL)));
|
srand(static_cast<int>(time(NULL)));
|
||||||
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
||||||
g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(cmd, "reload") == 0)
|
||||||
|
{
|
||||||
|
if (argcount < 4)
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Usage: sm exts reload <#>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *arg = smcore.Arg(command, 3);
|
||||||
|
unsigned int num = atoi(arg);
|
||||||
|
CExtension *pExt = FindByOrder(num);
|
||||||
|
|
||||||
|
if (!pExt)
|
||||||
|
{
|
||||||
|
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)))
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Extension %s is now reloaded.", filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Extension %s failed to reload: %s", filename, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rootmenu->ConsolePrint("[SM] Extension %s is not loaded.", pExt->GetFilename());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
|
rootmenu->ConsolePrint("SourceMod Extensions Menu:");
|
||||||
g_RootMenu.DrawGenericOption("info", "Extra extension information");
|
rootmenu->DrawGenericOption("info", "Extra extension information");
|
||||||
g_RootMenu.DrawGenericOption("list", "List extensions");
|
rootmenu->DrawGenericOption("list", "List extensions");
|
||||||
g_RootMenu.DrawGenericOption("unload", "Unload an extension");
|
rootmenu->DrawGenericOption("load", "Load an extension");
|
||||||
|
rootmenu->DrawGenericOption("reload", "Reload an extension");
|
||||||
|
rootmenu->DrawGenericOption("unload", "Unload an extension");
|
||||||
}
|
}
|
||||||
|
|
||||||
CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
|
CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
|
||||||
@@ -1141,7 +1290,7 @@ void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
|
|||||||
{
|
{
|
||||||
CExtension *pExt = (CExtension *)pSource;
|
CExtension *pExt = (CExtension *)pSource;
|
||||||
pExt->AddLibrary(library);
|
pExt->AddLibrary(library);
|
||||||
g_PluginSys.OnLibraryAction(library, false, false);
|
scripts->OnLibraryAction(library, LibraryAction_Added);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CExtensionManager::LibraryExists(const char *library)
|
bool CExtensionManager::LibraryExists(const char *library)
|
||||||
@@ -1210,3 +1359,29 @@ void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CVector<IExtension *> *CExtensionManager::ListExtensions()
|
||||||
|
{
|
||||||
|
CVector<IExtension *> *list = new CVector<IExtension *>();
|
||||||
|
for (List<CExtension *>::iterator iter = m_Libs.begin(); iter != m_Libs.end(); iter++)
|
||||||
|
list->push_back(*iter);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CExtensionManager::FreeExtensionList(const CVector<IExtension *> *list)
|
||||||
|
{
|
||||||
|
delete const_cast<CVector<IExtension *> *>(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -36,14 +36,13 @@
|
|||||||
#include <ILibrarySys.h>
|
#include <ILibrarySys.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include <sm_trie_tpl.h>
|
#include "common_logic.h"
|
||||||
#include "sm_globals.h"
|
|
||||||
#include "ShareSys.h"
|
|
||||||
#include <ISmmAPI.h>
|
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <IRootConsoleMenu.h>
|
#include <IRootConsoleMenu.h>
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "NativeOwner.h"
|
#include "NativeOwner.h"
|
||||||
|
#include "ShareSys.h"
|
||||||
|
|
||||||
|
class CPlayer;
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
@@ -66,6 +65,7 @@ public:
|
|||||||
public: //IExtension
|
public: //IExtension
|
||||||
IExtensionInterface *GetAPI();
|
IExtensionInterface *GetAPI();
|
||||||
const char *GetFilename();
|
const char *GetFilename();
|
||||||
|
const char *GetPath() const;
|
||||||
IdentityToken_t *GetIdentity();
|
IdentityToken_t *GetIdentity();
|
||||||
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||||
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||||
@@ -83,6 +83,8 @@ public:
|
|||||||
virtual bool Load(char *error, size_t maxlength);
|
virtual bool Load(char *error, size_t maxlength);
|
||||||
virtual bool IsLoaded() =0;
|
virtual bool IsLoaded() =0;
|
||||||
virtual void Unload() =0;
|
virtual void Unload() =0;
|
||||||
|
virtual bool Reload(char *error, size_t maxlength) =0;
|
||||||
|
virtual bool IsSameFile(const char* file) =0;
|
||||||
protected:
|
protected:
|
||||||
void Initialize(const char *filename, const char *path);
|
void Initialize(const char *filename, const char *path);
|
||||||
bool PerformAPICheck(char *error, size_t maxlength);
|
bool PerformAPICheck(char *error, size_t maxlength);
|
||||||
@@ -92,6 +94,7 @@ protected:
|
|||||||
IdentityToken_t *m_pIdentToken;
|
IdentityToken_t *m_pIdentToken;
|
||||||
IExtensionInterface *m_pAPI;
|
IExtensionInterface *m_pAPI;
|
||||||
String m_File;
|
String m_File;
|
||||||
|
String m_RealFile;
|
||||||
String m_Path;
|
String m_Path;
|
||||||
String m_Error;
|
String m_Error;
|
||||||
List<IfaceInfo> m_Deps; /** Dependencies */
|
List<IfaceInfo> m_Deps; /** Dependencies */
|
||||||
@@ -110,9 +113,11 @@ public:
|
|||||||
bool Load(char *error, size_t maxlength);
|
bool Load(char *error, size_t maxlength);
|
||||||
bool IsLoaded();
|
bool IsLoaded();
|
||||||
void Unload();
|
void Unload();
|
||||||
|
bool Reload(char *error, size_t maxlength);
|
||||||
bool IsExternal();
|
bool IsExternal();
|
||||||
|
bool IsSameFile(const char *file);
|
||||||
private:
|
private:
|
||||||
PluginId m_PlId;
|
int m_PlId;
|
||||||
ILibrary *m_pLib;
|
ILibrary *m_pLib;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,11 +129,13 @@ public:
|
|||||||
bool Load(char *error, size_t maxlength);
|
bool Load(char *error, size_t maxlength);
|
||||||
bool IsLoaded();
|
bool IsLoaded();
|
||||||
void Unload();
|
void Unload();
|
||||||
|
bool Reload(char *error, size_t maxlength);
|
||||||
bool IsExternal();
|
bool IsExternal();
|
||||||
|
bool IsSameFile(const char *file);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CExtensionManager :
|
class CExtensionManager :
|
||||||
public IExtensionManager,
|
public IExtensionSys,
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IPluginsListener,
|
public IPluginsListener,
|
||||||
public IRootConsoleCommand
|
public IRootConsoleCommand
|
||||||
@@ -156,10 +163,10 @@ public: //IPluginsListener
|
|||||||
public: //IRootConsoleCommand
|
public: //IRootConsoleCommand
|
||||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||||
public:
|
public:
|
||||||
IExtension *LoadAutoExtension(const char *path);
|
IExtension *LoadAutoExtension(const char *path, bool bErrorOnMissing=true);
|
||||||
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
||||||
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
|
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
|
||||||
void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
|
void BindChildPlugin(IExtension *pParent, SMPlugin *pPlugin);
|
||||||
void MarkAllLoaded();
|
void MarkAllLoaded();
|
||||||
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
|
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
|
||||||
void TryAutoload();
|
void TryAutoload();
|
||||||
@@ -167,6 +174,8 @@ public:
|
|||||||
bool LibraryExists(const char *library);
|
bool LibraryExists(const char *library);
|
||||||
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
|
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
|
||||||
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
|
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
|
||||||
|
const CVector<IExtension *> *ListExtensions();
|
||||||
|
void FreeExtensionList(const CVector<IExtension *> *list);
|
||||||
public:
|
public:
|
||||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -33,9 +33,8 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "ForwardSys.h"
|
#include "ForwardSys.h"
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "ShareSys.h"
|
|
||||||
#include "DebugReporter.h"
|
#include "DebugReporter.h"
|
||||||
|
#include "common_logic.h"
|
||||||
|
|
||||||
CForwardManager g_Forwards;
|
CForwardManager g_Forwards;
|
||||||
|
|
||||||
@@ -63,8 +62,8 @@ CForwardManager::~CForwardManager()
|
|||||||
|
|
||||||
void CForwardManager::OnSourceModAllInitialized()
|
void CForwardManager::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_PluginSys.AddPluginsListener(this);
|
scripts->AddPluginsListener(this);
|
||||||
g_ShareSys.AddInterface(NULL, this);
|
sharesys->AddInterface(NULL, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
|
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
|
||||||
@@ -79,7 +78,7 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned
|
|||||||
|
|
||||||
if (fwd)
|
if (fwd)
|
||||||
{
|
{
|
||||||
g_PluginSys.AddFunctionsToForward(name, fwd);
|
scripts->AddFunctionsToForward(name, fwd);
|
||||||
|
|
||||||
m_managed.push_back(fwd);
|
m_managed.push_back(fwd);
|
||||||
}
|
}
|
||||||
@@ -193,6 +192,7 @@ void CForwardManager::ForwardFree(CForward *fwd)
|
|||||||
|
|
||||||
m_FreeForwards.push(fwd);
|
m_FreeForwards.push(fwd);
|
||||||
m_managed.remove(fwd);
|
m_managed.remove(fwd);
|
||||||
|
m_unmanaged.remove(fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
CForward *CForwardManager::ForwardMake()
|
CForward *CForwardManager::ForwardMake()
|
||||||
@@ -210,7 +210,23 @@ CForward *CForwardManager::ForwardMake()
|
|||||||
|
|
||||||
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
|
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
|
||||||
{
|
{
|
||||||
/* No longer used */
|
if(paused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Attach any globally managed forwards */
|
||||||
|
List<CForward *>::iterator iter;
|
||||||
|
CForward *fwd;
|
||||||
|
|
||||||
|
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||||
|
{
|
||||||
|
fwd = (*iter);
|
||||||
|
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
|
||||||
|
// Only add functions, if they aren't registered yet!
|
||||||
|
if (pFunc && !fwd->IsFunctionRegistered(pFunc))
|
||||||
|
{
|
||||||
|
fwd->AddFunction(pFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************
|
/*************************************
|
||||||
@@ -255,6 +271,7 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
CForward *pForward = g_Forwards.ForwardMake();
|
CForward *pForward = g_Forwards.ForwardMake();
|
||||||
|
pForward->m_IterGuard = NULL;
|
||||||
pForward->m_curparam = 0;
|
pForward->m_curparam = 0;
|
||||||
pForward->m_ExecType = et;
|
pForward->m_ExecType = et;
|
||||||
snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
|
snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
|
||||||
@@ -294,7 +311,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
cell_t high_result = 0;
|
cell_t high_result = 0;
|
||||||
cell_t low_result = 0;
|
cell_t low_result = 0;
|
||||||
int err;
|
int err;
|
||||||
unsigned int failed=0, success=0;
|
unsigned int success=0;
|
||||||
unsigned int num_params = m_curparam;
|
unsigned int num_params = m_curparam;
|
||||||
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||||
FwdParamInfo *param;
|
FwdParamInfo *param;
|
||||||
@@ -304,10 +321,15 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
memcpy(temp_info, m_params, sizeof(m_params));
|
memcpy(temp_info, m_params, sizeof(m_params));
|
||||||
m_curparam = 0;
|
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);
|
func = (*iter);
|
||||||
|
|
||||||
|
if (filter)
|
||||||
|
filter->Preprocess(func, temp_info);
|
||||||
|
|
||||||
for (unsigned int i=0; i<num_params; i++)
|
for (unsigned int i=0; i<num_params; i++)
|
||||||
{
|
{
|
||||||
int err = SP_ERROR_PARAM;
|
int err = SP_ERROR_PARAM;
|
||||||
@@ -359,11 +381,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Call the function and deal with the return value. */
|
/* 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)
|
||||||
{
|
|
||||||
failed++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
success++;
|
success++;
|
||||||
switch (m_ExecType)
|
switch (m_ExecType)
|
||||||
@@ -403,6 +421,9 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!guard.Triggered())
|
||||||
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@@ -678,10 +699,11 @@ bool CForward::RemoveFunction(IPluginFunction *func)
|
|||||||
lst = &m_paused;
|
lst = &m_paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
for (iter=lst->begin(); iter!=lst->end(); iter++)
|
||||||
{
|
{
|
||||||
if ((*iter) == func)
|
if ((*iter) == func)
|
||||||
{
|
{
|
||||||
|
m_IterGuard->FixIteratorChain(iter);
|
||||||
found = true;
|
found = true;
|
||||||
lst->erase(iter);
|
lst->erase(iter);
|
||||||
break;
|
break;
|
||||||
@@ -735,6 +757,28 @@ bool CForward::AddFunction(IPluginFunction *func)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CForward::IsFunctionRegistered(IPluginFunction *func)
|
||||||
|
{
|
||||||
|
FuncIter iter;
|
||||||
|
List<IPluginFunction *> *lst;
|
||||||
|
|
||||||
|
if (func->IsRunnable())
|
||||||
|
{
|
||||||
|
lst = &m_functions;
|
||||||
|
} else {
|
||||||
|
lst = &m_paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||||
|
{
|
||||||
|
if ((*iter) == func)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char *CForward::GetForwardName()
|
const char *CForward::GetForwardName()
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
@@ -34,10 +34,10 @@
|
|||||||
|
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include "sm_globals.h"
|
#include "common_logic.h"
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include "sourcemod.h"
|
#include "ISourceMod.h"
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
@@ -46,19 +46,48 @@ 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
|
#define FORWARDS_NAME_MAX 64
|
||||||
|
|
||||||
struct ByrefInfo
|
class FuncIteratorGuard
|
||||||
{
|
{
|
||||||
unsigned int cells;
|
bool triggered;
|
||||||
cell_t *orig_addr;
|
FuncIteratorGuard **pprev;
|
||||||
int flags;
|
FuncIter *iter;
|
||||||
int sz_flags;
|
FuncIteratorGuard *next;
|
||||||
};
|
public:
|
||||||
|
FuncIteratorGuard(FuncIteratorGuard **pprev, FuncIter *iter)
|
||||||
|
: triggered(false), pprev(pprev), iter(iter), next(*pprev)
|
||||||
|
{
|
||||||
|
*pprev = this;
|
||||||
|
}
|
||||||
|
|
||||||
struct FwdParamInfo
|
~FuncIteratorGuard()
|
||||||
{
|
{
|
||||||
cell_t val;
|
*pprev = next;
|
||||||
ByrefInfo byref;
|
}
|
||||||
ParamType pushedas;
|
|
||||||
|
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
|
class CForward : public IChangeableForward
|
||||||
@@ -89,6 +118,7 @@ public:
|
|||||||
unsigned int num_params,
|
unsigned int num_params,
|
||||||
const ParamType *types,
|
const ParamType *types,
|
||||||
va_list ap);
|
va_list ap);
|
||||||
|
bool IsFunctionRegistered(IPluginFunction *func);
|
||||||
private:
|
private:
|
||||||
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||||
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
|
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
|
||||||
@@ -103,6 +133,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
mutable List<IPluginFunction *> m_functions;
|
mutable List<IPluginFunction *> m_functions;
|
||||||
mutable List<IPluginFunction *> m_paused;
|
mutable List<IPluginFunction *> m_paused;
|
||||||
|
FuncIteratorGuard *m_IterGuard;
|
||||||
|
|
||||||
/* Type and name information */
|
/* Type and name information */
|
||||||
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
|
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet:
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -32,14 +32,12 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
|
#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
|
||||||
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
|
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
|
||||||
|
|
||||||
|
#include "common_logic.h"
|
||||||
#include <IGameConfigs.h>
|
#include <IGameConfigs.h>
|
||||||
#include <ITextParsers.h>
|
#include <ITextParsers.h>
|
||||||
#include <sh_list.h>
|
#include <am-refcounting.h>
|
||||||
#include "sm_trie.h"
|
#include <sm_stringhashmap.h>
|
||||||
#include "sm_globals.h"
|
#include <sm_namehashset.h>
|
||||||
#include "sm_memtable.h"
|
|
||||||
#include "sm_trie_tpl.h"
|
|
||||||
#include "ThreadSupport.h"
|
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
@@ -48,15 +46,18 @@ class SendProp;
|
|||||||
|
|
||||||
class CGameConfig :
|
class CGameConfig :
|
||||||
public ITextListener_SMC,
|
public ITextListener_SMC,
|
||||||
public IGameConfig
|
public IGameConfig,
|
||||||
|
public ke::Refcounted<CGameConfig>
|
||||||
{
|
{
|
||||||
friend class GameConfigManager;
|
friend class GameConfigManager;
|
||||||
public:
|
public:
|
||||||
CGameConfig(const char *file);
|
CGameConfig(const char *file, const char *engine = NULL);
|
||||||
~CGameConfig();
|
~CGameConfig();
|
||||||
public:
|
public:
|
||||||
bool Reparse(char *error, size_t maxlength);
|
bool Reparse(char *error, size_t maxlength);
|
||||||
bool EnterFile(const char *file, char *error, size_t maxlength);
|
bool EnterFile(const char *file, char *error, size_t maxlength);
|
||||||
|
void SetBaseEngine(const char *engine);
|
||||||
|
void SetParseEngine(const char *engine);
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
@@ -66,18 +67,19 @@ public: //IGameConfig
|
|||||||
bool GetOffset(const char *key, int *value);
|
bool GetOffset(const char *key, int *value);
|
||||||
SendProp *GetSendProp(const char *key);
|
SendProp *GetSendProp(const char *key);
|
||||||
bool GetMemSig(const char *key, void **addr);
|
bool GetMemSig(const char *key, void **addr);
|
||||||
public:
|
bool GetAddress(const char *key, void **addr);
|
||||||
void IncRefCount();
|
public: //NameHashSet
|
||||||
unsigned int DecRefCount();
|
static inline bool matches(const char *key, const CGameConfig *value)
|
||||||
|
{
|
||||||
|
return strcmp(key, value->m_File) == 0;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
BaseStringTable *m_pStrings;
|
|
||||||
char m_File[PLATFORM_MAX_PATH];
|
char m_File[PLATFORM_MAX_PATH];
|
||||||
char m_CurFile[PLATFORM_MAX_PATH];
|
char m_CurFile[PLATFORM_MAX_PATH];
|
||||||
Trie *m_pOffsets;
|
StringHashMap<int> m_Offsets;
|
||||||
Trie *m_pProps;
|
StringHashMap<SendProp *> m_Props;
|
||||||
Trie *m_pKeys;
|
StringHashMap<ke::AString> m_Keys;
|
||||||
Trie *m_pSigs;
|
StringHashMap<void *> m_Sigs;
|
||||||
unsigned int m_RefCount;
|
|
||||||
/* Parse states */
|
/* Parse states */
|
||||||
int m_ParseState;
|
int m_ParseState;
|
||||||
unsigned int m_IgnoreLevel;
|
unsigned int m_IgnoreLevel;
|
||||||
@@ -90,10 +92,31 @@ private:
|
|||||||
bool matched_game;
|
bool matched_game;
|
||||||
bool had_engine;
|
bool had_engine;
|
||||||
bool matched_engine;
|
bool matched_engine;
|
||||||
|
bool matched_platform;
|
||||||
|
|
||||||
/* Custom Sections */
|
/* Custom Sections */
|
||||||
unsigned int m_CustomLevel;
|
unsigned int m_CustomLevel;
|
||||||
ITextListener_SMC *m_CustomHandler;
|
ITextListener_SMC *m_CustomHandler;
|
||||||
|
|
||||||
|
/* Support for reading Addresses */
|
||||||
|
struct AddressConf
|
||||||
|
{
|
||||||
|
char signatureName[64];
|
||||||
|
int readCount;
|
||||||
|
int read[8];
|
||||||
|
|
||||||
|
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read);
|
||||||
|
|
||||||
|
AddressConf() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
char m_Address[64];
|
||||||
|
char m_AddressSignature[64];
|
||||||
|
int m_AddressReadCount;
|
||||||
|
int m_AddressRead[8];
|
||||||
|
StringHashMap<AddressConf> m_Addresses;
|
||||||
|
const char *m_pEngine;
|
||||||
|
const char *m_pBaseEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameConfigManager :
|
class GameConfigManager :
|
||||||
@@ -117,11 +140,12 @@ public: //SMGlobalClass
|
|||||||
void OnSourceModStartup(bool late);
|
void OnSourceModStartup(bool late);
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
void OnSourceModAllShutdown();
|
void OnSourceModAllShutdown();
|
||||||
private:
|
|
||||||
List<CGameConfig *> m_cfgs;
|
|
||||||
Trie *m_pLookup;
|
|
||||||
public:
|
public:
|
||||||
KTrie<ITextListener_SMC *> m_customHandlers;
|
void RemoveCachedConfig(CGameConfig *config);
|
||||||
|
private:
|
||||||
|
NameHashSet<CGameConfig *> m_Lookup;
|
||||||
|
public:
|
||||||
|
StringHashMap<ITextListener_SMC *> m_customHandlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GameConfigManager g_GameConfigs;
|
extern GameConfigManager g_GameConfigs;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -30,13 +30,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include "ShareSys.h"
|
|
||||||
#include "PluginSys.h"
|
|
||||||
#include "ExtensionSys.h"
|
|
||||||
#include "Logger.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sm_stringutil.h"
|
#include "common_logic.h"
|
||||||
|
#include "ShareSys.h"
|
||||||
|
#include "ExtensionSys.h"
|
||||||
|
#include "PluginSys.h"
|
||||||
|
|
||||||
HandleSystem g_HandleSys;
|
HandleSystem g_HandleSys;
|
||||||
|
|
||||||
@@ -60,9 +59,6 @@ HandleSystem::HandleSystem()
|
|||||||
m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
|
m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
|
||||||
memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
|
memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
|
||||||
|
|
||||||
m_TypeLookup = sm_trie_create();
|
|
||||||
m_strtab = new BaseStringTable(512);
|
|
||||||
|
|
||||||
m_TypeTail = 0;
|
m_TypeTail = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +66,6 @@ HandleSystem::~HandleSystem()
|
|||||||
{
|
{
|
||||||
delete [] m_Handles;
|
delete [] m_Handles;
|
||||||
delete [] m_Types;
|
delete [] m_Types;
|
||||||
sm_trie_destroy(m_TypeLookup);
|
|
||||||
delete m_strtab;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -145,12 +139,10 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
|||||||
|
|
||||||
if (name && name[0] != '\0')
|
if (name && name[0] != '\0')
|
||||||
{
|
{
|
||||||
if (sm_trie_retrieve(m_TypeLookup, name, NULL))
|
if (m_TypeLookup.contains(name))
|
||||||
{
|
{
|
||||||
if (err)
|
if (err)
|
||||||
{
|
|
||||||
*err = HandleError_Parameter;
|
*err = HandleError_Parameter;
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,10 +204,8 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
|||||||
pType->dispatch = dispatch;
|
pType->dispatch = dispatch;
|
||||||
if (name && name[0] != '\0')
|
if (name && name[0] != '\0')
|
||||||
{
|
{
|
||||||
pType->nameIdx = m_strtab->AddString(name);
|
pType->name = new ke::AString(name);
|
||||||
sm_trie_insert(m_TypeLookup, name, (void *)pType);
|
m_TypeLookup.insert(name, pType);
|
||||||
} else {
|
|
||||||
pType->nameIdx = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pType->opened = 0;
|
pType->opened = 0;
|
||||||
@@ -243,21 +233,14 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
|
bool HandleSystem::FindHandleType(const char *name, HandleType_t *aResult)
|
||||||
{
|
{
|
||||||
QHandleType *_type;
|
QHandleType *type;
|
||||||
|
if (!m_TypeLookup.retrieve(name, &type))
|
||||||
if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int offset = _type - m_Types;
|
if (aResult)
|
||||||
|
*aResult = type - m_Types;
|
||||||
if (type)
|
|
||||||
{
|
|
||||||
*type = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -579,6 +562,7 @@ HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Hand
|
|||||||
}
|
}
|
||||||
|
|
||||||
pNewHandle->clone = index;
|
pNewHandle->clone = index;
|
||||||
|
pNewHandle->object = NULL;
|
||||||
pHandle->refcount++;
|
pHandle->refcount++;
|
||||||
|
|
||||||
*newhandle = new_handle;
|
*newhandle = new_handle;
|
||||||
@@ -620,8 +604,53 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, Iden
|
|||||||
return CloneHandle(pHandle, index, newhandle, newOwner);
|
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)
|
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];
|
QHandleType *pType = &m_Types[pHandle->type];
|
||||||
|
|
||||||
if (pHandle->clone)
|
if (pHandle->clone)
|
||||||
@@ -636,6 +665,7 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
|||||||
pMaster = &m_Handles[master];
|
pMaster = &m_Handles[master];
|
||||||
|
|
||||||
/* Release the clone now */
|
/* Release the clone now */
|
||||||
|
pHandle->is_destroying = true;
|
||||||
ReleasePrimHandle(index);
|
ReleasePrimHandle(index);
|
||||||
|
|
||||||
/* Decrement the master's reference count */
|
/* Decrement the master's reference count */
|
||||||
@@ -644,20 +674,27 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
|||||||
/* Type should be the same but do this anyway... */
|
/* Type should be the same but do this anyway... */
|
||||||
pType = &m_Types[pMaster->type];
|
pType = &m_Types[pMaster->type];
|
||||||
pMaster->is_destroying = true;
|
pMaster->is_destroying = true;
|
||||||
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
|
if (pMaster->object)
|
||||||
|
{
|
||||||
|
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
|
||||||
|
}
|
||||||
ReleasePrimHandle(master);
|
ReleasePrimHandle(master);
|
||||||
}
|
}
|
||||||
} else if (pHandle->set == HandleSet_Identity) {
|
} else if (pHandle->set == HandleSet_Identity) {
|
||||||
/* If we're an identity, skip all this stuff!
|
/* If we're an identity, skip all this stuff!
|
||||||
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
|
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
|
||||||
*/
|
*/
|
||||||
|
pHandle->is_destroying = true;
|
||||||
ReleasePrimHandle(index);
|
ReleasePrimHandle(index);
|
||||||
} else {
|
} else {
|
||||||
/* Decrement, free if necessary */
|
/* Decrement, free if necessary */
|
||||||
if (--pHandle->refcount == 0)
|
if (--pHandle->refcount == 0)
|
||||||
{
|
{
|
||||||
pHandle->is_destroying = true;
|
pHandle->is_destroying = true;
|
||||||
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
if (pHandle->object)
|
||||||
|
{
|
||||||
|
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
||||||
|
}
|
||||||
ReleasePrimHandle(index);
|
ReleasePrimHandle(index);
|
||||||
} else {
|
} else {
|
||||||
/* We must be cloned, so mark ourselves as freed */
|
/* We must be cloned, so mark ourselves as freed */
|
||||||
@@ -690,14 +727,6 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec
|
|||||||
return HandleError_Access;
|
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);
|
return FreeHandle(pHandle, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -756,6 +785,9 @@ void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
|
|||||||
assert(pHandle->owner == 0);
|
assert(pHandle->owner == 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pHandle->owner = NULL;
|
||||||
|
|
||||||
/* Note that since 0 is an invalid handle, if any of these links are 0,
|
/* Note that since 0 is an invalid handle, if any of these links are 0,
|
||||||
* the data can still be set.
|
* the data can still be set.
|
||||||
*/
|
*/
|
||||||
@@ -865,10 +897,6 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
|||||||
m_Types[++m_FreeTypes].freeID = type;
|
m_Types[++m_FreeTypes].freeID = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalidate the type now */
|
|
||||||
IHandleTypeDispatch *dispatch = pType->dispatch;
|
|
||||||
pType->dispatch = NULL;
|
|
||||||
|
|
||||||
/* Make sure nothing is using this type. */
|
/* Make sure nothing is using this type. */
|
||||||
if (pType->opened)
|
if (pType->opened)
|
||||||
{
|
{
|
||||||
@@ -880,29 +908,9 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pHandle->clone)
|
|
||||||
{
|
FreeHandle(pHandle, i);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pType->opened == 0)
|
if (pType->opened == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -910,14 +918,12 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove it from the type cache. */
|
/* Invalidate the type now */
|
||||||
if (pType->nameIdx != -1)
|
pType->dispatch = NULL;
|
||||||
{
|
|
||||||
const char *typeName;
|
|
||||||
|
|
||||||
typeName = m_strtab->GetString(pType->nameIdx);
|
/* Remove it from the type cache. */
|
||||||
sm_trie_delete(m_TypeLookup, typeName);
|
if (pType->name)
|
||||||
}
|
m_TypeLookup.remove(pType->name->chars());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -950,14 +956,17 @@ bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHa
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HANDLE_LOG_VERY_BAD(message, ...) \
|
||||||
|
smcore.LogFatal(message, ##__VA_ARGS__); \
|
||||||
|
smcore.LogError(message, ##__VA_ARGS__);
|
||||||
|
|
||||||
bool HandleSystem::TryAndFreeSomeHandles()
|
bool HandleSystem::TryAndFreeSomeHandles()
|
||||||
{
|
{
|
||||||
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
|
|
||||||
IPlugin *highest_owner = NULL;
|
IPlugin *highest_owner = NULL;
|
||||||
unsigned int highest_handle_count = 0;
|
unsigned int highest_handle_count = 0;
|
||||||
|
|
||||||
/* Search all plugins */
|
/* 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();
|
IPlugin *plugin = pl_iter->GetPlugin();
|
||||||
IdentityToken_t *identity = plugin->GetIdentity();
|
IdentityToken_t *identity = plugin->GetIdentity();
|
||||||
@@ -986,8 +995,6 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
highest_owner = plugin;
|
highest_owner = plugin;
|
||||||
highest_handle_count = handle_count;
|
highest_handle_count = handle_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_iter->NextPlugin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highest_owner == NULL || highest_handle_count == 0)
|
if (highest_owner == NULL || highest_handle_count == 0)
|
||||||
@@ -995,13 +1002,66 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
|
HANDLE_LOG_VERY_BAD("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
|
||||||
g_Logger.LogFatal("[SM] Unloading plugin to free %d handles.", highest_handle_count);
|
HANDLE_LOG_VERY_BAD("[SM] Unloading 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] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
|
||||||
|
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
const IdentityToken_t *pIdentity = highest_owner->GetIdentity();
|
||||||
|
unsigned int total = 0, highest_index = 0, total_size = 0, size;
|
||||||
|
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
|
||||||
|
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
|
||||||
|
|
||||||
|
for (unsigned int i = 1; i <= m_HandleTail; ++i)
|
||||||
|
{
|
||||||
|
const QHandle &Handle = m_Handles[i];
|
||||||
|
if (Handle.set != HandleSet_Used || Handle.owner != pIdentity)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++pCount[Handle.type];
|
||||||
|
++total;
|
||||||
|
|
||||||
|
if (Handle.type >= highest_index)
|
||||||
|
{
|
||||||
|
highest_index = ((Handle.type) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Handle.clone != 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Types[Handle.type].dispatch->GetHandleApproxSize(Handle.type, Handle.object, &size))
|
||||||
|
{
|
||||||
|
total_size += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * pTypeName = NULL;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < highest_index; ++i)
|
||||||
|
{
|
||||||
|
if (pCount[i] == 0)
|
||||||
|
{
|
||||||
|
continue; /* We may have gaps, it's fine. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Types[i].name)
|
||||||
|
pTypeName = m_Types[i].name->chars();
|
||||||
|
else
|
||||||
|
pTypeName = "ANON";
|
||||||
|
|
||||||
|
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
|
||||||
|
delete [] pCount;
|
||||||
|
|
||||||
highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
|
highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
|
||||||
|
|
||||||
return g_PluginSys.UnloadPlugin(highest_owner);
|
return scripts->UnloadPlugin(highest_owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleSystem::Dump(HANDLE_REPORTER rep)
|
void HandleSystem::Dump(HANDLE_REPORTER rep)
|
||||||
@@ -1026,20 +1086,20 @@ void HandleSystem::Dump(HANDLE_REPORTER rep)
|
|||||||
{
|
{
|
||||||
owner = "CORE";
|
owner = "CORE";
|
||||||
}
|
}
|
||||||
else if (pOwner == g_PluginSys.GetIdentity())
|
else if (pOwner == scripts->GetIdentity())
|
||||||
{
|
{
|
||||||
owner = "PLUGINSYS";
|
owner = "PLUGINSYS";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
|
IExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
|
||||||
if (ext)
|
if (ext)
|
||||||
{
|
{
|
||||||
owner = ext->GetFilename();
|
owner = ext->GetFilename();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
|
SMPlugin *pPlugin = scripts->FindPluginByIdentity(pOwner);
|
||||||
if (pPlugin)
|
if (pPlugin)
|
||||||
{
|
{
|
||||||
owner = pPlugin->GetFilename();
|
owner = pPlugin->GetFilename();
|
||||||
@@ -1054,19 +1114,37 @@ void HandleSystem::Dump(HANDLE_REPORTER rep)
|
|||||||
const char *type = "ANON";
|
const char *type = "ANON";
|
||||||
QHandleType *pType = &m_Types[m_Handles[i].type];
|
QHandleType *pType = &m_Types[m_Handles[i].type];
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
if (pType->nameIdx != -1)
|
unsigned int parentIdx;
|
||||||
|
bool bresult;
|
||||||
|
if (pType->name)
|
||||||
|
type = pType->name->chars();
|
||||||
|
|
||||||
|
if ((parentIdx = m_Handles[i].clone) != 0)
|
||||||
{
|
{
|
||||||
type = m_strtab->GetString(pType->nameIdx);
|
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
|
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");
|
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
UTIL_Format(buffer, sizeof(buffer), "%d", size);
|
smcore.Format(buffer, sizeof(buffer), "%d", size);
|
||||||
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
|
rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
|
||||||
total_size += size;
|
total_size += size;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||||
@@ -34,10 +34,9 @@
|
|||||||
|
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "sm_globals.h"
|
#include <sm_namehashset.h>
|
||||||
#include "sm_trie.h"
|
#include <am-string.h>
|
||||||
#include "sourcemod.h"
|
#include "common_logic.h"
|
||||||
#include "sm_memtable.h"
|
|
||||||
|
|
||||||
#define HANDLESYS_MAX_HANDLES (1<<14)
|
#define HANDLESYS_MAX_HANDLES (1<<14)
|
||||||
#define HANDLESYS_MAX_TYPES (1<<9)
|
#define HANDLESYS_MAX_TYPES (1<<9)
|
||||||
@@ -104,7 +103,12 @@ struct QHandleType
|
|||||||
TypeAccess typeSec;
|
TypeAccess typeSec;
|
||||||
HandleAccess hndlSec;
|
HandleAccess hndlSec;
|
||||||
unsigned int opened;
|
unsigned int opened;
|
||||||
int nameIdx;
|
ke::AutoPtr<ke::AString> name;
|
||||||
|
|
||||||
|
static inline bool matches(const char *key, const QHandleType *type)
|
||||||
|
{
|
||||||
|
return type->name && type->name->compare(key) == 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (HANDLE_REPORTER)(const char *str, ...);
|
typedef void (HANDLE_REPORTER)(const char *str, ...);
|
||||||
@@ -160,6 +164,9 @@ public: //IHandleSystem
|
|||||||
HandleError *err);
|
HandleError *err);
|
||||||
|
|
||||||
void Dump(HANDLE_REPORTER rep);
|
void Dump(HANDLE_REPORTER rep);
|
||||||
|
|
||||||
|
/* Bypasses security checks. */
|
||||||
|
Handle_t FastCloneHandle(Handle_t hndl);
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Decodes a handle with sanity and security checking.
|
* Decodes a handle with sanity and security checking.
|
||||||
@@ -170,6 +177,9 @@ protected:
|
|||||||
unsigned int *index,
|
unsigned int *index,
|
||||||
bool ignoreFree=false);
|
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.
|
* Creates a basic handle and sets its reference count to 1.
|
||||||
* Does not do any type or security checking.
|
* Does not do any type or security checking.
|
||||||
@@ -211,15 +221,37 @@ protected:
|
|||||||
private:
|
private:
|
||||||
QHandle *m_Handles;
|
QHandle *m_Handles;
|
||||||
QHandleType *m_Types;
|
QHandleType *m_Types;
|
||||||
Trie *m_TypeLookup;
|
NameHashSet<QHandleType *> m_TypeLookup;
|
||||||
unsigned int m_TypeTail;
|
unsigned int m_TypeTail;
|
||||||
unsigned int m_FreeTypes;
|
unsigned int m_FreeTypes;
|
||||||
unsigned int m_HandleTail;
|
unsigned int m_HandleTail;
|
||||||
unsigned int m_FreeHandles;
|
unsigned int m_FreeHandles;
|
||||||
unsigned int m_HSerial;
|
unsigned int m_HSerial;
|
||||||
BaseStringTable *m_strtab;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern HandleSystem g_HandleSys;
|
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_
|
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
# (C)2004-2008 SourceMod Development Team
|
||||||
|
# Makefile written by David "BAILOPAN" Anderson
|
||||||
|
|
||||||
|
SMSDK = ../..
|
||||||
|
MMSOURCE17 = ../../../mmsource-1.7
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
BINARY = sourcemod.logic.so
|
||||||
|
|
||||||
|
OBJECTS = \
|
||||||
|
common_logic.cpp \
|
||||||
|
smn_adt_array.cpp \
|
||||||
|
smn_sorting.cpp \
|
||||||
|
smn_maplists.cpp \
|
||||||
|
smn_adt_stack.cpp \
|
||||||
|
thread/ThreadWorker.cpp \
|
||||||
|
thread/BaseWorker.cpp \
|
||||||
|
thread/PosixThreads.cpp \
|
||||||
|
ThreadSupport.cpp \
|
||||||
|
smn_float.cpp \
|
||||||
|
TextParsers.cpp \
|
||||||
|
smn_textparse.cpp \
|
||||||
|
smn_adt_trie.cpp \
|
||||||
|
Profiler.cpp \
|
||||||
|
smn_functions.cpp \
|
||||||
|
sm_crc32.cpp \
|
||||||
|
smn_timers.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 \
|
||||||
|
smn_players.cpp \
|
||||||
|
smn_profiler.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
|
||||||
|
|
||||||
|
LINK += -lpthread -static-libgcc
|
||||||
|
|
||||||
|
INCLUDE += -I. -I$(MMSOURCE17)/core/sourcehook -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
|
||||||
|
|
||||||
|
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||||
|
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||||
|
-Wno-uninitialized -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -m32 \
|
||||||
|
-DSM_LOGIC
|
||||||
|
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
||||||
|
|
||||||
|
################################################
|
||||||
|
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||||
|
################################################
|
||||||
|
|
||||||
|
ifeq "$(DEBUG)" "true"
|
||||||
|
BIN_DIR = Debug
|
||||||
|
CFLAGS += $(C_DEBUG_FLAGS)
|
||||||
|
else
|
||||||
|
BIN_DIR = Release
|
||||||
|
CFLAGS += $(C_OPT_FLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||||
|
ifeq "$(GCC_VERSION)" "4"
|
||||||
|
CFLAGS += $(C_GCC4_FLAGS)
|
||||||
|
CPPFLAGS += $(CPP_GCC4_FLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
||||||
|
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
|
||||||
|
|
||||||
|
$(BIN_DIR)/%.o: %.cpp
|
||||||
|
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
$(BIN_DIR)/%.o: %.c
|
||||||
|
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p $(BIN_DIR)/thread
|
||||||
|
$(MAKE) -f Makefile sourcemod
|
||||||
|
|
||||||
|
sourcemod: $(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)/*.o
|
||||||
|
rm -rf $(BIN_DIR)/thread/*.o
|
||||||
|
rm -rf $(BIN_DIR)/$(BINARY)
|
||||||
@@ -0,0 +1,612 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "MemoryUtils.h"
|
||||||
|
#ifdef PLATFORM_LINUX
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_APPLE
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
#include <mach/task.h>
|
||||||
|
#include <mach-o/dyld_images.h>
|
||||||
|
#include <mach-o/loader.h>
|
||||||
|
#include <mach-o/nlist.h>
|
||||||
|
|
||||||
|
/* Define things from 10.6 SDK for older SDKs */
|
||||||
|
#ifndef MAC_OS_X_VERSION_10_6
|
||||||
|
struct task_dyld_info
|
||||||
|
{
|
||||||
|
mach_vm_address_t all_image_info_addr;
|
||||||
|
mach_vm_size_t all_image_info_size;
|
||||||
|
};
|
||||||
|
typedef struct task_dyld_info task_dyld_info_data_t;
|
||||||
|
#define TASK_DYLD_INFO 17
|
||||||
|
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
|
||||||
|
#endif // MAC_OS_X_VERSION_10_6
|
||||||
|
#endif // PLATFORM_APPLE
|
||||||
|
|
||||||
|
MemoryUtils g_MemUtils;
|
||||||
|
|
||||||
|
MemoryUtils::MemoryUtils()
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_APPLE
|
||||||
|
|
||||||
|
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
|
||||||
|
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
|
||||||
|
|
||||||
|
/* Get pointer to struct that describes all loaded mach-o images in process */
|
||||||
|
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
|
||||||
|
{
|
||||||
|
task_dyld_info_data_t dyld_info;
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
|
||||||
|
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct nlist list[2];
|
||||||
|
memset(list, 0, sizeof(list));
|
||||||
|
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
|
||||||
|
nlist("/usr/lib/dyld", list);
|
||||||
|
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryUtils::~MemoryUtils()
|
||||||
|
{
|
||||||
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
delete m_SymTables[i];
|
||||||
|
}
|
||||||
|
m_SymTables.clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryUtils::OnSourceModAllInitialized()
|
||||||
|
{
|
||||||
|
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 - len;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
return GetProcAddress((HMODULE)handle, symbol);
|
||||||
|
|
||||||
|
#elif defined PLATFORM_LINUX
|
||||||
|
|
||||||
|
struct link_map *dlmap;
|
||||||
|
struct stat dlstat;
|
||||||
|
int dlfile;
|
||||||
|
uintptr_t map_base;
|
||||||
|
Elf32_Ehdr *file_hdr;
|
||||||
|
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
|
||||||
|
Elf32_Sym *symtab;
|
||||||
|
const char *shstrtab, *strtab;
|
||||||
|
uint16_t section_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlmap = (struct link_map *)handle;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
strtab_hdr = NULL;
|
||||||
|
table = NULL;
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlmap->l_addr)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlmap->l_addr;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.push_back(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have open the actual library */
|
||||||
|
dlfile = open(dlmap->l_name, O_RDONLY);
|
||||||
|
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
|
||||||
|
{
|
||||||
|
close(dlfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map library file into memory */
|
||||||
|
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
|
||||||
|
map_base = (uintptr_t)file_hdr;
|
||||||
|
if (file_hdr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
close(dlfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
close(dlfile);
|
||||||
|
|
||||||
|
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
|
||||||
|
{
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
|
||||||
|
section_count = file_hdr->e_shnum;
|
||||||
|
/* Get ELF section header string table */
|
||||||
|
shstrtab_hdr = §ions[file_hdr->e_shstrndx];
|
||||||
|
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
|
||||||
|
|
||||||
|
/* Iterate sections while looking for ELF symbol table and string table */
|
||||||
|
for (uint16_t i = 0; i < section_count; i++)
|
||||||
|
{
|
||||||
|
Elf32_Shdr &hdr = sections[i];
|
||||||
|
const char *section_name = shstrtab + hdr.sh_name;
|
||||||
|
|
||||||
|
if (strcmp(section_name, ".symtab") == 0)
|
||||||
|
{
|
||||||
|
symtab_hdr = &hdr;
|
||||||
|
}
|
||||||
|
else if (strcmp(section_name, ".strtab") == 0)
|
||||||
|
{
|
||||||
|
strtab_hdr = &hdr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Uh oh, we don't have a symbol table or a string table */
|
||||||
|
if (symtab_hdr == NULL || strtab_hdr == NULL)
|
||||||
|
{
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
|
||||||
|
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
|
||||||
|
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
Elf32_Sym &sym = symtab[i];
|
||||||
|
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
|
||||||
|
const char *sym_name = strtab + sym.st_name;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined or do not refer to functions or objects */
|
||||||
|
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#elif defined PLATFORM_APPLE
|
||||||
|
|
||||||
|
uintptr_t dlbase, linkedit_addr;
|
||||||
|
uint32_t image_count;
|
||||||
|
struct mach_header *file_hdr;
|
||||||
|
struct load_command *loadcmds;
|
||||||
|
struct segment_command *linkedit_hdr;
|
||||||
|
struct symtab_command *symtab_hdr;
|
||||||
|
struct nlist *symtab;
|
||||||
|
const char *strtab;
|
||||||
|
uint32_t loadcmd_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlbase = 0;
|
||||||
|
image_count = m_ImageList->infoArrayCount;
|
||||||
|
linkedit_hdr = NULL;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
table = NULL;
|
||||||
|
|
||||||
|
/* Loop through mach-o images in process.
|
||||||
|
* We can skip index 0 since that is just the executable.
|
||||||
|
*/
|
||||||
|
for (uint32_t i = 1; i < image_count; i++)
|
||||||
|
{
|
||||||
|
const struct dyld_image_info &info = m_ImageList->infoArray[i];
|
||||||
|
|
||||||
|
/* "Load" each one until we get a matching handle */
|
||||||
|
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
|
||||||
|
if (h == handle)
|
||||||
|
{
|
||||||
|
dlbase = (uintptr_t)info.imageLoadAddress;
|
||||||
|
dlclose(h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlclose(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dlbase)
|
||||||
|
{
|
||||||
|
/* Uh oh, we couldn't find a matching handle */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlbase)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlbase;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.push_back(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have to locate it in memory */
|
||||||
|
|
||||||
|
file_hdr = (struct mach_header *)dlbase;
|
||||||
|
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
|
||||||
|
loadcmd_count = file_hdr->ncmds;
|
||||||
|
|
||||||
|
/* Loop through load commands until we find the ones for the symbol table */
|
||||||
|
for (uint32_t i = 0; i < loadcmd_count; i++)
|
||||||
|
{
|
||||||
|
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
|
||||||
|
{
|
||||||
|
struct segment_command *seg = (struct segment_command *)loadcmds;
|
||||||
|
if (strcmp(seg->segname, "__LINKEDIT") == 0)
|
||||||
|
{
|
||||||
|
linkedit_hdr = seg;
|
||||||
|
if (symtab_hdr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (loadcmds->cmd == LC_SYMTAB)
|
||||||
|
{
|
||||||
|
symtab_hdr = (struct symtab_command *)loadcmds;
|
||||||
|
if (linkedit_hdr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load commands are not of a fixed size which is why we add the size */
|
||||||
|
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
|
||||||
|
{
|
||||||
|
/* Uh oh, no symbol table */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
|
||||||
|
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
|
||||||
|
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
|
||||||
|
symbol_count = symtab_hdr->nsyms;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
struct nlist &sym = symtab[i];
|
||||||
|
/* Ignore the prepended underscore on all symbols, so +1 here */
|
||||||
|
const char *sym_name = strtab + sym.n_un.n_strx + 1;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined */
|
||||||
|
if (sym.n_sect == NO_SECT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||||
|
{
|
||||||
|
uintptr_t 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<uintptr_t>(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<uintptr_t>(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);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < phdrCount; i++)
|
||||||
|
{
|
||||||
|
Elf32_Phdr &hdr = phdr[i];
|
||||||
|
|
||||||
|
/* We only really care about the segment with executable code */
|
||||||
|
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
|
||||||
|
{
|
||||||
|
/* From glibc, elf/dl-load.c:
|
||||||
|
* c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
|
||||||
|
* & ~(GLRO(dl_pagesize) - 1));
|
||||||
|
*
|
||||||
|
* In glibc, the segment file size is aligned up to the nearest page size and
|
||||||
|
* added to the virtual address of the segment. We just want the size here.
|
||||||
|
*/
|
||||||
|
lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined PLATFORM_APPLE
|
||||||
|
|
||||||
|
Dl_info info;
|
||||||
|
struct mach_header *file;
|
||||||
|
struct segment_command *seg;
|
||||||
|
uint32_t cmd_count;
|
||||||
|
|
||||||
|
if (!dladdr(libPtr, &info))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is for our insane sanity checks :o */
|
||||||
|
baseAddr = (uintptr_t)info.dli_fbase;
|
||||||
|
file = (struct mach_header *)baseAddr;
|
||||||
|
|
||||||
|
/* Check Mach-O magic */
|
||||||
|
if (file->magic != MH_MAGIC)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check architecture (32-bit/x86) */
|
||||||
|
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For our purposes, this must be a dynamic library */
|
||||||
|
if (file->filetype != MH_DYLIB)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_count = file->ncmds;
|
||||||
|
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
|
||||||
|
|
||||||
|
/* Add up memory sizes of mapped segments */
|
||||||
|
for (uint32_t i = 0; i < cmd_count; i++)
|
||||||
|
{
|
||||||
|
if (seg->cmd == LC_SEGMENT)
|
||||||
|
{
|
||||||
|
lib.memorySize += seg->vmsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2011 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@@ -25,34 +25,64 @@
|
|||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||||
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||||
|
|
||||||
|
#include "common_logic.h"
|
||||||
#include <IMemoryUtils.h>
|
#include <IMemoryUtils.h>
|
||||||
#include "sm_globals.h"
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
|
#include <sh_vector.h>
|
||||||
|
#include "sm_symtable.h"
|
||||||
|
|
||||||
|
using namespace SourceHook;
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
|
#ifdef PLATFORM_APPLE
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct DynLibInfo
|
struct DynLibInfo
|
||||||
{
|
{
|
||||||
void *baseAddress;
|
void *baseAddress;
|
||||||
size_t memorySize;
|
size_t memorySize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
|
struct LibSymbolTable
|
||||||
|
{
|
||||||
|
SymbolTable table;
|
||||||
|
uintptr_t lib_base;
|
||||||
|
uint32_t last_pos;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class MemoryUtils :
|
class MemoryUtils :
|
||||||
public IMemoryUtils,
|
public IMemoryUtils,
|
||||||
public SMGlobalClass
|
public SMGlobalClass
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
MemoryUtils();
|
||||||
|
~MemoryUtils();
|
||||||
public: // SMGlobalClass
|
public: // SMGlobalClass
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
public: // IMemoryUtils
|
public: // IMemoryUtils
|
||||||
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||||
private:
|
void *ResolveSymbol(void *handle, const char *symbol);
|
||||||
|
public:
|
||||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||||
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
|
private:
|
||||||
|
CVector<LibSymbolTable *> m_SymTables;
|
||||||
|
#ifdef PLATFORM_APPLE
|
||||||
|
struct dyld_all_image_infos *m_ImageList;
|
||||||
|
SInt32 m_OSXMajor;
|
||||||
|
SInt32 m_OSXMinor;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MemoryUtils g_MemUtils;
|
extern MemoryUtils g_MemUtils;
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
// MersenneTwister.h
|
||||||
|
// Mersenne Twister random number generator -- a C++ class MTRand
|
||||||
|
// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
|
||||||
|
// Richard J. Wagner v1.0 15 May 2003 [email protected]
|
||||||
|
|
||||||
|
// The Mersenne Twister is an algorithm for generating random numbers. It
|
||||||
|
// was designed with consideration of the flaws in various other generators.
|
||||||
|
// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
|
||||||
|
// are far greater. The generator is also fast; it avoids multiplication and
|
||||||
|
// division, and it benefits from caches and pipelines. For more information
|
||||||
|
// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
|
||||||
|
|
||||||
|
// Reference
|
||||||
|
// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
|
||||||
|
// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
|
||||||
|
// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
|
||||||
|
|
||||||
|
// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||||
|
// Copyright (C) 2000 - 2003, Richard J. Wagner
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions
|
||||||
|
// are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. The names of its contributors may not be used to endorse or promote
|
||||||
|
// products derived from this software without specific prior written
|
||||||
|
// permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// The original code included the following notice:
|
||||||
|
//
|
||||||
|
// When you use this, send an email to: [email protected]
|
||||||
|
// with an appropriate reference to your work.
|
||||||
|
//
|
||||||
|
// It would be nice to CC: [email protected] and [email protected]
|
||||||
|
// when you write.
|
||||||
|
|
||||||
|
#ifndef MERSENNETWISTER_H
|
||||||
|
#define MERSENNETWISTER_H
|
||||||
|
|
||||||
|
// Not thread safe (unless auto-initialization is avoided and each thread has
|
||||||
|
// its own MTRand object)
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
class MTRand {
|
||||||
|
// Data
|
||||||
|
public:
|
||||||
|
typedef unsigned long uint32; // unsigned integer type, at least 32 bits
|
||||||
|
|
||||||
|
enum { N = 624 }; // length of state vector
|
||||||
|
enum { SAVE = N + 1 }; // length of array for save()
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum { M = 397 }; // period parameter
|
||||||
|
|
||||||
|
uint32 state[N]; // internal state
|
||||||
|
uint32 *pNext; // next value to get from state
|
||||||
|
int left; // number of values left before reload needed
|
||||||
|
|
||||||
|
|
||||||
|
//Methods
|
||||||
|
public:
|
||||||
|
MTRand( const uint32& oneSeed ); // initialize with a simple uint32
|
||||||
|
MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array
|
||||||
|
MTRand(); // auto-initialize with /dev/urandom or time() and clock()
|
||||||
|
|
||||||
|
// Do NOT use for CRYPTOGRAPHY without securely hashing several returned
|
||||||
|
// values together, otherwise the generator state can be learned after
|
||||||
|
// reading 624 consecutive values.
|
||||||
|
|
||||||
|
// Access to 32-bit random numbers
|
||||||
|
double rand(); // real number in [0,1]
|
||||||
|
double rand( const double& n ); // real number in [0,n]
|
||||||
|
double randExc(); // real number in [0,1)
|
||||||
|
double randExc( const double& n ); // real number in [0,n)
|
||||||
|
double randDblExc(); // real number in (0,1)
|
||||||
|
double randDblExc( const double& n ); // real number in (0,n)
|
||||||
|
uint32 randInt(); // integer in [0,2^32-1]
|
||||||
|
uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32
|
||||||
|
double operator()() { return rand(); } // same as rand()
|
||||||
|
|
||||||
|
// Access to 53-bit random numbers (capacity of IEEE double precision)
|
||||||
|
double rand53(); // real number in [0,1)
|
||||||
|
|
||||||
|
// Access to nonuniform random number distributions
|
||||||
|
double randNorm( const double& mean = 0.0, const double& variance = 0.0 );
|
||||||
|
|
||||||
|
// Re-seeding functions with same behavior as initializers
|
||||||
|
void seed( const uint32 oneSeed );
|
||||||
|
void seed( uint32 *const bigSeed, const uint32 seedLength = N );
|
||||||
|
void seed();
|
||||||
|
|
||||||
|
// Saving and loading generator state
|
||||||
|
void save( uint32* saveArray ) const; // to array of size SAVE
|
||||||
|
void load( uint32 *const loadArray ); // from such array
|
||||||
|
protected:
|
||||||
|
void initialize( const uint32 oneSeed );
|
||||||
|
void reload();
|
||||||
|
uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
|
||||||
|
uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
|
||||||
|
uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
|
||||||
|
uint32 mixBits( const uint32& u, const uint32& v ) const
|
||||||
|
{ return hiBit(u) | loBits(v); }
|
||||||
|
uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
|
||||||
|
{ return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); }
|
||||||
|
static uint32 hash( time_t t, clock_t c );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline MTRand::MTRand( const uint32& oneSeed )
|
||||||
|
{ seed(oneSeed); }
|
||||||
|
|
||||||
|
inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
|
||||||
|
{ seed(bigSeed,seedLength); }
|
||||||
|
|
||||||
|
inline MTRand::MTRand()
|
||||||
|
{ seed(); }
|
||||||
|
|
||||||
|
inline double MTRand::rand()
|
||||||
|
{ return double(randInt()) * (1.0/4294967295.0); }
|
||||||
|
|
||||||
|
inline double MTRand::rand( const double& n )
|
||||||
|
{ return rand() * n; }
|
||||||
|
|
||||||
|
inline double MTRand::randExc()
|
||||||
|
{ return double(randInt()) * (1.0/4294967296.0); }
|
||||||
|
|
||||||
|
inline double MTRand::randExc( const double& n )
|
||||||
|
{ return randExc() * n; }
|
||||||
|
|
||||||
|
inline double MTRand::randDblExc()
|
||||||
|
{ return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
|
||||||
|
|
||||||
|
inline double MTRand::randDblExc( const double& n )
|
||||||
|
{ return randDblExc() * n; }
|
||||||
|
|
||||||
|
inline double MTRand::rand53()
|
||||||
|
{
|
||||||
|
uint32 a = randInt() >> 5, b = randInt() >> 6;
|
||||||
|
return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double MTRand::randNorm( const double& mean, const double& variance )
|
||||||
|
{
|
||||||
|
// Return a real number from a normal (Gaussian) distribution with given
|
||||||
|
// mean and variance by Box-Muller method
|
||||||
|
double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
|
||||||
|
double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
|
||||||
|
return mean + r * cos(phi);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MTRand::uint32 MTRand::randInt()
|
||||||
|
{
|
||||||
|
// Pull a 32-bit integer from the generator state
|
||||||
|
// Every other access function simply transforms the numbers extracted here
|
||||||
|
|
||||||
|
if( left == 0 ) reload();
|
||||||
|
--left;
|
||||||
|
|
||||||
|
register uint32 s1;
|
||||||
|
s1 = *pNext++;
|
||||||
|
s1 ^= (s1 >> 11);
|
||||||
|
s1 ^= (s1 << 7) & 0x9d2c5680UL;
|
||||||
|
s1 ^= (s1 << 15) & 0xefc60000UL;
|
||||||
|
return ( s1 ^ (s1 >> 18) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MTRand::uint32 MTRand::randInt( const uint32& n )
|
||||||
|
{
|
||||||
|
// Find which bits are used in n
|
||||||
|
// Optimized by Magnus Jonsson ([email protected])
|
||||||
|
uint32 used = n;
|
||||||
|
used |= used >> 1;
|
||||||
|
used |= used >> 2;
|
||||||
|
used |= used >> 4;
|
||||||
|
used |= used >> 8;
|
||||||
|
used |= used >> 16;
|
||||||
|
|
||||||
|
// Draw numbers until one is found in [0,n]
|
||||||
|
uint32 i;
|
||||||
|
do
|
||||||
|
i = randInt() & used; // toss unused bits to shorten search
|
||||||
|
while( i > n );
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::seed( const uint32 oneSeed )
|
||||||
|
{
|
||||||
|
// Seed the generator with a simple uint32
|
||||||
|
initialize(oneSeed);
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
|
||||||
|
{
|
||||||
|
// Seed the generator with an array of uint32's
|
||||||
|
// There are 2^19937-1 possible initial states. This function allows
|
||||||
|
// all of those to be accessed by providing at least 19937 bits (with a
|
||||||
|
// default seed length of N = 624 uint32's). Any bits above the lower 32
|
||||||
|
// in each element are discarded.
|
||||||
|
// Just call seed() if you want to get array from /dev/urandom
|
||||||
|
initialize(19650218UL);
|
||||||
|
register int i = 1;
|
||||||
|
register uint32 j = 0;
|
||||||
|
register int k = ( N > seedLength ? N : seedLength );
|
||||||
|
for( ; k; --k )
|
||||||
|
{
|
||||||
|
state[i] =
|
||||||
|
state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
|
||||||
|
state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
|
||||||
|
state[i] &= 0xffffffffUL;
|
||||||
|
++i; ++j;
|
||||||
|
if( i >= N ) { state[0] = state[N-1]; i = 1; }
|
||||||
|
if( j >= seedLength ) j = 0;
|
||||||
|
}
|
||||||
|
for( k = N - 1; k; --k )
|
||||||
|
{
|
||||||
|
state[i] =
|
||||||
|
state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
|
||||||
|
state[i] -= i;
|
||||||
|
state[i] &= 0xffffffffUL;
|
||||||
|
++i;
|
||||||
|
if( i >= N ) { state[0] = state[N-1]; i = 1; }
|
||||||
|
}
|
||||||
|
state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::seed()
|
||||||
|
{
|
||||||
|
// Seed the generator with an array from /dev/urandom if available
|
||||||
|
// Otherwise use a hash of time() and clock() values
|
||||||
|
|
||||||
|
// First try getting an array from /dev/urandom
|
||||||
|
FILE* urandom = fopen( "/dev/urandom", "rb" );
|
||||||
|
if( urandom )
|
||||||
|
{
|
||||||
|
uint32 bigSeed[N];
|
||||||
|
register uint32 *s = bigSeed;
|
||||||
|
register int i = N;
|
||||||
|
register bool success = true;
|
||||||
|
while( success && i-- )
|
||||||
|
success = fread( s++, sizeof(uint32), 1, urandom );
|
||||||
|
fclose(urandom);
|
||||||
|
if( success ) { seed( bigSeed, N ); return; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Was not successful, so use time() and clock() instead
|
||||||
|
seed( hash( time(NULL), clock() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::initialize( const uint32 seed )
|
||||||
|
{
|
||||||
|
// Initialize generator state with seed
|
||||||
|
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
|
||||||
|
// In previous versions, most significant bits (MSBs) of the seed affect
|
||||||
|
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
|
||||||
|
register uint32 *s = state;
|
||||||
|
register uint32 *r = state;
|
||||||
|
register int i = 1;
|
||||||
|
*s++ = seed & 0xffffffffUL;
|
||||||
|
for( ; i < N; ++i )
|
||||||
|
{
|
||||||
|
*s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::reload()
|
||||||
|
{
|
||||||
|
// Generate N new values in state
|
||||||
|
// Made clearer and faster by Matthew Bellew ([email protected])
|
||||||
|
register uint32 *p = state;
|
||||||
|
register int i;
|
||||||
|
for( i = N - M; i--; ++p )
|
||||||
|
*p = twist( p[M], p[0], p[1] );
|
||||||
|
for( i = M; --i; ++p )
|
||||||
|
*p = twist( p[M-N], p[0], p[1] );
|
||||||
|
*p = twist( p[M-N], p[0], state[0] );
|
||||||
|
|
||||||
|
left = N, pNext = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
|
||||||
|
{
|
||||||
|
// Get a uint32 from t and c
|
||||||
|
// Better than uint32(x) in case x is floating point in [0,1]
|
||||||
|
// Based on code by Lawrence Kirby ([email protected])
|
||||||
|
|
||||||
|
static uint32 differ = 0; // guarantee time-based seeds will change
|
||||||
|
|
||||||
|
uint32 h1 = 0;
|
||||||
|
unsigned char *p = (unsigned char *) &t;
|
||||||
|
for( size_t i = 0; i < sizeof(t); ++i )
|
||||||
|
{
|
||||||
|
h1 *= UCHAR_MAX + 2U;
|
||||||
|
h1 += p[i];
|
||||||
|
}
|
||||||
|
uint32 h2 = 0;
|
||||||
|
p = (unsigned char *) &c;
|
||||||
|
for( size_t j = 0; j < sizeof(c); ++j )
|
||||||
|
{
|
||||||
|
h2 *= UCHAR_MAX + 2U;
|
||||||
|
h2 += p[j];
|
||||||
|
}
|
||||||
|
return ( h1 + differ++ ) ^ h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::save( uint32* saveArray ) const
|
||||||
|
{
|
||||||
|
register uint32 *sa = saveArray;
|
||||||
|
register const uint32 *s = state;
|
||||||
|
register int i = N;
|
||||||
|
for( ; i--; *sa++ = *s++ ) {}
|
||||||
|
*sa = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void MTRand::load( uint32 *const loadArray )
|
||||||
|
{
|
||||||
|
register uint32 *s = state;
|
||||||
|
register uint32 *la = loadArray;
|
||||||
|
register int i = N;
|
||||||
|
for( ; i--; *s++ = *la++ ) {}
|
||||||
|
left = *la;
|
||||||
|
pNext = &state[N-left];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MERSENNETWISTER_H
|
||||||
|
|
||||||
|
// Change log:
|
||||||
|
//
|
||||||
|
// v0.1 - First release on 15 May 2000
|
||||||
|
// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
|
||||||
|
// - Translated from C to C++
|
||||||
|
// - Made completely ANSI compliant
|
||||||
|
// - Designed convenient interface for initialization, seeding, and
|
||||||
|
// obtaining numbers in default or user-defined ranges
|
||||||
|
// - Added automatic seeding from /dev/urandom or time() and clock()
|
||||||
|
// - Provided functions for saving and loading generator state
|
||||||
|
//
|
||||||
|
// v0.2 - Fixed bug which reloaded generator one step too late
|
||||||
|
//
|
||||||
|
// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
|
||||||
|
//
|
||||||
|
// v0.4 - Removed trailing newline in saved generator format to be consistent
|
||||||
|
// with output format of built-in types
|
||||||
|
//
|
||||||
|
// v0.5 - Improved portability by replacing static const int's with enum's and
|
||||||
|
// clarifying return values in seed(); suggested by Eric Heimburg
|
||||||
|
// - Removed MAXINT constant; use 0xffffffffUL instead
|
||||||
|
//
|
||||||
|
// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
|
||||||
|
// - Changed integer [0,n] generator to give better uniformity
|
||||||
|
//
|
||||||
|
// v0.7 - Fixed operator precedence ambiguity in reload()
|
||||||
|
// - Added access for real numbers in (0,1) and (0,n)
|
||||||
|
//
|
||||||
|
// v0.8 - Included time.h header to properly support time_t and clock_t
|
||||||
|
//
|
||||||
|
// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
|
||||||
|
// - Allowed for seeding with arrays of any length
|
||||||
|
// - Added access for real numbers in [0,1) with 53-bit resolution
|
||||||
|
// - Added access for real numbers from normal (Gaussian) distributions
|
||||||
|
// - Increased overall speed by optimizing twist()
|
||||||
|
// - Doubled speed of integer [0,n] generation
|
||||||
|
// - Fixed out-of-range number generation on 64-bit machines
|
||||||
|
// - Improved portability by substituting literal constants for long enum's
|
||||||
|
// - Changed license from GNU LGPL to BSD
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* 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_native_h_
|
||||||
|
#define _include_sourcemod_native_h_
|
||||||
|
|
||||||
|
#include <IShareSys.h>
|
||||||
|
#include <IHandleSys.h>
|
||||||
|
#include <am-string.h>
|
||||||
|
#include <am-utility.h>
|
||||||
|
#include <am-refcounting.h>
|
||||||
|
#include "common_logic.h"
|
||||||
|
|
||||||
|
struct FakeNative
|
||||||
|
{
|
||||||
|
FakeNative(const char *name, IPluginFunction *fun)
|
||||||
|
: name(name),
|
||||||
|
ctx(fun->GetParentContext()),
|
||||||
|
call(fun),
|
||||||
|
gate(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~FakeNative();
|
||||||
|
|
||||||
|
ke::AString name;
|
||||||
|
IPluginContext *ctx;
|
||||||
|
IPluginFunction *call;
|
||||||
|
SPVM_NATIVE_FUNC gate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Native : public ke::Refcounted<Native>
|
||||||
|
{
|
||||||
|
Native(CNativeOwner *owner, const sp_nativeinfo_t *native)
|
||||||
|
: owner(owner),
|
||||||
|
native(native),
|
||||||
|
fake(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Native(CNativeOwner *owner, FakeNative *fake)
|
||||||
|
: owner(owner),
|
||||||
|
native(NULL),
|
||||||
|
fake(fake)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CNativeOwner *owner;
|
||||||
|
const sp_nativeinfo_t *native;
|
||||||
|
ke::AutoPtr<FakeNative> fake;
|
||||||
|
|
||||||
|
SPVM_NATIVE_FUNC func() const
|
||||||
|
{
|
||||||
|
if (native)
|
||||||
|
return native->func;
|
||||||
|
return fake->gate;
|
||||||
|
}
|
||||||
|
const char *name() const
|
||||||
|
{
|
||||||
|
if (native)
|
||||||
|
return native->name;
|
||||||
|
return fake->name.chars();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool matches(const char *name, const ke::Ref<Native> &entry)
|
||||||
|
{
|
||||||
|
return strcmp(name, entry->name()) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _include_sourcemod_native_h_
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourcePawn
|
* SourcePawn
|
||||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
@@ -54,7 +54,7 @@ unsigned int NativeInterface::GetInterfaceVersion()
|
|||||||
|
|
||||||
void NativeInterface::OnSourceModAllInitialized()
|
void NativeInterface::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_ShareSys.AddInterface(NULL, &g_NInvoke);
|
sharesys->AddInterface(NULL, &g_NInvoke);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
|
IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
|
||||||
@@ -69,30 +69,15 @@ INativeInvoker *NativeInterface::CreateInvoker()
|
|||||||
|
|
||||||
bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
|
bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
|
||||||
{
|
{
|
||||||
NativeEntry *entry;
|
ke::Ref<Native> entry = g_ShareSys.FindNative(name);
|
||||||
|
if (!entry)
|
||||||
entry = g_ShareSys.FindNative(name);
|
|
||||||
if (entry == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
native = NULL;
|
if (!entry->owner)
|
||||||
if (entry->replacement.owner != NULL)
|
|
||||||
{
|
|
||||||
native = entry->replacement.func;
|
|
||||||
}
|
|
||||||
else if (entry->owner != NULL)
|
|
||||||
{
|
|
||||||
native = entry->func;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (native == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
this->pContext = pContext;
|
native_ = entry->func();
|
||||||
|
context_ = pContext;
|
||||||
|
|
||||||
m_curparam = 0;
|
m_curparam = 0;
|
||||||
m_errorstate = SP_ERROR_NONE;
|
m_errorstate = SP_ERROR_NONE;
|
||||||
@@ -184,15 +169,13 @@ int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, s
|
|||||||
|
|
||||||
void NativeInvoker::Cancel()
|
void NativeInvoker::Cancel()
|
||||||
{
|
{
|
||||||
if (pContext == NULL)
|
if (context_ == NULL)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
m_errorstate = SP_ERROR_NONE;
|
m_errorstate = SP_ERROR_NONE;
|
||||||
m_curparam = 0;
|
m_curparam = 0;
|
||||||
pContext = NULL;
|
context_ = NULL;
|
||||||
native = NULL;
|
native_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NativeInvoker::SetError(int err)
|
int NativeInvoker::SetError(int err)
|
||||||
@@ -205,10 +188,8 @@ int NativeInvoker::Invoke(cell_t *result)
|
|||||||
{
|
{
|
||||||
int err = SP_ERROR_NONE;
|
int err = SP_ERROR_NONE;
|
||||||
|
|
||||||
if (pContext == NULL)
|
if (context_ == NULL)
|
||||||
{
|
|
||||||
return SP_ERROR_INVALID_NATIVE;
|
return SP_ERROR_INVALID_NATIVE;
|
||||||
}
|
|
||||||
|
|
||||||
if (m_errorstate != SP_ERROR_NONE)
|
if (m_errorstate != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
@@ -225,7 +206,7 @@ int NativeInvoker::Invoke(cell_t *result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//This is for re-entrancy!
|
//This is for re-entrancy!
|
||||||
IPluginContext *ctx = pContext;
|
IPluginContext *ctx = context_;
|
||||||
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
|
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
|
||||||
cell_t *temp_params = &_temp_params[1];
|
cell_t *temp_params = &_temp_params[1];
|
||||||
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||||
@@ -239,7 +220,7 @@ int NativeInvoker::Invoke(cell_t *result)
|
|||||||
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
||||||
}
|
}
|
||||||
m_curparam = 0;
|
m_curparam = 0;
|
||||||
pContext = NULL;
|
context_ = NULL;
|
||||||
|
|
||||||
/* Initialize 0th parameter */
|
/* Initialize 0th parameter */
|
||||||
_temp_params[0] = numparams;
|
_temp_params[0] = numparams;
|
||||||
@@ -324,7 +305,7 @@ int NativeInvoker::Invoke(cell_t *result)
|
|||||||
/* Make the call if we can */
|
/* Make the call if we can */
|
||||||
if (err == SP_ERROR_NONE)
|
if (err == SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
*result = native(ctx, _temp_params);
|
*result = native_(ctx, _temp_params);
|
||||||
if (ctx->GetLastNativeError() != SP_ERROR_NONE)
|
if (ctx->GetLastNativeError() != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
docopies = false;
|
docopies = false;
|
||||||
@@ -32,8 +32,12 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||||
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||||
|
|
||||||
#include "sm_globals.h"
|
#include <sp_vm_api.h>
|
||||||
#include <INativeInvoker.h>
|
#include <INativeInvoker.h>
|
||||||
|
#include "common_logic.h"
|
||||||
|
|
||||||
|
using namespace SourceMod;
|
||||||
|
using namespace SourcePawn;
|
||||||
|
|
||||||
struct ParamInfo
|
struct ParamInfo
|
||||||
{
|
{
|
||||||
@@ -71,8 +75,8 @@ private:
|
|||||||
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
||||||
int SetError(int err);
|
int SetError(int err);
|
||||||
private:
|
private:
|
||||||
IPluginContext *pContext;
|
IPluginContext *context_;
|
||||||
SPVM_NATIVE_FUNC native;
|
SPVM_NATIVE_FUNC native_;
|
||||||
cell_t m_params[SP_MAX_EXEC_PARAMS];
|
cell_t m_params[SP_MAX_EXEC_PARAMS];
|
||||||
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
|
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
|
||||||
unsigned int m_curparam;
|
unsigned int m_curparam;
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* 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 "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)
|
||||||
|
{
|
||||||
|
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
||||||
|
g_ShareSys.AddNativeToCache(this, native);
|
||||||
|
|
||||||
|
m_natives.append(natives);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNativeOwner::PropagateMarkSerial(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)
|
||||||
|
{
|
||||||
|
native->status = SP_NATIVE_UNBOUND;
|
||||||
|
native->pfn = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNativeOwner::DropEverything()
|
||||||
|
{
|
||||||
|
List<WeakNative>::iterator 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strip all of our natives from the cache */
|
||||||
|
for (size_t i = 0; i < m_natives.length(); i++) {
|
||||||
|
const sp_nativeinfo_t *natives = m_natives[i];
|
||||||
|
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
||||||
|
g_ShareSys.ClearNativeFromCache(this, native->name);
|
||||||
|
}
|
||||||
|
m_natives.clear();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_fakes.length(); i++)
|
||||||
|
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
|
||||||
|
m_fakes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* 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$
|
||||||
|
*/
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
|
||||||
|
|
||||||
|
#include <sp_vm_types.h>
|
||||||
|
#include <sh_list.h>
|
||||||
|
#include <am-linkedlist.h>
|
||||||
|
#include <am-vector.h>
|
||||||
|
#include "common_logic.h"
|
||||||
|
#include "Native.h"
|
||||||
|
|
||||||
|
struct Native;
|
||||||
|
class CPlugin;
|
||||||
|
|
||||||
|
using namespace SourceMod;
|
||||||
|
|
||||||
|
struct WeakNative
|
||||||
|
{
|
||||||
|
WeakNative(IPlugin *plugin, uint32_t index) :
|
||||||
|
pl(plugin), idx(index)
|
||||||
|
{
|
||||||
|
pl = plugin;
|
||||||
|
idx = index;
|
||||||
|
}
|
||||||
|
IPlugin *pl;
|
||||||
|
uint32_t idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 PropagateMarkSerial(unsigned int serial);
|
||||||
|
public:
|
||||||
|
void AddDependent(CPlugin *pPlugin);
|
||||||
|
void AddWeakRef(const WeakNative & ref);
|
||||||
|
void DropRefsTo(CPlugin *pPlugin);
|
||||||
|
private:
|
||||||
|
void DropWeakRefsTo(CPlugin *pPlugin);
|
||||||
|
void UnbindWeakRef(const WeakNative & ref);
|
||||||
|
protected:
|
||||||
|
List<CPlugin *> m_Dependents;
|
||||||
|
unsigned int m_nMarkSerial;
|
||||||
|
List<WeakNative> m_WeakRefs;
|
||||||
|
ke::Vector<const sp_nativeinfo_t *> m_natives;
|
||||||
|
ke::Vector<ke::Ref<Native> > m_fakes;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CNativeOwner g_CoreNatives;
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_NATIVE_OWNER_H_
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "common_logic.h"
|
||||||
#include "PhraseCollection.h"
|
#include "PhraseCollection.h"
|
||||||
#include "Translator.h"
|
#include "Translator.h"
|
||||||
#include "sm_stringutil.h"
|
|
||||||
|
|
||||||
CPhraseCollection::CPhraseCollection()
|
CPhraseCollection::CPhraseCollection()
|
||||||
{
|
{
|
||||||
@@ -54,7 +54,7 @@ IPhraseFile *CPhraseCollection::AddPhraseFile(const char *filename)
|
|||||||
char full_name[PLATFORM_MAX_PATH];
|
char full_name[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
/* No compat shim here. The user should have read the doc. */
|
/* No compat shim here. The user should have read the doc. */
|
||||||
UTIL_Format(full_name, sizeof(full_name), "%s.txt", filename);
|
smcore.Format(full_name, sizeof(full_name), "%s.txt", filename);
|
||||||
|
|
||||||
fid = g_Translator.FindOrAddPhraseFile(full_name);
|
fid = g_Translator.FindOrAddPhraseFile(full_name);
|
||||||
pFile = g_Translator.GetFileByIndex(fid);
|
pFile = g_Translator.GetFileByIndex(fid);
|
||||||
@@ -113,7 +113,7 @@ bool CPhraseCollection::FormatString(char *buffer,
|
|||||||
unsigned int arg;
|
unsigned int arg;
|
||||||
|
|
||||||
arg = 0;
|
arg = 0;
|
||||||
if (!gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase))
|
if (!smcore.gnprintf(buffer, maxlength, format, this, params, numparams, arg, pOutLength, pFailPhrase))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
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