Compare commits
703 Commits
1.10-fork
...
master-reb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
313c555e2e | ||
|
|
e5fed0051b | ||
|
|
c2a86c77fd | ||
|
|
8c534e770b | ||
|
|
2c86e8099a | ||
|
|
03eeb23ab3 | ||
|
|
a9c85d8842 | ||
|
|
850ee60a18 | ||
|
|
7cd130904b | ||
|
|
19019d3a4b | ||
|
|
b31375f087 | ||
|
|
1d999c3984 | ||
|
|
fdcbdb6918 | ||
|
|
d42a8c7c1e | ||
|
|
11d3cf94f7 | ||
|
|
0e4b1ca4cf | ||
|
|
1bcc5b8a44 | ||
|
|
7df2f8e045 | ||
|
|
9f3584a056 | ||
|
|
4e73713fab | ||
|
|
e07c120cab | ||
|
|
e3734803f0 | ||
|
|
7c757ac119 | ||
|
|
c5425def7f | ||
|
|
e60c672485 | ||
|
|
908ffdb523 | ||
|
|
d56dc62e03 | ||
|
|
f08f1ef0d6 | ||
|
|
5cb2d68fd7 | ||
|
|
96d0959db1 | ||
|
|
5a6b2c8ebf | ||
|
|
343f64f6b7 | ||
|
|
f9ad35badf | ||
|
|
60b6a8dfb0 | ||
|
|
00f3970036 | ||
|
|
7d78c141e7 | ||
|
|
123ad7aab1 | ||
|
|
ee51162c3f | ||
|
|
af93d819c6 | ||
|
|
d426d1f04f | ||
|
|
6cac489fce | ||
|
|
5c507cc35c | ||
|
|
dbec0b165c | ||
|
|
4e8b66bf99 | ||
|
|
8dcbe14ea0 | ||
|
|
06dcb991e8 | ||
|
|
e262064fd8 | ||
|
|
a80b9c5c0f | ||
|
|
638aae0040 | ||
|
|
35ac74c7a7 | ||
|
|
7bb9da2a26 | ||
|
|
b5b9b8388c | ||
|
|
e7e92d4e40 | ||
|
|
33e869a4e5 | ||
|
|
0bc9aa46e6 | ||
|
|
80ad76a563 | ||
|
|
7e29f22f8f | ||
|
|
a9eb3a0d45 | ||
|
|
ab6b45b81c | ||
|
|
385eae892c | ||
|
|
5f309f45f8 | ||
|
|
a2e5e2a442 | ||
|
|
b42e5ac922 | ||
|
|
544204654d | ||
|
|
5c971fd51b | ||
|
|
6507d947cc | ||
|
|
30415e299e | ||
|
|
8eeea2aba1 | ||
|
|
bb1431cd3b | ||
|
|
a2aec9b42e | ||
|
|
ef74b51c8b | ||
|
|
e74aa099bc | ||
|
|
8140cb2d6b | ||
|
|
d981e252d2 | ||
|
|
e6a04abc9e | ||
|
|
c90477a720 | ||
|
|
11c8084ccd | ||
|
|
7747beb4cf | ||
|
|
9fa7421122 | ||
|
|
f2ca671d1f | ||
|
|
d4da21b07f | ||
|
|
4b2d8b53fa | ||
|
|
7bfd5e521e | ||
|
|
060c832f89 | ||
|
|
8c9fd3746b | ||
|
|
314184beea | ||
|
|
17462cbe5a | ||
|
|
ae4e043c3e | ||
|
|
6def79ff23 | ||
|
|
1ba7024a3a | ||
|
|
44aaaf8b10 | ||
|
|
62754333cd | ||
|
|
8938a29904 | ||
|
|
2c6ef5825f | ||
|
|
b090aa36bf | ||
|
|
cb1dae5aab | ||
|
|
c9e824632f | ||
|
|
0436fb0ab3 | ||
|
|
767c5cf468 | ||
|
|
f01ad5317a | ||
|
|
fac3138ff5 | ||
|
|
ab9e86910c | ||
|
|
e88e9342ef | ||
|
|
e3a01b0e1a | ||
|
|
07d928dbad | ||
|
|
a402b3cceb | ||
|
|
99dbe06d8a | ||
|
|
29694ec13b | ||
|
|
1e8db957bf | ||
|
|
0656696251 | ||
|
|
af04c964fe | ||
|
|
bc81361319 | ||
|
|
853bcf703a | ||
|
|
c81248004a | ||
|
|
79787cb868 | ||
|
|
20aae06f12 | ||
|
|
a20eb08dc6 | ||
|
|
8d60a46358 | ||
|
|
4c376cbcb7 | ||
|
|
d83c498a8f | ||
|
|
531b053096 | ||
|
|
0dafe04899 | ||
|
|
7170a8f11c | ||
|
|
2ef874dbc9 | ||
|
|
cb8541548b | ||
|
|
46e3de8d24 | ||
|
|
5addaffa56 | ||
|
|
f40ae82df4 | ||
|
|
6ebf04b75d | ||
|
|
e93dd7af3f | ||
|
|
4dc2383fe3 | ||
|
|
5f827089d3 | ||
|
|
8a7f8c5cbd | ||
|
|
dae8aba554 | ||
|
|
b9029dedff | ||
|
|
1a375bcc17 | ||
|
|
eaccec3e4a | ||
|
|
5fff988a8f | ||
|
|
1a1bb54c4f | ||
|
|
97f2fc9d7f | ||
|
|
2e1235a585 | ||
|
|
426c1a090f | ||
|
|
50b4ad4e11 | ||
|
|
a330d0a1bf | ||
|
|
4e6774befb | ||
|
|
b1b993989a | ||
|
|
2e59202ea4 | ||
|
|
4a6d29c9e2 | ||
|
|
e746fdf1fb | ||
|
|
cac7793f15 | ||
|
|
e0c95674c8 | ||
|
|
bc42cef765 | ||
|
|
680a198fa2 | ||
|
|
38f7be7664 | ||
|
|
94f5b5d06c | ||
|
|
f66a904c31 | ||
|
|
8e0039aaec | ||
|
|
dd1e5997f3 | ||
|
|
bc6e920213 | ||
|
|
a28c3cac9b | ||
|
|
6670b93cc6 | ||
|
|
8826663186 | ||
|
|
c5087d7a39 | ||
|
|
5ba9816377 | ||
|
|
4eecc80b9a | ||
|
|
008fbf78a5 | ||
|
|
48150e0c7a | ||
|
|
d8fd60b562 | ||
|
|
178658912e | ||
|
|
5539484f92 | ||
|
|
a9a1939f75 | ||
|
|
850f96b986 | ||
|
|
693e584dcd | ||
|
|
397b70add0 | ||
|
|
a0eb6a9550 | ||
|
|
6bd49ff415 | ||
|
|
43cdc65708 | ||
|
|
cd6886319c | ||
|
|
6e839a95c6 | ||
|
|
2dcee81f22 | ||
|
|
a253d35bcd | ||
|
|
02e9d214b4 | ||
|
|
30a2160839 | ||
|
|
d57d7e7401 | ||
|
|
1f5b735dbd | ||
|
|
d5a26adc49 | ||
|
|
221d34f809 | ||
|
|
8922ed0c5d | ||
|
|
27b1817b10 | ||
|
|
3a488f7041 | ||
|
|
8f7a1641fc | ||
|
|
b0799d3336 | ||
|
|
2130c60fd9 | ||
|
|
ecb707e38d | ||
|
|
7e94bfb307 | ||
|
|
51bba0b894 | ||
|
|
775d4f04f2 | ||
|
|
4320d7b17a | ||
|
|
174bf307a2 | ||
|
|
f8349e846a | ||
|
|
ef7d3abefd | ||
|
|
b77e8c50ac | ||
|
|
0d6179299c | ||
|
|
515df38b72 | ||
|
|
c5e69900f9 | ||
|
|
2d5bc4007f | ||
|
|
3a315e88c2 | ||
|
|
6c5a3fdaf2 | ||
|
|
02f188899e | ||
|
|
aab8c6ac9f | ||
|
|
5d391fda07 | ||
|
|
8538233985 | ||
|
|
3b4a343274 | ||
|
|
f90b7ade76 | ||
|
|
83a29cf82b | ||
|
|
89bd4d7329 | ||
|
|
ed662dc8cf | ||
|
|
6574dd8273 | ||
|
|
63f8ea89ca | ||
|
|
34c8220e5d | ||
|
|
3595525f12 | ||
|
|
4989666d72 | ||
|
|
f7fda0023c | ||
|
|
13be211e9a | ||
|
|
f6b39720ec | ||
|
|
764e38a58f | ||
|
|
e34e9b9869 | ||
|
|
721f348684 | ||
|
|
9ddcd335af | ||
|
|
eda9a42ee2 | ||
|
|
22a964d89a | ||
|
|
855ece1d3b | ||
|
|
568da23c96 | ||
|
|
4015f9c1c9 | ||
|
|
21740d9a26 | ||
|
|
05aa3fd39d | ||
|
|
3100e23b87 | ||
|
|
da3e868df5 | ||
|
|
63e0e2bc82 | ||
|
|
a35ecde538 | ||
|
|
81ad870def | ||
|
|
24f1c89b96 | ||
|
|
a761194917 | ||
|
|
9321229321 | ||
|
|
e5ebd65176 | ||
|
|
5f7b22d2a4 | ||
|
|
52da989762 | ||
|
|
625c7a98f2 | ||
|
|
278998f7d0 | ||
|
|
c29e185d2a | ||
|
|
5c66a78763 | ||
|
|
5e3a189642 | ||
|
|
7b89f5fab3 | ||
|
|
b0e7407552 | ||
|
|
407c24cb14 | ||
|
|
65cb76e2f6 | ||
|
|
678ad74bf4 | ||
|
|
12e20eecf7 | ||
|
|
a5ae01a2f4 | ||
|
|
614c7d8332 | ||
|
|
9121472061 | ||
|
|
54fd778830 | ||
|
|
37c2a83523 | ||
|
|
28a5d4b342 | ||
|
|
0dcfdf3d7e | ||
|
|
0f7f9dad97 | ||
|
|
4276301499 | ||
|
|
d41ffaad7e | ||
|
|
5c0ae11a46 | ||
|
|
7424deefb9 | ||
|
|
c92354debb | ||
|
|
50eca8e60c | ||
|
|
c570150318 | ||
|
|
3bafc1e2f4 | ||
|
|
e28bf30b7d | ||
|
|
7becdc48d3 | ||
|
|
7a3d4e70bf | ||
|
|
6e73aba250 | ||
|
|
5797411b2b | ||
|
|
d2c4257c36 | ||
|
|
b057580a62 | ||
|
|
a1ad9e1acf | ||
|
|
a877a4475b | ||
|
|
441259e36a | ||
|
|
ab8bbbd118 | ||
|
|
39d604ae6c | ||
|
|
a7cb35c2af | ||
|
|
ff558b32e5 | ||
|
|
6b588fff61 | ||
|
|
3f3f1b8914 | ||
|
|
05e48ef866 | ||
|
|
6e1f095186 | ||
|
|
852703ccca | ||
|
|
01203a5a44 | ||
|
|
96ae65a96c | ||
|
|
9df93b0708 | ||
|
|
f307e44b79 | ||
|
|
dc8a22a76a | ||
|
|
8579e873ca | ||
|
|
addfb3c8a1 | ||
|
|
358bcca3a2 | ||
|
|
b209279589 | ||
|
|
5479084039 | ||
|
|
95ab60c4eb | ||
|
|
2111e90540 | ||
|
|
dc9c52bfd6 | ||
|
|
f5461df28c | ||
|
|
e5afdb4181 | ||
|
|
250dc1b206 | ||
|
|
f5f26e2dfe | ||
|
|
f7c54e9027 | ||
|
|
1ce828b6c8 | ||
|
|
c471e41dc7 | ||
|
|
afc9310704 | ||
|
|
bf898dd45f | ||
|
|
7d6eb2bd81 | ||
|
|
547ac5b026 | ||
|
|
7328ce657b | ||
|
|
14c9ac8fdb | ||
|
|
93cd78a6c5 | ||
|
|
b62f332611 | ||
|
|
47f135534d | ||
|
|
bb095097a2 | ||
|
|
c873e1aafb | ||
|
|
455bb14589 | ||
|
|
e786ff54f7 | ||
|
|
af3c10b173 | ||
|
|
351ac171d2 | ||
|
|
96c74651db | ||
|
|
329d587214 | ||
|
|
4e3df76358 | ||
|
|
161084e6f8 | ||
|
|
b38c9824fe | ||
|
|
4e4c2a7bb0 | ||
|
|
1c30b88069 | ||
|
|
31f6c0cb18 | ||
|
|
9cb693d8a3 | ||
|
|
896e92264f | ||
|
|
f32b210ec9 | ||
|
|
8f7ecf66a4 | ||
|
|
581068c09b | ||
|
|
0f5f1a814e | ||
|
|
18f9d65938 | ||
|
|
589fc96bc9 | ||
|
|
5787fca029 | ||
|
|
09ea982bbd | ||
|
|
e3569edb65 | ||
|
|
3db7116620 | ||
|
|
83672a6ce0 | ||
|
|
90fec5c6df | ||
|
|
257535daf2 | ||
|
|
eb0878be2b | ||
|
|
f229badbfc | ||
|
|
9a6866d14a | ||
|
|
8991b557ab | ||
|
|
be60a55aa3 | ||
|
|
10795fbed5 | ||
|
|
9d7e720f33 | ||
|
|
7605940994 | ||
|
|
94ff26bdf1 | ||
|
|
2a06680252 | ||
|
|
38a069b97a | ||
|
|
4b58b9f673 | ||
|
|
ffc23a1a1e | ||
|
|
cab60f7385 | ||
|
|
92ce0fe814 | ||
|
|
79d594aca3 | ||
|
|
a343410793 | ||
|
|
3332da3489 | ||
|
|
1a65b308d1 | ||
|
|
f9309c83d2 | ||
|
|
636161e183 | ||
|
|
897878f8ae | ||
|
|
7650cee459 | ||
|
|
30c764e4b3 | ||
|
|
dc92335fbe | ||
|
|
8c625ca87d | ||
|
|
536750b428 | ||
|
|
11e7bb10f1 | ||
|
|
f7cd28cfd3 | ||
|
|
83c7bdf872 | ||
|
|
97383028e5 | ||
|
|
4a6d263dad | ||
|
|
549e881ba4 | ||
|
|
c72ea03a86 | ||
|
|
9fed0724f7 | ||
|
|
ed96da1afc | ||
|
|
da3146e294 | ||
|
|
5aa0cdfd45 | ||
|
|
0be7813398 | ||
|
|
de84f47503 | ||
|
|
115e3d4392 | ||
|
|
9f101ce67f | ||
|
|
9295bc4fbb | ||
|
|
9e083ec668 | ||
|
|
68c8857410 | ||
|
|
9323d1094f | ||
|
|
dc2967b2e7 | ||
|
|
6d85c09e69 | ||
|
|
6a8177145d | ||
|
|
baf686c6c4 | ||
|
|
34c5eed867 | ||
|
|
59840685a4 | ||
|
|
c4e33cab8c | ||
|
|
bf0741e48a | ||
|
|
51b5bbac0d | ||
|
|
03699a4a9e | ||
|
|
57a38636fc | ||
|
|
a5f99c57e1 | ||
|
|
1b0c7bc1b8 | ||
|
|
d84fd76070 | ||
|
|
677697a168 | ||
|
|
0fd4fa7066 | ||
|
|
0932d78d26 | ||
|
|
106f807b68 | ||
|
|
c3e6428ff7 | ||
|
|
78cb89938d | ||
|
|
f503139fae | ||
|
|
5ea096e61e | ||
|
|
f4ff2ad45a | ||
|
|
4fb57dc4e3 | ||
|
|
b8c5303b05 | ||
|
|
3c79701208 | ||
|
|
e82f88dfa9 | ||
|
|
296deb95e6 | ||
|
|
c6917296d3 | ||
|
|
b3672916de | ||
|
|
7c3cb49dfa | ||
|
|
b383302128 | ||
|
|
32d951e312 | ||
|
|
f8f5a18d67 | ||
|
|
2d241316c7 | ||
|
|
6a2ac9800b | ||
|
|
39aa75436e | ||
|
|
f708842e09 | ||
|
|
86af9601bd | ||
|
|
5b7c9c5845 | ||
|
|
7f2fdf3fe1 | ||
|
|
70c9a6528a | ||
|
|
54364d213d | ||
|
|
4d6b9895d3 | ||
|
|
f927455778 | ||
|
|
6928d21bcf | ||
|
|
38eecd5ece | ||
|
|
5aedb73aae | ||
|
|
387b85406e | ||
|
|
823b55c22a | ||
|
|
fdfb8837d1 | ||
|
|
d7c359c412 | ||
|
|
82c51dbe75 | ||
|
|
77259acf9e | ||
|
|
7816379aae | ||
|
|
d192527707 | ||
|
|
b0563a493c | ||
|
|
c38d45b9e7 | ||
|
|
f603b7aec3 | ||
|
|
a9d3cf4574 | ||
|
|
3b2fa89926 | ||
|
|
0d956b229f | ||
|
|
d73f4e7eca | ||
|
|
2778b132f0 | ||
|
|
1eae765dc3 | ||
|
|
267eb90da5 | ||
|
|
8075ce8371 | ||
|
|
d01c72f79b | ||
|
|
8f73e5e5a1 | ||
|
|
62142197c1 | ||
|
|
ff43e60831 | ||
|
|
6b9037790a | ||
|
|
babc6abc64 | ||
|
|
66d932c79f | ||
|
|
7be2f50a98 | ||
|
|
499f7160a4 | ||
|
|
7aca0cc77f | ||
|
|
c874703136 | ||
|
|
e6129ab2d9 | ||
|
|
4a43ac1bdd | ||
|
|
6b7fd8c3dc | ||
|
|
845c20ad93 | ||
|
|
47c050d5b6 | ||
|
|
1fbe5e1daa | ||
|
|
2b1cc43355 | ||
|
|
62cb6a0458 | ||
|
|
ca1dcc9bed | ||
|
|
5a72644486 | ||
|
|
e552466886 | ||
|
|
65043baf5d | ||
|
|
46c54f829c | ||
|
|
4dd5ab7576 | ||
|
|
ee27a48714 | ||
|
|
e5342afe2a | ||
|
|
3c30f7b971 | ||
|
|
99c39b1d57 | ||
|
|
ae485c3115 | ||
|
|
6c2be9bdcc | ||
|
|
1a11d92fd9 | ||
|
|
52c4d08e15 | ||
|
|
6ea1e39ee4 | ||
|
|
f9633a5f6f | ||
|
|
5bc48b2ab3 | ||
|
|
70b6e96f95 | ||
|
|
91a1fd074b | ||
|
|
a615c139e6 | ||
|
|
978fa6b252 | ||
|
|
24f90449ad | ||
|
|
ba8753836e | ||
|
|
e59fd9de96 | ||
|
|
6c4079cb94 | ||
|
|
c2b806563e | ||
|
|
15d912df38 | ||
|
|
a191a907e9 | ||
|
|
0caa349f6a | ||
|
|
1cd0efad41 | ||
|
|
9d49bbfaf0 | ||
|
|
3eb2cd2971 | ||
|
|
8e7d41ec02 | ||
|
|
94ea925152 | ||
|
|
18d93ff677 | ||
|
|
d48cf93a94 | ||
|
|
104b6b878a | ||
|
|
90b68f095f | ||
|
|
6a4364d404 | ||
|
|
5e819f6596 | ||
|
|
eef96da641 | ||
|
|
c38b392fdf | ||
|
|
e0d9dfb68e | ||
|
|
589d6df75d | ||
|
|
6fd9d1ce11 | ||
|
|
ef36604666 | ||
|
|
db56b14637 | ||
|
|
b14c18ee64 | ||
|
|
2c94ab3b1c | ||
|
|
f12b3a2e13 | ||
|
|
ea3f55f030 | ||
|
|
6e2c5a66b3 | ||
|
|
0bed34e0c7 | ||
|
|
f0d8a70b38 | ||
|
|
9acf2b5cda | ||
|
|
d49b92603a | ||
|
|
aa01a22416 | ||
|
|
50e43a9f98 | ||
|
|
ed325c7208 | ||
|
|
aac2c4a080 | ||
|
|
785c6aa1cf | ||
|
|
1b86c8564d | ||
|
|
031f80f6e1 | ||
|
|
6f21138489 | ||
|
|
7bab9cc344 | ||
|
|
510bd261f8 | ||
|
|
c5619f887d | ||
|
|
bb25b03884 | ||
|
|
9bbbf60268 | ||
|
|
37355f9c57 | ||
|
|
af76f757b5 | ||
|
|
b7650b11d6 | ||
|
|
a0d06b3209 | ||
|
|
c52edbd863 | ||
|
|
7355e34946 | ||
|
|
5fa25e70ad | ||
|
|
b8ae4e617b | ||
|
|
353ced0e41 | ||
|
|
ed9f214256 | ||
|
|
939bdaf669 | ||
|
|
2d2ba818e7 | ||
|
|
2653a450fc | ||
|
|
a065773b6d | ||
|
|
4e0ae0cb5e | ||
|
|
611bad4036 | ||
|
|
4a4b9ce7f0 | ||
|
|
100f1e56ca | ||
|
|
69ae224938 | ||
|
|
287628bfee | ||
|
|
f27dc2f4f4 | ||
|
|
1282f13442 | ||
|
|
47514c7708 | ||
|
|
b364bf8b06 | ||
|
|
dea3ef70a2 | ||
|
|
1cc7d37189 | ||
|
|
3164af7e34 | ||
|
|
4c8103a4e1 | ||
|
|
2ebbf2774b | ||
|
|
15450a6d0c | ||
|
|
832519ab64 | ||
|
|
4e2806c951 | ||
|
|
7e0dd1fd41 | ||
|
|
2d971a9fb7 | ||
|
|
3b386379dd | ||
|
|
7b887ee9f6 | ||
|
|
67f0e4be60 | ||
|
|
80acff8d7d | ||
|
|
d5d4d78023 | ||
|
|
5d94f0bea8 | ||
|
|
e5ddbd9886 | ||
|
|
d525b466ec | ||
|
|
333227fad8 | ||
|
|
288a781555 | ||
|
|
979e410efc | ||
|
|
75fa198321 | ||
|
|
49669f6585 | ||
|
|
acf8782786 | ||
|
|
6d2e0aa684 | ||
|
|
032a30f676 | ||
|
|
c9f574c27b | ||
|
|
b725196a26 | ||
|
|
301bafa3f5 | ||
|
|
7a3e4054c7 | ||
|
|
7d7253c9cc | ||
|
|
c2df49ee33 | ||
|
|
a253e175bb | ||
|
|
15023777f4 | ||
|
|
ff018a9a5d | ||
|
|
f76cb94511 | ||
|
|
87cc42d348 | ||
|
|
5177cfdf97 | ||
|
|
13621a1274 | ||
|
|
bc89e54f6d | ||
|
|
5ed2f79217 | ||
|
|
3696a4cd9e | ||
|
|
8259bd316a | ||
|
|
6717f45469 | ||
|
|
44615b7ade | ||
|
|
f3200b2232 | ||
|
|
881cbcd45d | ||
|
|
30a4032067 | ||
|
|
5597fc56d3 | ||
|
|
adcc0efda6 | ||
|
|
d044b13ce4 | ||
|
|
d42c304a55 | ||
|
|
d876f04baf | ||
|
|
593552f8d6 | ||
|
|
25462071df | ||
|
|
1d98c3a782 | ||
|
|
7f239bb931 | ||
|
|
23efe26655 | ||
|
|
ece447182f | ||
|
|
6465bd83a4 | ||
|
|
e941c1acea | ||
|
|
ecad8f25a8 | ||
|
|
48c3a9f2fa | ||
|
|
d59edc5d0a | ||
|
|
17440fc4be | ||
|
|
bff8585411 | ||
|
|
6a307bfcee | ||
|
|
604942f0e7 | ||
|
|
22eeb2f3a5 | ||
|
|
cc6059a4b7 | ||
|
|
91480b6b91 | ||
|
|
4a8e0799bd | ||
|
|
bcd5e40842 | ||
|
|
9fb6430313 | ||
|
|
68e45f3583 | ||
|
|
a1ed47be87 | ||
|
|
ded3867605 | ||
|
|
2b6833f65d | ||
|
|
4d38f11367 | ||
|
|
a3dd25f354 | ||
|
|
4b0e73ca5a | ||
|
|
cd37354634 | ||
|
|
8a5d0a58e4 | ||
|
|
1a71f4fbde | ||
|
|
1534f8749b | ||
|
|
4ea85a9291 | ||
|
|
739c07ca9b | ||
|
|
452338dc11 | ||
|
|
b6a6387f16 | ||
|
|
4a8c869b7e | ||
|
|
c052eb3969 | ||
|
|
48ed38a8c1 | ||
|
|
fba71ed24d | ||
|
|
625650c160 | ||
|
|
9f4c6c61d9 | ||
|
|
9d978f5581 | ||
|
|
664b352559 | ||
|
|
cfa4998ac1 | ||
|
|
5efe6d0a42 | ||
|
|
e34fbcce0d | ||
|
|
8746b2fd7f | ||
|
|
4328627326 | ||
|
|
fc6925fa0a | ||
|
|
b5de3eb588 | ||
|
|
26422fd425 | ||
|
|
cd1a296e4f | ||
|
|
3ddf9f8a0d | ||
|
|
82df6087af | ||
|
|
bef8562de5 | ||
|
|
1000d419fc | ||
|
|
2a9deb6a64 | ||
|
|
351e406f85 | ||
|
|
d6e518838f | ||
|
|
9e39f18230 | ||
|
|
3dd1e5a318 | ||
|
|
23e1c0b71e | ||
|
|
a1436cd205 | ||
|
|
0d320b7922 | ||
|
|
b2a0d0e4da | ||
|
|
273f058da9 | ||
|
|
c6f751bb67 | ||
|
|
00b7ac5a39 | ||
|
|
c0686dc4f9 | ||
|
|
7ab3a3cfd9 | ||
|
|
06d327e76c | ||
|
|
2e28b036f8 | ||
|
|
5293815bf6 |
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
# Check for updates to GitHub Actions every week
|
||||||
|
interval: "weekly"
|
||||||
98
.github/workflows/ci.yml
vendored
Normal file
98
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
name: Continuous Integration
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-20.04, ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
os_short: win
|
||||||
|
compiler_cc: msvc
|
||||||
|
- os: ubuntu-latest
|
||||||
|
os_short: linux
|
||||||
|
compiler_cc: clang
|
||||||
|
compiler_cxx: clang++
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
os_short: linux
|
||||||
|
compiler_cc: clang-8
|
||||||
|
compiler_cxx: clang++-8
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
name: ${{ matrix.os_short }}-${{ matrix.compiler_cc }}
|
||||||
|
env:
|
||||||
|
SDKS: '["episode1","css","tf2","l4d2","csgo"]'
|
||||||
|
ARCH: x86,x86_64
|
||||||
|
DEPENDENCIES_FOLDER: dependencies
|
||||||
|
DEPENDENCIES_ROOT: ${{ github.workspace }}/dependencies
|
||||||
|
MYSQL_VERSION: '5.5'
|
||||||
|
MMSOURCE_VERSION: '1.12'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
path: sourcemod
|
||||||
|
|
||||||
|
- name: Cache dependencies
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: hl2sdk-mysql-mmsource
|
||||||
|
with:
|
||||||
|
path: ${{ env.DEPENDENCIES_ROOT }}
|
||||||
|
key: ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-${{ join(fromJSON(env.SDKS), '') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-
|
||||||
|
|
||||||
|
# Setup Python for AMBuild
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
name: Setup Python 3.8
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p ${{ env.DEPENDENCIES_FOLDER }}
|
||||||
|
cd ${{ env.DEPENDENCIES_FOLDER }}
|
||||||
|
|
||||||
|
# Satisfy checkout-deps requirement for a "sourcemod" folder.
|
||||||
|
mkdir -p sourcemod
|
||||||
|
../sourcemod/tools/checkout-deps.sh -s ${{ join(fromJSON(env.SDKS)) }}
|
||||||
|
|
||||||
|
- name: Install Linux dependencies
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||||
|
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||||
|
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||||
|
|
||||||
|
- name: Select clang compiler
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
echo "CC=${{ matrix.compiler_cc }}" >> $GITHUB_ENV
|
||||||
|
echo "CXX=${{ matrix.compiler_cxx }}" >> $GITHUB_ENV
|
||||||
|
${{ matrix.compiler_cc }} --version
|
||||||
|
${{ matrix.compiler_cxx }} --version
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: sourcemod
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
python ../configure.py --enable-optimize --sdks=${{ join(fromJSON(env.SDKS)) }} --targets=${{ env.ARCH }} --mms-path=${{ env.DEPENDENCIES_ROOT }}/mmsource-${{ env.MMSOURCE_VERSION }} --hl2sdk-root=${{ env.DEPENDENCIES_ROOT }} --mysql-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }} --mysql64-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }}-x86_64
|
||||||
|
ambuild
|
||||||
104
.github/workflows/mocktest.yml
vendored
Normal file
104
.github/workflows/mocktest.yml
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
name: hl2sdk-mock tests
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
jobs:
|
||||||
|
mock:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
name: Clone sourcemod
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
path: sourcemod
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
name: Clone metamod-source
|
||||||
|
with:
|
||||||
|
repository: alliedmodders/metamod-source
|
||||||
|
submodules: recursive
|
||||||
|
path: metamod-source
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
name: Clone hl2sdk-mock
|
||||||
|
with:
|
||||||
|
repository: alliedmodders/hl2sdk-mock
|
||||||
|
submodules: recursive
|
||||||
|
path: hl2sdk-mock
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
name: Setup Python 3.10
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
|
||||||
|
- name: Install AMBuild
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
pip install git+https://github.com/alliedmodders/ambuild
|
||||||
|
|
||||||
|
- name: Build MetaMod:Source
|
||||||
|
working-directory: metamod-source
|
||||||
|
run: |
|
||||||
|
python configure.py --enable-optimize --sdks=mock --targets=x86_64
|
||||||
|
ambuild objdir
|
||||||
|
|
||||||
|
- name: Build SourceMod
|
||||||
|
working-directory: sourcemod
|
||||||
|
run: |
|
||||||
|
python configure.py --no-mysql --enable-optimize --sdks=mock --targets=x86_64
|
||||||
|
ambuild objdir
|
||||||
|
|
||||||
|
- name: Build hl2sdk-mock
|
||||||
|
working-directory: hl2sdk-mock
|
||||||
|
run: |
|
||||||
|
python configure.py --enable-optimize --targets=x86_64
|
||||||
|
ambuild objdir
|
||||||
|
|
||||||
|
- name: Setup gamedir
|
||||||
|
working-directory: hl2sdk-mock
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir ../gamedir
|
||||||
|
./build_gamedir.sh ../gamedir ../metamod-source/objdir/package
|
||||||
|
./build_gamedir.sh ../gamedir ../sourcemod/objdir/package
|
||||||
|
|
||||||
|
- name: Compile testsuite
|
||||||
|
working-directory: hl2sdk-mock
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir ../gamedir/addons/sourcemod/plugins/optional
|
||||||
|
|
||||||
|
for f in ../sourcemod/plugins/testsuite/mock/*.sp; do
|
||||||
|
echo "Compiling $(basename $f)"
|
||||||
|
../gamedir/addons/sourcemod/scripting/spcomp64 -i ../gamedir/addons/sourcemod/scripting/include -o "../gamedir/addons/sourcemod/plugins/optional/$(basename $f .sp).smx" -E "$f"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
working-directory: hl2sdk-mock
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
for f in ../gamedir/addons/sourcemod/plugins/optional/*.smx; do
|
||||||
|
echo "==================================="
|
||||||
|
echo "Running $(basename $f)..."
|
||||||
|
echo "==================================="
|
||||||
|
timeout 60 ./objdir/dist/x86_64/srcds -game_dir ../gamedir +map de_thunder -command "sm plugins load optional/$(basename $f)" -run -run-ticks 20 |
|
||||||
|
{
|
||||||
|
failed=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
echo "$line"
|
||||||
|
if [[ "$line" == *"FAIL"* ]]; then
|
||||||
|
failed=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$failed" = "1" ]; then
|
||||||
|
echo "$(basename $f) failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
done
|
||||||
79
.github/workflows/scripting.yml
vendored
Normal file
79
.github/workflows/scripting.yml
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
name: SourcePawn scripting
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- '[0-9]+.[0-9]+-dev'
|
||||||
|
paths:
|
||||||
|
- 'plugins/include/*'
|
||||||
|
- 'sourcepawn/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '53 05 01 */3 *' # Artifacts expire every 3 months
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
os_short: linux
|
||||||
|
- os: windows-latest
|
||||||
|
os_short: win
|
||||||
|
- os: macos-latest
|
||||||
|
os_short: mac
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
ARCH: x86,x86_64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
# Setup Python for AMBuild
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
name: Setup Python 3.8
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
- name: Install AMBuild
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
pip install git+https://github.com/alliedmodders/ambuild
|
||||||
|
|
||||||
|
- name: Build universal x64/arm64 on macOS
|
||||||
|
if: startsWith(runner.os, 'macOS')
|
||||||
|
run: echo "ARCH=x86_64,arm64" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install Linux dependencies
|
||||||
|
if: startsWith(runner.os, 'Linux')
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \
|
||||||
|
libc6-dev libc6-dev-i386 linux-libc-dev \
|
||||||
|
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||||
|
|
||||||
|
- name: Select clang compiler
|
||||||
|
if: startsWith(runner.os, 'Linux') || startsWith(runner.os, 'macOS')
|
||||||
|
run: |
|
||||||
|
echo "CC=clang" >> $GITHUB_ENV
|
||||||
|
echo "CXX=clang++" >> $GITHUB_ENV
|
||||||
|
clang --version
|
||||||
|
clang++ --version
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
python ../configure.py --enable-optimize --scripting-only --targets=${{ env.ARCH }}
|
||||||
|
ambuild
|
||||||
|
echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Archive tooling
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
|
||||||
|
path: build/package
|
||||||
42
.github/workflows/translations.yml
vendored
Normal file
42
.github/workflows/translations.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
name: Update translation project
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'translations/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
update_translations:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
name: Setup Python 3.10
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
working-directory: tools/language_check
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade -r requirements.txt
|
||||||
|
|
||||||
|
- name: Generate token
|
||||||
|
id: generate_token
|
||||||
|
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
|
||||||
|
with:
|
||||||
|
app_id: ${{ secrets.APP_ID }}
|
||||||
|
private_key: ${{ secrets.APP_PEM }}
|
||||||
|
|
||||||
|
- name: Update translation project
|
||||||
|
working-directory: tools/language_check
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||||
|
ORGANIZATION: alliedmodders
|
||||||
|
PROJECT_NUMBER: 1
|
||||||
|
run: |
|
||||||
|
python ./compare_translation_phrases.py
|
||||||
|
|
||||||
29
.github/workflows/translations_sanitycheck.yml
vendored
Normal file
29
.github/workflows/translations_sanitycheck.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: Sanity check translation phrases
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'translations/**'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'translations/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
check_translations:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
name: Setup Python 3.10
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
|
||||||
|
- name: Check translation phrases syntax
|
||||||
|
working-directory: tools/language_check
|
||||||
|
run: |
|
||||||
|
python ./sanity_check.py
|
||||||
|
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -28,7 +28,6 @@ LIB-Debug/
|
|||||||
[Tt]humbs.db
|
[Tt]humbs.db
|
||||||
|
|
||||||
# AMBuild build directories
|
# AMBuild build directories
|
||||||
build/
|
|
||||||
obj-*/
|
obj-*/
|
||||||
*~
|
*~
|
||||||
*.rej
|
*.rej
|
||||||
@ -36,3 +35,9 @@ obj-*/
|
|||||||
*.smx
|
*.smx
|
||||||
*.swp
|
*.swp
|
||||||
*.gdb_history
|
*.gdb_history
|
||||||
|
objdir
|
||||||
|
# Not standardized, but common name for build directories
|
||||||
|
build*/
|
||||||
|
|
||||||
|
.vs/*
|
||||||
|
.vscode/*
|
||||||
|
|||||||
10
.gitmodules
vendored
10
.gitmodules
vendored
@ -1,6 +1,14 @@
|
|||||||
[submodule "public/amtl"]
|
[submodule "public/amtl"]
|
||||||
path = public/amtl
|
path = public/amtl
|
||||||
url = https://github.com/alliedmodders/amtl
|
url = https://github.com/alliedmodders/amtl
|
||||||
|
shallow = true
|
||||||
[submodule "sourcepawn"]
|
[submodule "sourcepawn"]
|
||||||
path = sourcepawn
|
path = sourcepawn
|
||||||
url = https://github.com/BotoX/sourcepawn.git
|
url = https://github.com/alliedmodders/sourcepawn
|
||||||
|
shallow = true
|
||||||
|
[submodule "hl2sdk-manifests"]
|
||||||
|
path = hl2sdk-manifests
|
||||||
|
url = https://github.com/alliedmodders/hl2sdk-manifests.git
|
||||||
|
[submodule "public/safetyhook"]
|
||||||
|
path = public/safetyhook
|
||||||
|
url = https://github.com/alliedmodders/safetyhook
|
||||||
|
|||||||
146
.travis.yml
146
.travis.yml
@ -1,118 +1,86 @@
|
|||||||
git:
|
git:
|
||||||
depth: 3
|
depth: 3
|
||||||
|
|
||||||
sudo: false
|
|
||||||
language: cpp
|
language: cpp
|
||||||
os: linux
|
os: linux
|
||||||
dist: trusty
|
dist: xenial
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
- llvm-toolchain-trusty-3.9
|
|
||||||
- llvm-toolchain-trusty-4.0
|
|
||||||
- llvm-toolchain-trusty-5.0
|
|
||||||
packages:
|
|
||||||
- lib32stdc++6
|
|
||||||
- lib32z1-dev
|
|
||||||
- libc6-dev-i386
|
|
||||||
- linux-libc-dev
|
|
||||||
- g++-multilib
|
|
||||||
# - clang-3.6
|
|
||||||
# - clang-3.8
|
|
||||||
# - clang-4.0
|
|
||||||
# - clang-5.0
|
|
||||||
# - g++-6
|
|
||||||
# - g++-6-multilib
|
|
||||||
- clang-3.9
|
|
||||||
- g++-4.8-multilib
|
|
||||||
- g++-4.8
|
|
||||||
- g++-4.9-multilib
|
|
||||||
- g++-4.9
|
|
||||||
- g++-5-multilib
|
|
||||||
- g++-5
|
|
||||||
- g++-7-multilib
|
|
||||||
- g++-7
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- ../mysql-5.0
|
|
||||||
env:
|
|
||||||
- MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9"
|
|
||||||
- MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8"
|
|
||||||
- MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
|
|
||||||
- MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
|
|
||||||
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
|
|
||||||
|
|
||||||
matrix:
|
jobs:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
dist: trusty
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages: ['clang-3.6', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
sources:
|
||||||
cache:
|
- ubuntu-toolchain-r-test
|
||||||
directories: ['../mysql-5.0']
|
packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip']
|
||||||
env: ['MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6"']
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"
|
||||||
|
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||||
|
- MODE=optimize
|
||||||
|
- ARCH=x86,x86_64
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
dist: trusty
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
sources:
|
||||||
cache:
|
- ubuntu-toolchain-r-test
|
||||||
directories: ['../mysql-5.0']
|
packages: ['clang-3.4', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip']
|
||||||
env: ['MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"']
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
|
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||||
|
- MODE=optimize
|
||||||
|
- ARCH=x86,x86_64
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode7.2
|
||||||
|
language: cpp
|
||||||
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
|
- SDKS=episode1,css,tf2,l4d2,csgo
|
||||||
|
- MODE=optimize
|
||||||
|
- ARCH=x86_64,x86
|
||||||
|
|
||||||
|
# # This is a faster test for the latest g++.
|
||||||
|
# - os: linux
|
||||||
|
# dist: bionic
|
||||||
|
# sudo: false
|
||||||
|
# language: cpp
|
||||||
|
# addons:
|
||||||
|
# apt:
|
||||||
|
# packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'g++']
|
||||||
|
# cache:
|
||||||
|
# directories: ['../mysql-5.0']
|
||||||
|
# env:
|
||||||
|
# - MATRIX_EVAL="CC=gcc && CXX=g++"
|
||||||
|
# - SDKS=csgo
|
||||||
|
# # GCC currently fails in opt builds trying to inline stuff in sqlite3.c.
|
||||||
|
# - MODE=debug
|
||||||
|
|
||||||
|
# This is a faster test for the latest clang.
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
dist: bionic
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['llvm-toolchain-trusty-4.0']
|
packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'clang']
|
||||||
packages: ['clang-4.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
env:
|
||||||
cache:
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
directories: ['../mysql-5.0']
|
- SDKS=csgo
|
||||||
env: ['MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"']
|
- MODE=optimize
|
||||||
|
- ARCH=x86
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
language: cpp
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['llvm-toolchain-trusty-5.0']
|
|
||||||
packages: ['clang-5.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
|
||||||
cache:
|
|
||||||
directories: ['../mysql-5.0']
|
|
||||||
env: ['MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"']
|
|
||||||
|
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
language: cpp
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
|
||||||
packages: ['g++-6', 'g++-6-multilib', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
|
||||||
cache:
|
|
||||||
directories: ['../mysql-5.0']
|
|
||||||
env: ['MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"']
|
|
||||||
|
|
||||||
allow_failures:
|
|
||||||
- env: MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7"
|
|
||||||
- env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
|
|
||||||
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
|
|
||||||
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
|
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh -s ${SDKS} && cd $CHECKOUT_DIR
|
||||||
script:
|
script:
|
||||||
- mkdir build && cd build
|
- mkdir build && cd build
|
||||||
- PATH="~/.local/bin:$PATH"
|
- PATH="~/.local/bin:$PATH"
|
||||||
- eval "${MATRIX_EVAL}"
|
- eval "${MATRIX_EVAL}"
|
||||||
- python ../configure.py --enable-optimize --sdks=episode1,css,tf2,l4d2,csgo,dota
|
- eval "${CC} --version"
|
||||||
|
- eval "${CXX} --version"
|
||||||
|
- python3 ../configure.py --enable-${MODE} --sdks=${SDKS} --targets=${ARCH}
|
||||||
- ambuild
|
- ambuild
|
||||||
|
|||||||
694
AMBuildScript
694
AMBuildScript
@ -1,63 +1,7 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
|
import collections
|
||||||
import os, sys
|
import os, sys
|
||||||
|
import subprocess
|
||||||
class SDK(object):
|
|
||||||
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
|
||||||
self.folder = 'hl2sdk-' + dir
|
|
||||||
self.envvar = sdk
|
|
||||||
self.ext = ext
|
|
||||||
self.code = aDef
|
|
||||||
self.define = name
|
|
||||||
self.platform = platform
|
|
||||||
self.name = dir
|
|
||||||
self.path = None # Actual path
|
|
||||||
self.platformSpec = platform
|
|
||||||
|
|
||||||
# By default, nothing supports x64.
|
|
||||||
if type(platform) is list:
|
|
||||||
self.platformSpec = {p: ['x86'] for p in platform}
|
|
||||||
else:
|
|
||||||
self.platformSpec = platform
|
|
||||||
|
|
||||||
def shouldBuild(self, target, archs):
|
|
||||||
if target.platform not in self.platformSpec:
|
|
||||||
return False
|
|
||||||
if not len([i for i in self.platformSpec[target.platform] if i in archs]):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
WinOnly = ['windows']
|
|
||||||
WinLinux = ['windows', 'linux']
|
|
||||||
WinLinuxMac = ['windows', 'linux', 'mac']
|
|
||||||
CSGO = {
|
|
||||||
'windows': ['x86'],
|
|
||||||
'linux': ['x86', 'x64'],
|
|
||||||
'mac': ['x64']
|
|
||||||
}
|
|
||||||
|
|
||||||
PossibleSDKs = {
|
|
||||||
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
|
||||||
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
|
||||||
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
|
|
||||||
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
|
|
||||||
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
|
|
||||||
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
|
|
||||||
'tf2': SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'),
|
|
||||||
'l4d': SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
|
|
||||||
'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
|
|
||||||
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
|
|
||||||
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
|
|
||||||
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'),
|
|
||||||
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
|
|
||||||
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
|
||||||
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
|
|
||||||
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
|
|
||||||
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'),
|
|
||||||
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
|
||||||
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
|
|
||||||
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
|
|
||||||
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def ResolveEnvPath(env, folder):
|
def ResolveEnvPath(env, folder):
|
||||||
if env in os.environ:
|
if env in os.environ:
|
||||||
@ -80,41 +24,60 @@ def ResolveEnvPath(env, folder):
|
|||||||
def Normalize(path):
|
def Normalize(path):
|
||||||
return os.path.abspath(os.path.normpath(path))
|
return os.path.abspath(os.path.normpath(path))
|
||||||
|
|
||||||
def SetArchFlags(compiler, arch, platform):
|
def SetArchFlags(compiler):
|
||||||
if compiler.behavior == 'gcc':
|
if compiler.behavior == 'gcc':
|
||||||
if arch == 'x86':
|
if compiler.target.arch == 'x86_64':
|
||||||
compiler.cflags += ['-m32']
|
compiler.cflags += ['-fPIC']
|
||||||
compiler.linkflags += ['-m32']
|
|
||||||
if platform == 'mac':
|
|
||||||
compiler.linkflags += ['-arch', 'i386']
|
|
||||||
elif arch == 'x64':
|
|
||||||
compiler.cflags += ['-m64', '-fPIC']
|
|
||||||
compiler.linkflags += ['-m64']
|
|
||||||
if platform == 'mac':
|
|
||||||
compiler.linkflags += ['-arch', 'x86_64']
|
|
||||||
elif compiler.like('msvc'):
|
elif compiler.like('msvc'):
|
||||||
if builder.target.arch == 'x86':
|
if compiler.target.arch == 'x86_64':
|
||||||
compiler.linkflags += ['/MACHINE:X86']
|
compiler.defines += ['WIN64']
|
||||||
elif builder.target.arch == 'x64':
|
|
||||||
compiler.linkflags += ['/MACHINE:X64']
|
|
||||||
|
|
||||||
def AppendArchSuffix(binary, name, arch):
|
SdkHelpers = builder.Eval('hl2sdk-manifests/SdkHelpers.ambuild', {
|
||||||
if arch == 'x64':
|
'Project': 'sourcemod'
|
||||||
binary.localFolder = name + '.x64'
|
})
|
||||||
|
|
||||||
class SMConfig(object):
|
class SMConfig(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.sdk_manifests = []
|
||||||
self.sdks = {}
|
self.sdks = {}
|
||||||
|
self.sdk_targets = []
|
||||||
self.binaries = []
|
self.binaries = []
|
||||||
|
self.spvm = []
|
||||||
self.extensions = []
|
self.extensions = []
|
||||||
self.generated_headers = None
|
self.generated_headers = None
|
||||||
self.mms_root = None
|
self.mms_root = None
|
||||||
self.mysql_root = {}
|
self.mysql_root = {}
|
||||||
self.spcomp = None
|
self.spcomp = None
|
||||||
self.spcomp_bins = None
|
self.spcomp_bins = []
|
||||||
self.smx_files = {}
|
self.smx_files = {}
|
||||||
self.versionlib = None
|
self.versionlib = None
|
||||||
self.archs = builder.target.arch.replace('x86_64', 'x64').split(',')
|
self.all_targets = []
|
||||||
|
self.target_archs = set()
|
||||||
|
self.enable_asan = getattr(builder.options, 'enable_asan', False)
|
||||||
|
self.asan_libs = {}
|
||||||
|
self.libsafetyhook = {}
|
||||||
|
|
||||||
|
if builder.options.targets:
|
||||||
|
target_archs = builder.options.targets.split(',')
|
||||||
|
else:
|
||||||
|
target_archs = ['x86']
|
||||||
|
if builder.backend != 'amb2':
|
||||||
|
target_archs.append('x86_64')
|
||||||
|
|
||||||
|
for arch in target_archs:
|
||||||
|
try:
|
||||||
|
cxx = builder.DetectCxx(target_arch = arch)
|
||||||
|
self.target_archs.add(cxx.target.arch)
|
||||||
|
except Exception as e:
|
||||||
|
# Error if archs were manually overridden.
|
||||||
|
if builder.options.targets:
|
||||||
|
raise
|
||||||
|
print('Skipping target {}: {}'.format(arch, e))
|
||||||
|
continue
|
||||||
|
self.all_targets.append(cxx)
|
||||||
|
|
||||||
|
if not self.all_targets:
|
||||||
|
raise Exception('No suitable C/C++ compiler was found.')
|
||||||
|
|
||||||
def use_auto_versioning(self):
|
def use_auto_versioning(self):
|
||||||
if builder.backend != 'amb2':
|
if builder.backend != 'amb2':
|
||||||
@ -134,41 +97,38 @@ class SMConfig(object):
|
|||||||
import re
|
import re
|
||||||
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
||||||
productContents = fp.read()
|
productContents = fp.read()
|
||||||
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
m = re.match(r'(\d+)\.(\d+)\.(\d+).*', productContents)
|
||||||
if m == None:
|
if m == None:
|
||||||
self.productVersion = '1.0.0'
|
self.productVersion = '1.0.0'
|
||||||
else:
|
else:
|
||||||
major, minor, release = m.groups()
|
major, minor, release = m.groups()
|
||||||
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
|
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
|
||||||
|
|
||||||
|
def findSdkPath(self, sdk_name):
|
||||||
|
dir_name = 'hl2sdk-{}'.format(sdk_name)
|
||||||
|
if builder.options.hl2sdk_root:
|
||||||
|
sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
|
||||||
|
if os.path.exists(sdk_path):
|
||||||
|
return sdk_path
|
||||||
|
return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
|
||||||
|
|
||||||
|
def shouldIncludeSdk(self, sdk):
|
||||||
|
return not sdk.get('source2', False)
|
||||||
|
|
||||||
def detectSDKs(self):
|
def detectSDKs(self):
|
||||||
sdk_list = builder.options.sdks.split(',')
|
sdk_list = [s for s in builder.options.sdks.split(',') if s]
|
||||||
use_all = sdk_list[0] == 'all'
|
SdkHelpers.sdk_filter = self.shouldIncludeSdk
|
||||||
use_present = sdk_list[0] == 'present'
|
SdkHelpers.find_sdk_path = self.findSdkPath
|
||||||
|
SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
|
||||||
|
|
||||||
for sdk_name in PossibleSDKs:
|
self.sdks = SdkHelpers.sdks
|
||||||
sdk = PossibleSDKs[sdk_name]
|
self.sdk_manifests = SdkHelpers.sdk_manifests
|
||||||
if sdk.shouldBuild(builder.target, self.archs):
|
self.sdk_targets = SdkHelpers.sdk_targets
|
||||||
if builder.options.hl2sdk_root:
|
|
||||||
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
|
||||||
else:
|
|
||||||
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
|
||||||
if sdk_path is None or not os.path.isdir(sdk_path):
|
|
||||||
if use_all or sdk_name in sdk_list:
|
|
||||||
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
|
||||||
continue
|
|
||||||
if use_all or use_present or sdk_name in sdk_list:
|
|
||||||
sdk.path = Normalize(sdk_path)
|
|
||||||
self.sdks[sdk_name] = sdk
|
|
||||||
|
|
||||||
if len(self.sdks) < 1 and len(sdk_list):
|
|
||||||
raise Exception('No SDKs were found that build on {0}-{1}, nothing to do.'.format(
|
|
||||||
builder.target.platform, builder.target.arch))
|
|
||||||
|
|
||||||
if builder.options.mms_path:
|
if builder.options.mms_path:
|
||||||
self.mms_root = builder.options.mms_path
|
self.mms_root = builder.options.mms_path
|
||||||
else:
|
else:
|
||||||
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
|
||||||
if not self.mms_root:
|
if not self.mms_root:
|
||||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||||
if not self.mms_root:
|
if not self.mms_root:
|
||||||
@ -179,40 +139,56 @@ class SMConfig(object):
|
|||||||
self.mms_root = Normalize(self.mms_root)
|
self.mms_root = Normalize(self.mms_root)
|
||||||
|
|
||||||
if builder.options.hasMySql:
|
if builder.options.hasMySql:
|
||||||
if builder.options.mysql_path:
|
if 'x86' in self.target_archs:
|
||||||
self.mysql_root['x86'] = builder.options.mysql_path
|
if builder.options.mysql_path:
|
||||||
else:
|
self.mysql_root['x86'] = builder.options.mysql_path
|
||||||
for i in range(10):
|
|
||||||
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
|
|
||||||
if self.mysql_root['x86']:
|
|
||||||
break
|
|
||||||
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
|
|
||||||
raise Exception('Could not find a path to MySQL!')
|
|
||||||
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
|
|
||||||
|
|
||||||
# For now, ignore 64-bit MySQL on Windows
|
|
||||||
if 'x64' in self.archs and builder.target.platform != 'windows':
|
|
||||||
if builder.options.mysql64_path:
|
|
||||||
self.mysql_root['x64'] = builder.options.mysql64_path
|
|
||||||
else:
|
else:
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
self.mysql_root['x64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
|
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
|
||||||
if self.mysql_root['x64']:
|
if self.mysql_root['x86']:
|
||||||
break
|
break
|
||||||
if not self.mysql_root['x64'] or not os.path.isdir(self.mysql_root['x64']):
|
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
|
||||||
|
raise Exception('Could not find a path to MySQL. Configure with --no-mysql to disable it.')
|
||||||
|
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
|
||||||
|
|
||||||
|
if 'x86_64' in self.target_archs:
|
||||||
|
if builder.options.mysql64_path:
|
||||||
|
self.mysql_root['x86_64'] = builder.options.mysql64_path
|
||||||
|
else:
|
||||||
|
for i in range(10):
|
||||||
|
self.mysql_root['x86_64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
|
||||||
|
if self.mysql_root['x86_64']:
|
||||||
|
break
|
||||||
|
if not self.mysql_root['x86_64'] or not os.path.isdir(self.mysql_root['x86_64']):
|
||||||
raise Exception('Could not find a path to 64-bit MySQL!')
|
raise Exception('Could not find a path to 64-bit MySQL!')
|
||||||
self.mysql_root['x64'] = Normalize(self.mysql_root['x64'])
|
self.mysql_root['x86_64'] = Normalize(self.mysql_root['x86_64'])
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
builder.AddConfigureFile('pushbuild.txt')
|
builder.AddConfigureFile('pushbuild.txt')
|
||||||
|
|
||||||
if not set(self.archs).issubset(['x86', 'x64']):
|
allowed_archs = ['x86_64']
|
||||||
raise Exception('Unknown target architecture: {0}'.format(builder.target.arch))
|
if builder.host.platform == 'mac':
|
||||||
|
if getattr(builder.options, 'scripting_only', False):
|
||||||
|
allowed_archs += ['arm64']
|
||||||
|
else:
|
||||||
|
allowed_archs += ['x86']
|
||||||
|
|
||||||
cxx = builder.DetectCxx()
|
if not set(self.target_archs).issubset(allowed_archs):
|
||||||
|
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
|
||||||
if cxx.like('msvc') and len(self.archs) > 1:
|
|
||||||
raise Exception('Building multiple archs with MSVC is not currently supported')
|
for cxx in self.all_targets:
|
||||||
|
self.configure_cxx(cxx)
|
||||||
|
|
||||||
|
def configure_cxx(self, cxx):
|
||||||
|
if cxx.family == 'msvc':
|
||||||
|
if cxx.version < 1914 and builder.options.generator != 'vs':
|
||||||
|
raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
|
||||||
|
elif cxx.family == 'gcc':
|
||||||
|
if cxx.version < 'gcc-9':
|
||||||
|
raise Exception('Only GCC versions 9 or later are supported, full C++17 support is required.')
|
||||||
|
elif cxx.family == 'clang':
|
||||||
|
if cxx.version < 'clang-5':
|
||||||
|
raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.')
|
||||||
|
|
||||||
if cxx.like('gcc'):
|
if cxx.like('gcc'):
|
||||||
self.configure_gcc(cxx)
|
self.configure_gcc(cxx)
|
||||||
@ -228,11 +204,11 @@ class SMConfig(object):
|
|||||||
cxx.defines += ['DEBUG', '_DEBUG']
|
cxx.defines += ['DEBUG', '_DEBUG']
|
||||||
|
|
||||||
# Platform-specifics
|
# Platform-specifics
|
||||||
if builder.target.platform == 'linux':
|
if cxx.target.platform == 'linux':
|
||||||
self.configure_linux(cxx)
|
self.configure_linux(cxx)
|
||||||
elif builder.target.platform == 'mac':
|
elif cxx.target.platform == 'mac':
|
||||||
self.configure_mac(cxx)
|
self.configure_mac(cxx)
|
||||||
elif builder.target.platform == 'windows':
|
elif cxx.target.platform == 'windows':
|
||||||
self.configure_windows(cxx)
|
self.configure_windows(cxx)
|
||||||
|
|
||||||
# Finish up.
|
# Finish up.
|
||||||
@ -267,25 +243,28 @@ class SMConfig(object):
|
|||||||
'-Wno-unused',
|
'-Wno-unused',
|
||||||
'-Wno-switch',
|
'-Wno-switch',
|
||||||
'-Wno-array-bounds',
|
'-Wno-array-bounds',
|
||||||
'-msse',
|
|
||||||
'-fvisibility=hidden',
|
'-fvisibility=hidden',
|
||||||
]
|
]
|
||||||
|
if cxx.target.arch in ['x86', 'x86_64']:
|
||||||
|
cxx.cflags += ['-msse']
|
||||||
|
|
||||||
|
cxx.cxxflags += ['-std=c++17']
|
||||||
|
|
||||||
cxx.cxxflags += [
|
cxx.cxxflags += [
|
||||||
'-std=c++11',
|
|
||||||
'-fno-exceptions',
|
|
||||||
'-fno-threadsafe-statics',
|
'-fno-threadsafe-statics',
|
||||||
'-Wno-non-virtual-dtor',
|
'-Wno-non-virtual-dtor',
|
||||||
'-Wno-overloaded-virtual',
|
'-Wno-overloaded-virtual',
|
||||||
|
'-Wno-register',
|
||||||
'-fvisibility-inlines-hidden',
|
'-fvisibility-inlines-hidden',
|
||||||
]
|
]
|
||||||
|
|
||||||
have_gcc = cxx.family == 'gcc'
|
have_gcc = cxx.family == 'gcc'
|
||||||
have_clang = cxx.family == 'clang'
|
have_clang = cxx.family == 'clang'
|
||||||
if cxx.version >= 'clang-3.9':
|
if cxx.version >= 'clang-3.9' or cxx.version == 'clang-3.4' or cxx.version > 'apple-clang-6.0':
|
||||||
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
||||||
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
||||||
cxx.cflags += ['-Wno-varargs']
|
cxx.cflags += ['-Wno-varargs']
|
||||||
if cxx.version >= 'clang-3.6' or cxx.version >= 'apple-clang-7.0':
|
if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0':
|
||||||
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
||||||
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
||||||
cxx.cxxflags += ['-Wno-null-dereference']
|
cxx.cxxflags += ['-Wno-null-dereference']
|
||||||
@ -305,14 +284,35 @@ class SMConfig(object):
|
|||||||
cxx.cxxflags += ['-Wno-deprecated']
|
cxx.cxxflags += ['-Wno-deprecated']
|
||||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||||
|
|
||||||
|
if self.enable_asan:
|
||||||
|
if not have_clang:
|
||||||
|
raise Exception('--enable-asan only supported when using Clang')
|
||||||
|
self.configure_asan(cxx)
|
||||||
|
|
||||||
|
# Work around SDK warnings.
|
||||||
|
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
|
||||||
|
cxx.cflags += [
|
||||||
|
'-Wno-implicit-int-float-conversion',
|
||||||
|
'-Wno-tautological-overlap-compare',
|
||||||
|
]
|
||||||
|
|
||||||
if have_gcc:
|
if have_gcc:
|
||||||
cxx.cflags += ['-mfpmath=sse']
|
cxx.cflags += ['-mfpmath=sse']
|
||||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||||
|
|
||||||
if builder.options.opt == '1':
|
if builder.options.opt == '1':
|
||||||
cxx.cflags += ['-O3']
|
if self.enable_asan:
|
||||||
|
cxx.cflags += ['-O1']
|
||||||
|
else:
|
||||||
|
cxx.cflags += ['-O3']
|
||||||
|
|
||||||
|
# Don't omit the frame pointer.
|
||||||
|
cxx.cflags += ['-fno-omit-frame-pointer']
|
||||||
|
|
||||||
def configure_msvc(self, cxx):
|
def configure_msvc(self, cxx):
|
||||||
|
if self.enable_asan:
|
||||||
|
raise Exception('--enable-asan only supported when using Clang')
|
||||||
|
|
||||||
if builder.options.debug == '1':
|
if builder.options.debug == '1':
|
||||||
cxx.cflags += ['/MTd']
|
cxx.cflags += ['/MTd']
|
||||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||||
@ -331,6 +331,7 @@ class SMConfig(object):
|
|||||||
'/EHsc',
|
'/EHsc',
|
||||||
'/GR-',
|
'/GR-',
|
||||||
'/TP',
|
'/TP',
|
||||||
|
'/std:c++17',
|
||||||
]
|
]
|
||||||
cxx.linkflags += [
|
cxx.linkflags += [
|
||||||
'kernel32.lib',
|
'kernel32.lib',
|
||||||
@ -358,29 +359,63 @@ class SMConfig(object):
|
|||||||
# Don't omit the frame pointer.
|
# Don't omit the frame pointer.
|
||||||
cxx.cflags += ['/Oy-']
|
cxx.cflags += ['/Oy-']
|
||||||
|
|
||||||
|
def configure_asan(self, cxx):
|
||||||
|
if cxx.target.platform != 'linux':
|
||||||
|
raise Exception('--enable-asan only supported on Linux')
|
||||||
|
cxx.cflags += ['-fsanitize=address']
|
||||||
|
cxx.linkflags += ['-fsanitize=address']
|
||||||
|
if cxx.target.arch == 'x86':
|
||||||
|
libclang_rt = 'libclang_rt.asan-i386.so'
|
||||||
|
else:
|
||||||
|
libclang_rt = 'libclang_rt.asan-x86_64.so'
|
||||||
|
|
||||||
|
try:
|
||||||
|
argv = cxx.cxx_argv + ['--print-file-name', libclang_rt]
|
||||||
|
output = subprocess.check_output(argv)
|
||||||
|
output = output.decode('utf-8')
|
||||||
|
output = output.strip()
|
||||||
|
except:
|
||||||
|
raise Exception('Could not find {}'.format(libclang_rt))
|
||||||
|
|
||||||
|
print('ASAN library for {}: {}'.format(cxx.target.arch, output))
|
||||||
|
print('You will need to LD_PRELOAD this into srcds.')
|
||||||
|
|
||||||
|
self.asan_libs[cxx.target.arch] = os.path.dirname(output)
|
||||||
|
|
||||||
def configure_linux(self, cxx):
|
def configure_linux(self, cxx):
|
||||||
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||||
cxx.linkflags += ['-lm']
|
cxx.linkflags += ['-lm']
|
||||||
if cxx.family == 'gcc':
|
if cxx.family == 'gcc':
|
||||||
cxx.linkflags += ['-static-libgcc']
|
cxx.linkflags += ['-static-libgcc']
|
||||||
elif cxx.family == 'clang':
|
elif cxx.family == 'clang':
|
||||||
cxx.linkflags += ['-lgcc_eh']
|
cxx.linkflags += ['-lgcc_eh']
|
||||||
|
cxx.linkflags += ['-static-libstdc++']
|
||||||
|
|
||||||
def configure_mac(self, cxx):
|
def configure_mac(self, cxx):
|
||||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
cxx.cflags += ['-mmacosx-version-min=10.15']
|
||||||
cxx.linkflags += [
|
cxx.linkflags += [
|
||||||
'-mmacosx-version-min=10.5',
|
'-mmacosx-version-min=10.15',
|
||||||
'-lstdc++',
|
'-stdlib=libc++',
|
||||||
'-stdlib=libstdc++',
|
'-lc++',
|
||||||
]
|
]
|
||||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
cxx.cxxflags += ['-stdlib=libc++']
|
||||||
|
|
||||||
def configure_windows(self, cxx):
|
def configure_windows(self, cxx):
|
||||||
cxx.defines += ['WIN32', '_WINDOWS']
|
cxx.defines += ['WIN32', '_WINDOWS']
|
||||||
|
|
||||||
def AddVersioning(self, binary, arch):
|
def add_libamtl(self):
|
||||||
if builder.target.platform == 'windows':
|
# Add libamtl.
|
||||||
|
self.libamtl = {}
|
||||||
|
for cxx in self.all_targets:
|
||||||
|
def get_configure_fn(cxx):
|
||||||
|
return lambda builder, name: self.StaticLibrary(builder, cxx, name)
|
||||||
|
extra_vars = {'Configure': get_configure_fn(cxx)}
|
||||||
|
libamtl = builder.Build('public/amtl/amtl/AMBuilder', extra_vars)
|
||||||
|
self.libamtl[cxx.target.arch] = libamtl.binary
|
||||||
|
|
||||||
|
def AddVersioning(self, binary):
|
||||||
|
if binary.compiler.target.platform == 'windows':
|
||||||
binary.sources += ['version.rc']
|
binary.sources += ['version.rc']
|
||||||
binary.compiler.rcdefines += [
|
binary.compiler.rcdefines += [
|
||||||
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
||||||
@ -388,31 +423,39 @@ class SMConfig(object):
|
|||||||
]
|
]
|
||||||
if self.use_auto_versioning():
|
if self.use_auto_versioning():
|
||||||
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
||||||
elif builder.target.platform == 'mac':
|
elif binary.compiler.target.platform == 'mac':
|
||||||
if binary.type == 'library':
|
if binary.type == 'library':
|
||||||
binary.compiler.postlink += [
|
binary.compiler.postlink += [
|
||||||
'-compatibility_version', '1.0.0',
|
'-compatibility_version', '1.0.0',
|
||||||
'-current_version', self.productVersion
|
'-current_version', self.productVersion
|
||||||
]
|
]
|
||||||
if self.use_auto_versioning():
|
if self.use_auto_versioning():
|
||||||
binary.compiler.linkflags += [self.versionlib[arch]]
|
binary.compiler.postlink += [self.versionlib[binary.compiler.target.arch]]
|
||||||
binary.compiler.sourcedeps += SM.generated_headers
|
binary.compiler.sourcedeps += SM.generated_headers
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def LibraryBuilder(self, compiler, name, arch):
|
def LibraryBuilder(self, compiler, name):
|
||||||
binary = compiler.Library(name)
|
binary = compiler.Library(name)
|
||||||
AppendArchSuffix(binary, name, arch)
|
self.AddVersioning(binary)
|
||||||
self.AddVersioning(binary, arch)
|
|
||||||
if binary.compiler.like('msvc'):
|
if binary.compiler.like('msvc'):
|
||||||
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
||||||
|
self.AddCxxCompat(binary)
|
||||||
|
|
||||||
|
# Dumb clang behavior means we have to manually find libclang_rt.
|
||||||
|
if self.enable_asan:
|
||||||
|
binary.compiler.linkflags += [
|
||||||
|
'-shared-libsan',
|
||||||
|
'-Wl,-rpath={}'.format(self.asan_libs[binary.compiler.target.arch]),
|
||||||
|
]
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def ProgramBuilder(self, compiler, name, arch):
|
def ProgramBuilder(self, compiler, name):
|
||||||
binary = compiler.Program(name)
|
binary = compiler.Program(name)
|
||||||
AppendArchSuffix(binary, name, arch)
|
self.AddVersioning(binary)
|
||||||
self.AddVersioning(binary, arch)
|
|
||||||
if '-static-libgcc' in binary.compiler.linkflags:
|
if '-static-libgcc' in binary.compiler.linkflags:
|
||||||
binary.compiler.linkflags.remove('-static-libgcc')
|
binary.compiler.linkflags.remove('-static-libgcc')
|
||||||
|
if self.enable_asan:
|
||||||
|
binary.compiler.linkflags.append('-static-libsan')
|
||||||
if '-lgcc_eh' in binary.compiler.linkflags:
|
if '-lgcc_eh' in binary.compiler.linkflags:
|
||||||
binary.compiler.linkflags.remove('-lgcc_eh')
|
binary.compiler.linkflags.remove('-lgcc_eh')
|
||||||
if binary.compiler.like('gcc'):
|
if binary.compiler.like('gcc'):
|
||||||
@ -421,25 +464,23 @@ class SMConfig(object):
|
|||||||
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
|
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def StaticLibraryBuilder(self, compiler, name, arch):
|
def StaticLibraryBuilder(self, compiler, name):
|
||||||
binary = compiler.StaticLibrary(name)
|
return compiler.StaticLibrary(name)
|
||||||
AppendArchSuffix(binary, name, arch)
|
|
||||||
return binary;
|
|
||||||
|
|
||||||
def Library(self, context, name, arch):
|
def Library(self, context, compiler, name):
|
||||||
compiler = context.cxx.clone()
|
compiler = compiler.clone()
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
SetArchFlags(compiler)
|
||||||
return self.LibraryBuilder(compiler, name, arch)
|
return self.LibraryBuilder(compiler, name)
|
||||||
|
|
||||||
def Program(self, context, name, arch):
|
def Program(self, context, compiler, name):
|
||||||
compiler = context.cxx.clone()
|
compiler = compiler.clone()
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
SetArchFlags(compiler)
|
||||||
return self.ProgramBuilder(compiler, name, arch)
|
return self.ProgramBuilder(compiler, name)
|
||||||
|
|
||||||
def StaticLibrary(self, context, name, arch):
|
def StaticLibrary(self, context, compiler, name):
|
||||||
compiler = context.cxx.clone()
|
compiler = compiler.clone()
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
SetArchFlags(compiler)
|
||||||
return self.StaticLibraryBuilder(compiler, name, arch)
|
return self.StaticLibraryBuilder(compiler, name)
|
||||||
|
|
||||||
def ConfigureForExtension(self, context, compiler):
|
def ConfigureForExtension(self, context, compiler):
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
@ -452,167 +493,82 @@ class SMConfig(object):
|
|||||||
]
|
]
|
||||||
return compiler
|
return compiler
|
||||||
|
|
||||||
def ExtLibrary(self, context, name, arch):
|
def ExtLibrary(self, context, compiler, name):
|
||||||
binary = self.Library(context, name, arch)
|
binary = self.Library(context, compiler, name)
|
||||||
|
SetArchFlags(compiler)
|
||||||
self.ConfigureForExtension(context, binary.compiler)
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def ConfigureForHL2(self, binary, sdk, arch):
|
def AddCxxCompat(self, binary):
|
||||||
|
if binary.compiler.target.platform == 'linux':
|
||||||
|
binary.sources += [
|
||||||
|
os.path.join(builder.sourcePath, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def ConfigureForHL2(self, context, binary, sdk):
|
||||||
compiler = binary.compiler
|
compiler = binary.compiler
|
||||||
|
SetArchFlags(compiler)
|
||||||
SetArchFlags(compiler, arch, builder.target.platform)
|
|
||||||
|
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
os.path.join(self.mms_root, 'core'),
|
os.path.join(self.mms_root, 'core'),
|
||||||
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||||
]
|
]
|
||||||
|
|
||||||
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
for other_sdk in self.sdk_manifests:
|
||||||
compiler.defines += defines
|
compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
|
||||||
|
|
||||||
paths = [
|
SdkHelpers.configureCxx(context, binary, sdk)
|
||||||
['public'],
|
|
||||||
['public', 'engine'],
|
|
||||||
['public', 'mathlib'],
|
|
||||||
['public', 'vstdlib'],
|
|
||||||
['public', 'tier0'],
|
|
||||||
['public', 'tier1']
|
|
||||||
]
|
|
||||||
if sdk.name == 'episode1' or sdk.name == 'darkm':
|
|
||||||
paths.append(['public', 'dlls'])
|
|
||||||
paths.append(['game_shared'])
|
|
||||||
else:
|
|
||||||
paths.append(['public', 'game', 'server'])
|
|
||||||
paths.append(['public', 'toolframework'])
|
|
||||||
paths.append(['game', 'shared'])
|
|
||||||
paths.append(['common'])
|
|
||||||
|
|
||||||
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
|
|
||||||
|
|
||||||
if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
|
|
||||||
# The 2013 SDK already has these in public/tier0/basetypes.h
|
|
||||||
compiler.defines.remove('stricmp=strcasecmp')
|
|
||||||
compiler.defines.remove('_stricmp=strcasecmp')
|
|
||||||
compiler.defines.remove('_snprintf=snprintf')
|
|
||||||
compiler.defines.remove('_vsnprintf=vsnprintf')
|
|
||||||
|
|
||||||
if compiler.like('msvc'):
|
|
||||||
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
|
|
||||||
if compiler.version >= 1900:
|
|
||||||
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
|
||||||
else:
|
|
||||||
compiler.defines += ['COMPILER_GCC']
|
|
||||||
|
|
||||||
if arch == 'x64':
|
|
||||||
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
|
|
||||||
|
|
||||||
# For everything after Swarm, this needs to be defined for entity networking
|
|
||||||
# to work properly with sendprop value changes.
|
|
||||||
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
|
||||||
compiler.defines += ['NETWORK_VARS_ENABLED']
|
|
||||||
|
|
||||||
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
|
|
||||||
if 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++']
|
|
||||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
|
||||||
|
|
||||||
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 in ['sdk2013', 'bms']:
|
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
|
||||||
elif arch == 'x64':
|
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
|
|
||||||
else:
|
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
|
||||||
elif builder.target.platform == 'mac':
|
|
||||||
if sdk.name in ['sdk2013', 'bms']:
|
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
|
||||||
elif arch == 'x64':
|
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
|
|
||||||
else:
|
|
||||||
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
|
||||||
|
|
||||||
if builder.target.platform in ['linux', 'mac']:
|
|
||||||
if sdk.name in ['sdk2013', 'bms'] or arch == 'x64':
|
|
||||||
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', 'doi', 'csgo']:
|
|
||||||
if arch == 'x64':
|
|
||||||
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces.a'))]
|
|
||||||
else:
|
|
||||||
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
|
|
||||||
|
|
||||||
dynamic_libs = []
|
|
||||||
if builder.target.platform == 'linux':
|
|
||||||
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
|
|
||||||
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
|
||||||
elif arch == 'x64' and sdk.name == 'csgo':
|
|
||||||
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
|
|
||||||
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
|
|
||||||
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
|
||||||
else:
|
|
||||||
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
|
||||||
elif 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', 'doi', 'csgo']:
|
|
||||||
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
|
return binary
|
||||||
|
|
||||||
def HL2Library(self, context, name, sdk, arch):
|
def AddCDetour(self, binary):
|
||||||
binary = self.Library(context, name, arch)
|
public_path = os.path.join(builder.sourcePath, 'public')
|
||||||
|
binary.sources += [ os.path.join(public_path, 'CDetour', 'detours.cpp') ]
|
||||||
|
binary.compiler.cxxincludes += [ os.path.join(public_path, 'safetyhook', 'include') ]
|
||||||
|
|
||||||
|
for task in self.libsafetyhook:
|
||||||
|
if task.target.arch == binary.compiler.target.arch:
|
||||||
|
binary.compiler.linkflags += [task.binary]
|
||||||
|
return
|
||||||
|
raise Exception('No suitable build of safetyhook was found.')
|
||||||
|
|
||||||
|
def HL2Library(self, context, compiler, name, sdk):
|
||||||
|
binary = self.Library(context, compiler, name)
|
||||||
self.ConfigureForExtension(context, binary.compiler)
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
return self.ConfigureForHL2(binary, sdk, arch)
|
return self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
|
||||||
def HL2Project(self, context, name):
|
def HL2Config(self, project, context, compiler, name, sdk):
|
||||||
project = context.cxx.LibraryProject(name)
|
binary = project.Configure(compiler, name,
|
||||||
self.ConfigureForExtension(context, project.compiler)
|
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||||
return project
|
self.AddCxxCompat(binary)
|
||||||
|
self.AddVersioning(binary)
|
||||||
|
return self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
|
||||||
def HL2Config(self, project, name, sdk, arch):
|
def HL2ExtConfig(self, project, context, compiler, name, sdk):
|
||||||
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
|
binary = project.Configure(compiler, name,
|
||||||
AppendArchSuffix(binary, name, arch)
|
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||||
self.AddVersioning(binary, arch)
|
self.AddCxxCompat(binary)
|
||||||
return self.ConfigureForHL2(binary, sdk, arch)
|
self.AddVersioning(binary)
|
||||||
|
self.ConfigureForHL2(context, binary, sdk)
|
||||||
|
self.ConfigureForExtension(context, binary.compiler)
|
||||||
|
return binary
|
||||||
|
|
||||||
|
if getattr(builder, 'target', None) is not None:
|
||||||
|
sys.stderr.write("Your output folder was configured for AMBuild 2.1, and SourceMod is now\n")
|
||||||
|
sys.stderr.write("configured to use AMBuild 2.2. Please remove your output folder and\n")
|
||||||
|
sys.stderr.write("reconfigure to continue.\n")
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
SM = SMConfig()
|
SM = SMConfig()
|
||||||
SM.detectProductVersion()
|
SM.detectProductVersion()
|
||||||
SM.detectSDKs()
|
if not getattr(builder.options, 'scripting_only', False):
|
||||||
|
SM.detectSDKs()
|
||||||
SM.configure()
|
SM.configure()
|
||||||
|
SM.add_libamtl()
|
||||||
|
|
||||||
|
# This will clone the list and each cxx object as we recurse, preventing child
|
||||||
|
# scripts from messing up global state.
|
||||||
|
builder.targets = builder.CloneableList(SM.all_targets)
|
||||||
|
|
||||||
if SM.use_auto_versioning():
|
if SM.use_auto_versioning():
|
||||||
SM.generated_headers = builder.Build(
|
SM.generated_headers = builder.Build(
|
||||||
@ -624,46 +580,104 @@ if SM.use_auto_versioning():
|
|||||||
{ 'SM': SM }
|
{ 'SM': SM }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class SafetyHookShim(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.all_targets = {}
|
||||||
|
self.libsafetyhook = {}
|
||||||
|
|
||||||
|
SafetyHook = SafetyHookShim()
|
||||||
|
SafetyHook.all_targets = SM.all_targets
|
||||||
|
builder.Build('public/safetyhook/AMBuilder', {'SafetyHook': SafetyHook })
|
||||||
|
SM.libsafetyhook = SafetyHook.libsafetyhook
|
||||||
|
|
||||||
|
class SPRoot(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.generated_headers = SM.generated_headers
|
||||||
|
# SourcePawn's build scripts are always one-offs, and attach the current target
|
||||||
|
# to the builder, so we have to provide a shim to our StaticLibrary() method.
|
||||||
|
def StaticLibrary(self, builder, name):
|
||||||
|
return SM.StaticLibrary(builder, builder.cxx, name)
|
||||||
|
def Program(self, builder, name):
|
||||||
|
return SM.Program(builder, builder.cxx, name)
|
||||||
|
def Library(self, builder, name):
|
||||||
|
return SM.Library(builder, builder.cxx, name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def targets(self):
|
||||||
|
return SM.all_targets
|
||||||
|
|
||||||
|
@property
|
||||||
|
def libamtl(self):
|
||||||
|
return SM.libamtl
|
||||||
|
|
||||||
|
SP_build_parts = ['core']
|
||||||
|
if getattr(builder.options, 'scripting_only', False):
|
||||||
|
SP_build_parts = ['spcomp']
|
||||||
|
|
||||||
# Build SourcePawn externally.
|
# Build SourcePawn externally.
|
||||||
SP = builder.Build('sourcepawn/AMBuildScript', {
|
SP = builder.Build('sourcepawn/AMBuildScript', {
|
||||||
'external_root': SM,
|
'external_root': SPRoot(),
|
||||||
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||||
'external_build': ['core'],
|
'external_build': SP_build_parts,
|
||||||
})
|
})
|
||||||
if len(SP.spcomp) > 1:
|
|
||||||
SM.spcomp = SP.spcomp['x86']
|
def IsBetterDefaultSpcomp(spcomp, other):
|
||||||
|
if other is None:
|
||||||
|
return True
|
||||||
|
if spcomp.target.arch == 'universal':
|
||||||
|
return True
|
||||||
|
if other.target.arch == 'universal':
|
||||||
|
return False
|
||||||
|
return spcomp.target.arch == 'x86'
|
||||||
|
|
||||||
|
for spcomp in SP.spcomp:
|
||||||
|
if IsBetterDefaultSpcomp(spcomp, SM.spcomp):
|
||||||
|
SM.spcomp = spcomp
|
||||||
|
SM.spcomp_bins.append(spcomp)
|
||||||
|
|
||||||
|
# If we have a universal binary, ignore all other spcomps.
|
||||||
|
if SM.spcomp.target.arch == 'universal':
|
||||||
|
SM.spcomp_bins = [SM.spcomp]
|
||||||
|
|
||||||
|
if not getattr(builder.options, 'scripting_only', False):
|
||||||
|
for cxx in SM.all_targets:
|
||||||
|
SM.spvm += [
|
||||||
|
SP.libsourcepawn[cxx.target.arch]
|
||||||
|
]
|
||||||
|
|
||||||
|
if getattr(builder.options, 'scripting_only', False):
|
||||||
|
BuildScripts = [
|
||||||
|
'tools/buildbot/PackageHelpers',
|
||||||
|
'tools/buildbot/ToolsPackageScript',
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
|
BuildScripts = [
|
||||||
SM.spcomp_bins = list(SP.spcomp.values())
|
'loader/AMBuilder',
|
||||||
for arch in SM.archs:
|
'core/AMBuilder',
|
||||||
SM.binaries += [
|
'core/logic/AMBuilder',
|
||||||
SP.libsourcepawn[arch]
|
'extensions/bintools/AMBuilder',
|
||||||
|
'extensions/clientprefs/AMBuilder',
|
||||||
|
'extensions/curl/AMBuilder',
|
||||||
|
'extensions/cstrike/AMBuilder',
|
||||||
|
'extensions/dhooks/AMBuilder',
|
||||||
|
'extensions/geoip/AMBuilder',
|
||||||
|
'extensions/mysql/AMBuilder',
|
||||||
|
'extensions/pgsql/AMBuilder',
|
||||||
|
'extensions/regex/AMBuilder',
|
||||||
|
'extensions/sdkhooks/AMBuilder',
|
||||||
|
'extensions/sdktools/AMBuilder',
|
||||||
|
'extensions/sqlite/AMBuilder',
|
||||||
|
'extensions/tf2/AMBuilder',
|
||||||
|
'extensions/topmenus/AMBuilder',
|
||||||
|
'extensions/updater/AMBuilder',
|
||||||
]
|
]
|
||||||
|
|
||||||
BuildScripts = [
|
if builder.backend == 'amb2':
|
||||||
'loader/AMBuilder',
|
BuildScripts += [
|
||||||
'core/AMBuilder',
|
'plugins/AMBuilder',
|
||||||
'core/logic/AMBuilder',
|
'tools/buildbot/PackageHelpers',
|
||||||
'extensions/bintools/AMBuilder',
|
'tools/buildbot/PackageScript',
|
||||||
'extensions/clientprefs/AMBuilder',
|
]
|
||||||
'extensions/curl/AMBuilder',
|
|
||||||
'extensions/cstrike/AMBuilder',
|
|
||||||
'extensions/geoip/AMBuilder',
|
|
||||||
'extensions/mysql/AMBuilder',
|
|
||||||
'extensions/regex/AMBuilder',
|
|
||||||
'extensions/sdkhooks/AMBuilder',
|
|
||||||
'extensions/sdktools/AMBuilder',
|
|
||||||
'extensions/sqlite/AMBuilder',
|
|
||||||
'extensions/tf2/AMBuilder',
|
|
||||||
'extensions/topmenus/AMBuilder',
|
|
||||||
'extensions/updater/AMBuilder',
|
|
||||||
]
|
|
||||||
|
|
||||||
if builder.backend == 'amb2':
|
|
||||||
BuildScripts += [
|
|
||||||
'plugins/AMBuilder',
|
|
||||||
'tools/buildbot/PackageScript',
|
|
||||||
]
|
|
||||||
|
|
||||||
builder.Build(BuildScripts, { 'SM': SM })
|
builder.Build(BuildScripts, { 'SM': SM })
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ Development
|
|||||||
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
|
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
|
||||||
- [SourceMod plugin API](https://sm.alliedmods.net/new-api): Online SourceMod plugin API reference generated from the include files
|
- [SourceMod plugin API](https://sm.alliedmods.net/new-api): Online SourceMod plugin API reference generated from the include files
|
||||||
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
|
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
|
||||||
|
- [Translation project](https://github.com/orgs/alliedmodders/projects/1): Help [translate SourceMod](https://wiki.alliedmods.net/Translations_(SourceMod_Scripting)) into your language
|
||||||
|
|
||||||
Contact
|
Contact
|
||||||
-------
|
-------
|
||||||
|
|||||||
17
appveyor.yml
Normal file
17
appveyor.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
version: 1.0.{build}
|
||||||
|
image: Visual Studio 2015
|
||||||
|
clone_folder: c:/projects/sourcemod
|
||||||
|
clone_depth: 1
|
||||||
|
install:
|
||||||
|
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
|
||||||
|
- cmd: git submodule update --init --recursive
|
||||||
|
- cmd: git pull --recurse-submodules
|
||||||
|
- cmd: cd ..
|
||||||
|
- ps: sourcemod/tools/checkout-deps.ps1 -SDKs episode1,css,tf2,l4d2,csgo
|
||||||
|
- cmd: cd sourcemod
|
||||||
|
build_script:
|
||||||
|
- cmd: call "%VS140COMNTOOLS%/vsvars32.bat"
|
||||||
|
- cmd: mkdir build
|
||||||
|
- cmd: cd build
|
||||||
|
- cmd: python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
|
||||||
|
- cmd: ambuild
|
||||||
@ -67,7 +67,7 @@ struct DatabaseInfo;
|
|||||||
class IPlayerInfoBridge;
|
class IPlayerInfoBridge;
|
||||||
class ICommandArgs;
|
class ICommandArgs;
|
||||||
|
|
||||||
typedef ke::Lambda<bool(int client, const ICommandArgs*)> CommandFunc;
|
typedef ke::Function<bool(int client, const ICommandArgs*)> CommandFunc;
|
||||||
|
|
||||||
class CoreProvider
|
class CoreProvider
|
||||||
{
|
{
|
||||||
@ -86,9 +86,6 @@ public:
|
|||||||
const char *gamesuffix;
|
const char *gamesuffix;
|
||||||
/* Data */
|
/* Data */
|
||||||
ServerGlobals *serverGlobals;
|
ServerGlobals *serverGlobals;
|
||||||
void * serverFactory;
|
|
||||||
void * engineFactory;
|
|
||||||
void * matchmakingDSFactory;
|
|
||||||
SMGlobalClass * listeners;
|
SMGlobalClass * listeners;
|
||||||
|
|
||||||
// ConVar functions.
|
// ConVar functions.
|
||||||
@ -115,6 +112,8 @@ public:
|
|||||||
virtual void ConsolePrint(const char *fmt, ...) = 0;
|
virtual void ConsolePrint(const char *fmt, ...) = 0;
|
||||||
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0;
|
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0;
|
||||||
|
|
||||||
|
virtual void FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength) = 0;
|
||||||
|
|
||||||
// Game engine helper functions.
|
// Game engine helper functions.
|
||||||
virtual bool IsClientConVarQueryingSupported() = 0;
|
virtual bool IsClientConVarQueryingSupported() = 0;
|
||||||
virtual int QueryClientConVar(int client, const char *cvar) = 0;
|
virtual int QueryClientConVar(int client, const char *cvar) = 0;
|
||||||
|
|||||||
@ -44,6 +44,7 @@ public:
|
|||||||
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
|
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
|
||||||
virtual bool EndOfFile(FileHandle_t file) = 0;
|
virtual bool EndOfFile(FileHandle_t file) = 0;
|
||||||
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
|
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
|
||||||
|
virtual unsigned int Size(FileHandle_t file) = 0;
|
||||||
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
|
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
|
||||||
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
|
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
|
||||||
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
|
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
|
||||||
@ -56,6 +57,7 @@ public:
|
|||||||
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
|
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
|
||||||
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
|
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
|
||||||
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
|
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
|
||||||
|
virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace SourceMod
|
} // namespace SourceMod
|
||||||
|
|||||||
@ -73,6 +73,9 @@ struct sm_logic_t
|
|||||||
void (*FreeCellArray)(ICellArray *arr);
|
void (*FreeCellArray)(ICellArray *arr);
|
||||||
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
|
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
|
||||||
uint32_t (*ToPseudoAddress)(void *addr);
|
uint32_t (*ToPseudoAddress)(void *addr);
|
||||||
|
void (*SetEntityLumpWritable)(bool writable);
|
||||||
|
bool (*ParseEntityLumpString)(const char *entityString, int &status, size_t &position);
|
||||||
|
const char * (*GetEntityLumpString)();
|
||||||
IScriptManager *scripts;
|
IScriptManager *scripts;
|
||||||
IShareSys *sharesys;
|
IShareSys *sharesys;
|
||||||
IExtensionSys *extsys;
|
IExtensionSys *extsys;
|
||||||
|
|||||||
@ -53,24 +53,6 @@
|
|||||||
* passwords to work, for security reasons.
|
* passwords to work, for security reasons.
|
||||||
*/
|
*/
|
||||||
"PassInfoVar" "_password"
|
"PassInfoVar" "_password"
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the sound that gets played when an item is selected from a menu.
|
|
||||||
*/
|
|
||||||
"MenuItemSound" "buttons/button14.wav"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the sound that gets played when an "Exit" button is selected
|
|
||||||
* from a menu.
|
|
||||||
*/
|
|
||||||
"MenuExitSound" "buttons/combine_button7.wav"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the sound that gets played when an "Exit Back" button is selected
|
|
||||||
* from a menu. This is the special "Back" button that is intended to roll back
|
|
||||||
* to a previous menu.
|
|
||||||
*/
|
|
||||||
"MenuExitBackSound" "buttons/combine_button7.wav"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables whether SourceMod reads a client's cl_language cvar to set
|
* Enables or disables whether SourceMod reads a client's cl_language cvar to set
|
||||||
@ -145,5 +127,15 @@
|
|||||||
* Disable this option at your own risk.
|
* Disable this option at your own risk.
|
||||||
*/
|
*/
|
||||||
"FollowCSGOServerGuidelines" "yes"
|
"FollowCSGOServerGuidelines" "yes"
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls whether the SourcePawn runtime will generate additional metadata about
|
||||||
|
* JIT-compiled functions for performance profiling or debugging purposes.
|
||||||
|
*
|
||||||
|
* "none" - Don't generate any additional JIT metadata
|
||||||
|
* "default" - Generate basic perf metadata (on Linux) and delete it automatically on quit
|
||||||
|
* "perf" - Generate basic perf metadata (Linux only - function names)
|
||||||
|
* "jitdump" - Generate extended perf metadata (Linux only - function names, bytecode, and source information)
|
||||||
|
*/
|
||||||
|
"JITMetadata" "default"
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -1,4 +1,38 @@
|
|||||||
"Languages"
|
"Languages"
|
||||||
{
|
{
|
||||||
"en" "English"
|
"ar" "Arabic" // Arabic
|
||||||
|
"bg" "Bulgarian" // Bulgarian
|
||||||
|
"chi" "SChinese" // Chinese (Simplified)
|
||||||
|
"cze" "Czech" // Czech
|
||||||
|
"da" "Danish" // Danish
|
||||||
|
"de" "German" // German
|
||||||
|
"el" "Greek" // Greek
|
||||||
|
"en" "English" // English
|
||||||
|
"es" "Spanish" // Spanish
|
||||||
|
"fi" "Finnish" // Finnish
|
||||||
|
"fr" "French" // French
|
||||||
|
"he" "Hebrew" // Hebrew
|
||||||
|
"hu" "Hungarian" // Hungarian
|
||||||
|
"it" "Italian" // Italian
|
||||||
|
"jp" "Japanese" // Japanese
|
||||||
|
"ko" "Korean" // Korean
|
||||||
|
"ko" "KoreanA" // Korean (https://bugs.alliedmods.net/show_bug.cgi?id=4667)
|
||||||
|
"las" "LatAm" // Latin American Spanish
|
||||||
|
"lt" "Lithuanian" // Lithuanian
|
||||||
|
"lv" "Latvian" // Latvian
|
||||||
|
"nl" "Dutch" // Dutch
|
||||||
|
"no" "Norwegian" // Norwegian
|
||||||
|
"pl" "Polish" // Polish
|
||||||
|
"pt" "Brazilian" // Brazilian Portuguese
|
||||||
|
"pt_p" "Portuguese" // Portuguese
|
||||||
|
"ro" "Romanian" // Romanian
|
||||||
|
"ru" "Russian" // Russian
|
||||||
|
"sk" "Slovak" // Slovak
|
||||||
|
"sv" "Swedish" // Swedish
|
||||||
|
"th" "Thai" // Thai
|
||||||
|
"tr" "Turkish" // Turkish
|
||||||
|
"ua" "Ukrainian" // Ukrainian
|
||||||
|
"vi" "Vietnamese" // Vietnamese
|
||||||
|
"zho" "TChinese" // Chinese (Traditional)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
41
configs/sql-init-scripts/pgsql/clientprefs-pgsql.sql
Normal file
41
configs/sql-init-scripts/pgsql/clientprefs-pgsql.sql
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS sm_cookies
|
||||||
|
(
|
||||||
|
id serial,
|
||||||
|
name varchar(30) NOT NULL UNIQUE,
|
||||||
|
description varchar(255),
|
||||||
|
access INTEGER,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS sm_cookie_cache
|
||||||
|
(
|
||||||
|
player varchar(65) NOT NULL,
|
||||||
|
cookie_id int NOT NULL,
|
||||||
|
value varchar(100),
|
||||||
|
timestamp int NOT NULL,
|
||||||
|
PRIMARY KEY (player, cookie_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS
|
||||||
|
$$
|
||||||
|
BEGIN
|
||||||
|
LOOP
|
||||||
|
-- first try to update the it.
|
||||||
|
UPDATE sm_cookie_cache SET value = in_value, timestamp = in_time WHERE player = in_player AND cookie_id = in_cookie;
|
||||||
|
IF found THEN
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
-- not there, so try to insert.
|
||||||
|
-- if someone else inserts the same key concurrently, we could get a unique-key failure.
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES (in_player, in_cookie, in_value, in_time);
|
||||||
|
RETURN;
|
||||||
|
EXCEPTION WHEN unique_violation THEN
|
||||||
|
-- do nothing... loop again, and we'll update.
|
||||||
|
END;
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
LANGUAGE plpgsql;
|
||||||
65
configs/sql-init-scripts/pgsql/create_admins.sql
Normal file
65
configs/sql-init-scripts/pgsql/create_admins.sql
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
CREATE TABLE sm_admins (
|
||||||
|
id serial,
|
||||||
|
authtype varchar(6) NOT NULL,
|
||||||
|
CHECK (authtype in ('steam', 'name', 'ip')),
|
||||||
|
identity varchar(65) NOT NULL,
|
||||||
|
password varchar(65),
|
||||||
|
flags varchar(30) NOT NULL,
|
||||||
|
name varchar(65) NOT NULL,
|
||||||
|
immunity int NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_groups (
|
||||||
|
id serial,
|
||||||
|
flags varchar(30) NOT NULL,
|
||||||
|
name varchar(120) NOT NULL,
|
||||||
|
immunity_level int NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_group_immunity (
|
||||||
|
group_id int NOT NULL,
|
||||||
|
other_id int NOT NULL,
|
||||||
|
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (other_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY (group_id, other_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_group_overrides (
|
||||||
|
group_id int NOT NULL,
|
||||||
|
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
type varchar(10) NOT NULL,
|
||||||
|
CHECK (type in ('command', 'group')),
|
||||||
|
name varchar(32) NOT NULL,
|
||||||
|
access varchar(5) NOT NULL,
|
||||||
|
CHECK (access in ('allow', 'deny')),
|
||||||
|
PRIMARY KEY (group_id, type, name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_overrides (
|
||||||
|
type varchar(10) NOT NULL,
|
||||||
|
CHECK (type in ('command', 'group')),
|
||||||
|
name varchar(32) NOT NULL,
|
||||||
|
flags varchar(30) NOT NULL,
|
||||||
|
PRIMARY KEY (type,name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sm_admins_groups (
|
||||||
|
admin_id int NOT NULL,
|
||||||
|
group_id int NOT NULL,
|
||||||
|
FOREIGN KEY (admin_id) REFERENCES sm_admins(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||||
|
inherit_order int NOT NULL,
|
||||||
|
PRIMARY KEY (admin_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- side note, this is pgsql module, sm_config will not exist if the above stuff exists... and it's being left to the admin
|
||||||
|
-- to figure out if it exists.
|
||||||
|
CREATE TABLE sm_config (
|
||||||
|
cfg_key varchar(32) NOT NULL,
|
||||||
|
cfg_value varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (cfg_key)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');
|
||||||
67
configure.py
67
configure.py
@ -1,42 +1,49 @@
|
|||||||
# vim: set ts=2 sw=2 tw=99 noet:
|
# vim: set ts=2 sw=2 tw=99 noet:
|
||||||
import sys
|
import sys
|
||||||
try:
|
try:
|
||||||
from ambuild2 import run, util
|
from ambuild2 import run, util
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
import ambuild
|
import ambuild
|
||||||
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
|
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
|
||||||
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
|
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
|
||||||
except:
|
except:
|
||||||
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
sys.stderr.write('AMBuild must be installed to build this project.\n')
|
||||||
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def make_objdir_name(p):
|
# Hack to show a decent upgrade message, which wasn't done until 2.2.
|
||||||
return 'obj-' + util.Platform() + '-' + p.target_arch
|
ambuild_version = getattr(run, 'CURRENT_API', '2.1')
|
||||||
|
if ambuild_version.startswith('2.1'):
|
||||||
|
sys.stderr.write("AMBuild 2.2 or higher is required; please update\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
parser = run.BuildParser(sourcePath=sys.path[0], api='2.1')
|
parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
||||||
parser.default_arch = 'x86'
|
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||||
parser.default_build_folder = make_objdir_name
|
help='Root search folder for HL2SDKs')
|
||||||
parser.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
parser.options.add_argument('--mysql-path', type=str, dest='mysql_path', default=None,
|
||||||
help='Root search folder for HL2SDKs')
|
help='Path to MySQL 5')
|
||||||
parser.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None,
|
parser.options.add_argument('--mysql64-path', type=str, dest='mysql64_path', default=None,
|
||||||
help='Path to MySQL 5')
|
help='Path to 64-bit MySQL 5')
|
||||||
parser.options.add_option('--mysql64-path', type=str, dest='mysql64_path', default=None,
|
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
|
||||||
help='Path to 64-bit MySQL 5')
|
|
||||||
parser.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
|
|
||||||
help='Path to Metamod:Source')
|
help='Path to Metamod:Source')
|
||||||
parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
|
||||||
help='Enable debugging symbols')
|
help='Enable debugging symbols')
|
||||||
parser.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||||
help='Enable optimization')
|
help='Enable optimization')
|
||||||
parser.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql',
|
parser.options.add_argument('--no-mysql', action='store_false', default=True, dest='hasMySql',
|
||||||
help='Disable building MySQL extension')
|
help='Disable building MySQL extension')
|
||||||
parser.options.add_option('-s', '--sdks', default='all', dest='sdks',
|
parser.options.add_argument('-s', '--sdks', default='present', dest='sdks',
|
||||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
help='Build against specified SDKs; valid args are "none", "all", "present",'
|
||||||
'comma-delimited list of engine names (default: %default)')
|
' or comma-delimited list of engine names')
|
||||||
parser.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump',
|
parser.options.add_argument('--breakpad-dump', action='store_true', dest='breakpad_dump',
|
||||||
default=False, help='Dump and upload breakpad symbols')
|
default=False, help='Dump and upload breakpad symbols')
|
||||||
parser.options.add_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
|
parser.options.add_argument('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
|
||||||
default=False, help='Disable the auto versioning script')
|
default=False, help='Disable the auto versioning script')
|
||||||
|
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
|
||||||
|
help="Override the target architecture (use commas to separate multiple targets).")
|
||||||
|
parser.options.add_argument('--scripting-only', action='store_true', dest='scripting_only', default=False,
|
||||||
|
help="Only build and package the files required for scripting in SourcePawn.")
|
||||||
|
parser.options.add_argument('--enable-asan', action='store_true', dest='enable_asan',
|
||||||
|
default=False, help='Enable ASAN (clang only)')
|
||||||
parser.Configure()
|
parser.Configure()
|
||||||
|
|||||||
148
core/AMBuilder
148
core/AMBuilder
@ -1,7 +1,8 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os
|
||||||
|
|
||||||
project = SM.HL2Project(builder, 'sourcemod')
|
project = builder.LibraryProject('sourcemod')
|
||||||
|
|
||||||
project.sources += [
|
project.sources += [
|
||||||
'MenuStyle_Valve.cpp',
|
'MenuStyle_Valve.cpp',
|
||||||
'logic_bridge.cpp',
|
'logic_bridge.cpp',
|
||||||
@ -37,76 +38,103 @@ project.sources += [
|
|||||||
'MenuStyle_Radio.cpp',
|
'MenuStyle_Radio.cpp',
|
||||||
'sm_autonatives.cpp',
|
'sm_autonatives.cpp',
|
||||||
'ConsoleDetours.cpp',
|
'ConsoleDetours.cpp',
|
||||||
'vprof_tool.cpp',
|
|
||||||
'smn_commandline.cpp',
|
'smn_commandline.cpp',
|
||||||
'GameHooks.cpp',
|
'GameHooks.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
for sdk_name in SM.sdks:
|
# SDK name to shipping gamedir
|
||||||
sdk = SM.sdks[sdk_name]
|
pb_gamedir_map = {
|
||||||
for arch in SM.archs:
|
'csgo': 'csgo',
|
||||||
if not arch in sdk.platformSpec[builder.target.platform]:
|
'blade': 'berimbau',
|
||||||
continue
|
'mcv': 'vietnam',
|
||||||
|
}
|
||||||
|
|
||||||
binary_name = 'sourcemod.' + sdk.ext
|
# SDK name to source code gamedir
|
||||||
|
pb_gamesrcdir_map = {
|
||||||
|
'csgo': 'cstrike15',
|
||||||
|
'blade': 'berimbau',
|
||||||
|
'mcv': 'vietnam',
|
||||||
|
}
|
||||||
|
|
||||||
binary = SM.HL2Config(project, binary_name, sdk, arch)
|
for sdk_target in SM.sdk_targets:
|
||||||
compiler = binary.compiler
|
sdk = sdk_target.sdk
|
||||||
|
cxx = sdk_target.cxx
|
||||||
|
|
||||||
|
binary_name = 'sourcemod.' + sdk['extension']
|
||||||
|
needs_protobuf = sdk['name'] in ['csgo', 'blade', 'mcv']
|
||||||
|
|
||||||
|
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
|
||||||
|
SM.ConfigureForExtension(builder, binary.compiler)
|
||||||
|
|
||||||
|
compiler = binary.compiler
|
||||||
|
compiler.cxxincludes += [
|
||||||
|
builder.sourcePath
|
||||||
|
]
|
||||||
|
|
||||||
|
if needs_protobuf:
|
||||||
compiler.cxxincludes += [
|
compiler.cxxincludes += [
|
||||||
builder.sourcePath
|
os.path.join(sdk['path'], 'common', 'protobuf-2.5.0', 'src'),
|
||||||
|
os.path.join(sdk['path'], 'public', 'engine', 'protobuf'),
|
||||||
|
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf')
|
||||||
|
]
|
||||||
|
|
||||||
|
if compiler.like('msvc'):
|
||||||
|
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||||
|
if cxx.target.platform == 'linux':
|
||||||
|
compiler.postlink += ['-lpthread', '-lrt']
|
||||||
|
|
||||||
|
if needs_protobuf:
|
||||||
|
if compiler.target.platform == 'linux':
|
||||||
|
if compiler.target.arch == 'x86':
|
||||||
|
lib_path = os.path.join(sdk['path'], 'lib', 'linux32', 'release', 'libprotobuf.a')
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
lib_path = os.path.join(sdk['path'], 'lib', 'linux64', 'release', 'libprotobuf.a')
|
||||||
|
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
||||||
|
elif compiler.target.platform == 'mac':
|
||||||
|
if compiler.target.arch == 'x86':
|
||||||
|
lib_path = os.path.join(sdk['path'], 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
lib_path = os.path.join(sdk['path'], 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||||
|
elif compiler.target.platform == 'windows':
|
||||||
|
msvc_ver = compiler.version
|
||||||
|
vs_year = ''
|
||||||
|
platform = ''
|
||||||
|
if compiler.target.arch == 'x86':
|
||||||
|
platform = 'win32'
|
||||||
|
elif compiler.target.arch == 'x86_64':
|
||||||
|
platform = 'win64'
|
||||||
|
|
||||||
|
if 1900 <= msvc_ver < 2000:
|
||||||
|
vs_year = '2015'
|
||||||
|
else:
|
||||||
|
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
||||||
|
|
||||||
|
if 'DEBUG' in compiler.defines:
|
||||||
|
lib_path = os.path.join(sdk['path'], 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
||||||
|
else:
|
||||||
|
lib_path = os.path.join(sdk['path'], 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
||||||
|
compiler.linkflags.insert(0, lib_path)
|
||||||
|
|
||||||
|
if needs_protobuf:
|
||||||
|
binary.sources += ['smn_protobuf.cpp']
|
||||||
|
else:
|
||||||
|
binary.sources += ['smn_bitbuffer.cpp']
|
||||||
|
|
||||||
|
if sdk['name'] != 'blade':
|
||||||
|
binary.sources += [
|
||||||
|
'vprof_tool.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
if needs_protobuf:
|
||||||
compiler.cxxincludes += [
|
binary.sources += [
|
||||||
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessages.pb.cc'),
|
||||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
|
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessage_helpers.cpp'),
|
||||||
]
|
]
|
||||||
|
if sdk['name'] == 'mcv':
|
||||||
if compiler.like('msvc'):
|
|
||||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
|
||||||
if builder.target.platform == 'linux':
|
|
||||||
compiler.postlink += ['-lpthread', '-lrt']
|
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
|
||||||
if builder.target.platform == 'linux':
|
|
||||||
if arch == 'x86':
|
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
|
|
||||||
elif arch == 'x64':
|
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a')
|
|
||||||
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
|
||||||
elif builder.target.platform == 'mac':
|
|
||||||
if arch == 'x86':
|
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
|
||||||
elif arch == 'x64':
|
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
|
|
||||||
elif builder.target.platform == 'windows':
|
|
||||||
msvc_ver = compiler.version
|
|
||||||
vs_year = ''
|
|
||||||
if msvc_ver == 1800:
|
|
||||||
vs_year = '2013'
|
|
||||||
elif 1900 <= msvc_ver < 2000:
|
|
||||||
vs_year = '2015'
|
|
||||||
else:
|
|
||||||
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
|
|
||||||
|
|
||||||
if 'DEBUG' in compiler.defines:
|
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
|
|
||||||
else:
|
|
||||||
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
|
|
||||||
compiler.linkflags.insert(0, binary.Dep(lib_path))
|
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
|
||||||
binary.sources += ['smn_protobuf.cpp']
|
|
||||||
else:
|
|
||||||
binary.sources += ['smn_bitbuffer.cpp']
|
|
||||||
|
|
||||||
if sdk.name == 'csgo':
|
|
||||||
binary.sources += [
|
binary.sources += [
|
||||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_gcmessages.pb.cc'),
|
||||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
|
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'engine_gcmessages.pb.cc'),
|
||||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
SM.binaries += builder.Add(project)
|
SM.binaries += builder.Add(project)
|
||||||
|
|||||||
@ -29,6 +29,8 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <ITextParsers.h>
|
#include <ITextParsers.h>
|
||||||
#include "ChatTriggers.h"
|
#include "ChatTriggers.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
@ -64,7 +66,7 @@ ChatTriggers::~ChatTriggers()
|
|||||||
|
|
||||||
void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
|
void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value)
|
||||||
{
|
{
|
||||||
ke::AutoPtr<char[]> filtered(new char[strlen(value) + 1]);
|
std::unique_ptr<char[]> filtered(new char[strlen(value) + 1]);
|
||||||
|
|
||||||
const char *src = value;
|
const char *src = value;
|
||||||
char *dest = filtered.get();
|
char *dest = filtered.get();
|
||||||
@ -135,26 +137,26 @@ void ChatTriggers::OnSourceModGameInitialized()
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (ConCommand *say = FindCommand("say")) {
|
if (ConCommand *say = FindCommand("say")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say, post_hook));
|
||||||
}
|
}
|
||||||
if (ConCommand *say_team = FindCommand("say_team")) {
|
if (ConCommand *say_team = FindCommand("say_team")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say_team, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_team, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0);
|
||||||
if (m_bIsINS) {
|
if (m_bIsINS) {
|
||||||
if (ConCommand *say2 = FindCommand("say2")) {
|
if (ConCommand *say2 = FindCommand("say2")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say2, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say2, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say2, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say2, post_hook));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
#elif SOURCE_ENGINE == SE_NUCLEARDAWN
|
||||||
if (ConCommand *say_squad = FindCommand("say_squad")) {
|
if (ConCommand *say_squad = FindCommand("say_squad")) {
|
||||||
hooks_.append(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook));
|
hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook));
|
||||||
hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook));
|
hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -275,10 +277,10 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command)
|
|||||||
bool is_silent = false;
|
bool is_silent = false;
|
||||||
|
|
||||||
// Prefer the silent trigger in case of clashes.
|
// Prefer the silent trigger in case of clashes.
|
||||||
if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) {
|
if (strchr(m_PrivTrigger.c_str(), m_ArgSBackup[0])) {
|
||||||
is_trigger = true;
|
is_trigger = true;
|
||||||
is_silent = true;
|
is_silent = true;
|
||||||
} else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) {
|
} else if (strchr(m_PubTrigger.c_str(), m_ArgSBackup[0])) {
|
||||||
is_trigger = true;
|
is_trigger = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +363,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
|||||||
if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
|
if (!g_ConCmds.LookForSourceModCommand(cmd_buf))
|
||||||
{
|
{
|
||||||
/* Check if we had an "sm_" prefix */
|
/* Check if we had an "sm_" prefix */
|
||||||
if (strncmp(cmd_buf, "sm_", 3) == 0)
|
if (strncasecmp(cmd_buf, "sm_", 3) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -385,15 +387,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args)
|
|||||||
/* See if we need to do extra string manipulation */
|
/* See if we need to do extra string manipulation */
|
||||||
if (prepended)
|
if (prepended)
|
||||||
{
|
{
|
||||||
size_t len;
|
ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
|
||||||
|
|
||||||
/* Check if we need to prepend sm_ */
|
|
||||||
if (prepended)
|
|
||||||
{
|
|
||||||
len = ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args);
|
|
||||||
} else {
|
|
||||||
len = ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args);
|
||||||
}
|
}
|
||||||
@ -467,3 +461,23 @@ bool ChatTriggers::WasFloodedMessage()
|
|||||||
{
|
{
|
||||||
return m_bWasFloodedMessage;
|
return m_bWasFloodedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *ChatTriggers::GetPublicChatTrigger()
|
||||||
|
{
|
||||||
|
if (!m_PubTrigger.length())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_PubTrigger.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ChatTriggers::GetPrivateChatTrigger()
|
||||||
|
{
|
||||||
|
if (!m_PrivTrigger.length())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_PrivTrigger.c_str();
|
||||||
|
}
|
||||||
|
|||||||
@ -63,6 +63,8 @@ public:
|
|||||||
unsigned int SetReplyTo(unsigned int reply);
|
unsigned int SetReplyTo(unsigned int reply);
|
||||||
bool IsChatTrigger();
|
bool IsChatTrigger();
|
||||||
bool WasFloodedMessage();
|
bool WasFloodedMessage();
|
||||||
|
const char *GetPublicChatTrigger();
|
||||||
|
const char *GetPrivateChatTrigger();
|
||||||
private:
|
private:
|
||||||
enum ChatTriggerType {
|
enum ChatTriggerType {
|
||||||
ChatTrigger_Public,
|
ChatTrigger_Public,
|
||||||
@ -73,9 +75,9 @@ private:
|
|||||||
bool ClientIsFlooding(int client);
|
bool ClientIsFlooding(int client);
|
||||||
cell_t CallOnClientSayCommand(int client);
|
cell_t CallOnClientSayCommand(int client);
|
||||||
private:
|
private:
|
||||||
ke::Vector<ke::RefPtr<CommandHook>> hooks_;
|
std::vector<ke::RefPtr<CommandHook>> hooks_;
|
||||||
ke::AString m_PubTrigger;
|
std::string m_PubTrigger;
|
||||||
ke::AString m_PrivTrigger;
|
std::string m_PrivTrigger;
|
||||||
bool m_bWillProcessInPost;
|
bool m_bWillProcessInPost;
|
||||||
bool m_bIsChatTrigger;
|
bool m_bIsChatTrigger;
|
||||||
bool m_bWasFloodedMessage;
|
bool m_bWasFloodedMessage;
|
||||||
|
|||||||
@ -30,21 +30,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ConCmdManager.h"
|
#include "ConCmdManager.h"
|
||||||
#include "sm_stringutil.h"
|
|
||||||
#include "PlayerManager.h"
|
|
||||||
#include "HalfLife2.h"
|
|
||||||
#include "ChatTriggers.h"
|
|
||||||
#include "logic_bridge.h"
|
|
||||||
#include "sourcemod.h"
|
|
||||||
#include "provider.h"
|
|
||||||
#include "command_args.h"
|
|
||||||
#include <bridge/include/IScriptManager.h>
|
#include <bridge/include/IScriptManager.h>
|
||||||
|
#include "ChatTriggers.h"
|
||||||
|
#include "HalfLife2.h"
|
||||||
|
#include "PlayerManager.h"
|
||||||
|
#include "command_args.h"
|
||||||
|
#include "logic_bridge.h"
|
||||||
|
#include "provider.h"
|
||||||
|
#include "sm_stringutil.h"
|
||||||
|
#include "sourcemod.h"
|
||||||
|
|
||||||
using namespace ke;
|
using namespace ke;
|
||||||
|
|
||||||
ConCmdManager g_ConCmds;
|
ConCmdManager g_ConCmds;
|
||||||
|
|
||||||
typedef ke::LinkedList<CmdHook *> PluginHookList;
|
typedef std::list<CmdHook *> PluginHookList;
|
||||||
void RegisterInPlugin(CmdHook *hook);
|
void RegisterInPlugin(CmdHook *hook);
|
||||||
|
|
||||||
ConCmdManager::ConCmdManager()
|
ConCmdManager::ConCmdManager()
|
||||||
@ -120,8 +121,13 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
|
|||||||
if (hook->admin)
|
if (hook->admin)
|
||||||
hook->admin->group->hooks.remove(hook);
|
hook->admin->group->hooks.remove(hook);
|
||||||
|
|
||||||
if (hook->info->hooks.empty())
|
if (hook->info->hooks.empty()) {
|
||||||
RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true);
|
RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true);
|
||||||
|
}
|
||||||
|
else { // update plugin reference to next hook in line
|
||||||
|
auto next = *hook->info->hooks.begin();
|
||||||
|
next->info->pPlugin = next->plugin;
|
||||||
|
}
|
||||||
|
|
||||||
iter = pList->erase(iter);
|
iter = pList->erase(iter);
|
||||||
delete hook;
|
delete hook;
|
||||||
@ -147,30 +153,13 @@ ConCmdInfo *ConCmdManager::FindInTrie(const char *name)
|
|||||||
return pInfo;
|
return pInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConCmdList::iterator ConCmdManager::FindInList(const char *cmd)
|
|
||||||
{
|
|
||||||
List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
|
|
||||||
|
|
||||||
while (iter != m_CmdList.end())
|
|
||||||
{
|
|
||||||
if (strcasecmp((*iter)->pCmd->GetName(), cmd) == 0)
|
|
||||||
break;
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
|
ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
|
||||||
{
|
{
|
||||||
ConCmdInfo *pInfo;
|
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||||
|
|
||||||
if ((pInfo = FindInTrie(cmd)) == NULL)
|
if (pInfo == NULL)
|
||||||
{
|
{
|
||||||
ConCmdList::iterator item = FindInList(cmd);
|
return type;
|
||||||
if (item == m_CmdList.end())
|
|
||||||
return type;
|
|
||||||
pInfo = *item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t result = type;
|
cell_t result = type;
|
||||||
@ -181,7 +170,7 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int
|
|||||||
if (hook->type == CmdHook::Server || !hook->pf->IsRunnable())
|
if (hook->type == CmdHook::Server || !hook->pf->IsRunnable())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (hook->admin && !CheckAccess(client, cmd, hook->admin))
|
if (hook->admin && !CheckAccess(client, cmd, hook->admin.get()))
|
||||||
{
|
{
|
||||||
if (result < Pl_Handled)
|
if (result < Pl_Handled)
|
||||||
result = Pl_Handled;
|
result = Pl_Handled;
|
||||||
@ -225,17 +214,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
|||||||
ConCmdInfo *pInfo = FindInTrie(cmd);
|
ConCmdInfo *pInfo = FindInTrie(cmd);
|
||||||
if (pInfo == NULL)
|
if (pInfo == NULL)
|
||||||
{
|
{
|
||||||
/* Unfortunately, we now have to do a slow lookup because Valve made client commands
|
return false;
|
||||||
* case-insensitive. We can't even use our sortedness.
|
|
||||||
*/
|
|
||||||
if (client == 0 && !engine->IsDedicatedServer())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ConCmdList::iterator item = FindInList(cmd);
|
|
||||||
if (item == m_CmdList.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pInfo = *item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a hack to prevent say triggers from firing on messages that were
|
/* This is a hack to prevent say triggers from firing on messages that were
|
||||||
@ -271,7 +250,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args)
|
|||||||
} else {
|
} else {
|
||||||
// Check admin rights if needed. realClient isn't needed since we
|
// Check admin rights if needed. realClient isn't needed since we
|
||||||
// should bypass admin checks if client == 0 anyway.
|
// should bypass admin checks if client == 0 anyway.
|
||||||
if (client && hook->admin && !CheckAccess(client, cmd, hook->admin))
|
if (client && hook->admin && !CheckAccess(client, cmd, hook->admin.get()))
|
||||||
{
|
{
|
||||||
if (result < Pl_Handled)
|
if (result < Pl_Handled)
|
||||||
result = Pl_Handled;
|
result = Pl_Handled;
|
||||||
@ -359,8 +338,8 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
|||||||
}
|
}
|
||||||
RefPtr<CommandGroup> cmdgroup = i->value;
|
RefPtr<CommandGroup> cmdgroup = i->value;
|
||||||
|
|
||||||
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description);
|
CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description, pPlugin);
|
||||||
pHook->admin = new AdminCmdInfo(cmdgroup, adminflags);
|
pHook->admin = std::make_unique<AdminCmdInfo>(cmdgroup, adminflags);
|
||||||
|
|
||||||
/* First get the command group override, if any */
|
/* First get the command group override, if any */
|
||||||
bool override = adminsys->GetCommandOverride(group,
|
bool override = adminsys->GetCommandOverride(group,
|
||||||
@ -380,7 +359,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
|
|||||||
pHook->admin->eflags = pHook->admin->flags;
|
pHook->admin->eflags = pHook->admin->flags;
|
||||||
pInfo->eflags = pHook->admin->eflags;
|
pInfo->eflags = pHook->admin->eflags;
|
||||||
|
|
||||||
cmdgroup->hooks.append(pHook);
|
cmdgroup->hooks.push_back(pHook);
|
||||||
pInfo->hooks.append(pHook);
|
pInfo->hooks.append(pHook);
|
||||||
RegisterInPlugin(pHook);
|
RegisterInPlugin(pHook);
|
||||||
return true;
|
return true;
|
||||||
@ -398,7 +377,7 @@ bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
|
|||||||
if (!pInfo)
|
if (!pInfo)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description);
|
CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description, pPlugin);
|
||||||
|
|
||||||
pInfo->hooks.append(pHook);
|
pInfo->hooks.append(pHook);
|
||||||
RegisterInPlugin(pHook);
|
RegisterInPlugin(pHook);
|
||||||
@ -425,13 +404,13 @@ void RegisterInPlugin(CmdHook *hook)
|
|||||||
const char *cmd = (*iter)->info->pCmd->GetName();
|
const char *cmd = (*iter)->info->pCmd->GetName();
|
||||||
if (strcmp(orig, cmd) < 0)
|
if (strcmp(orig, cmd) < 0)
|
||||||
{
|
{
|
||||||
pList->insertBefore(iter, hook);
|
pList->emplace(iter, hook);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pList->append(hook);
|
pList->emplace_back(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConCmdManager::AddToCmdList(ConCmdInfo *info)
|
void ConCmdManager::AddToCmdList(ConCmdInfo *info)
|
||||||
@ -495,7 +474,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag
|
|||||||
for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++)
|
for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++)
|
||||||
{
|
{
|
||||||
CmdHook *hook = *iter;
|
CmdHook *hook = *iter;
|
||||||
if (remove)
|
if (!remove)
|
||||||
hook->admin->eflags = bits;
|
hook->admin->eflags = bits;
|
||||||
else
|
else
|
||||||
hook->admin->eflags = hook->admin->flags;
|
hook->admin->eflags = hook->admin->flags;
|
||||||
@ -562,10 +541,6 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri
|
|||||||
ConCmdInfo *pInfo;
|
ConCmdInfo *pInfo;
|
||||||
if (!m_Cmds.retrieve(name, &pInfo))
|
if (!m_Cmds.retrieve(name, &pInfo))
|
||||||
{
|
{
|
||||||
ConCmdList::iterator item = FindInList(name);
|
|
||||||
if (item != m_CmdList.end())
|
|
||||||
return *item;
|
|
||||||
|
|
||||||
pInfo = new ConCmdInfo();
|
pInfo = new ConCmdInfo();
|
||||||
/* Find the commandopan */
|
/* Find the commandopan */
|
||||||
ConCommand *pCmd = FindCommand(name);
|
ConCommand *pCmd = FindCommand(name);
|
||||||
@ -648,7 +623,7 @@ void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
|||||||
|
|
||||||
name = hook->info->pCmd->GetName();
|
name = hook->info->pCmd->GetName();
|
||||||
if (hook->helptext.length())
|
if (hook->helptext.length())
|
||||||
help = hook->helptext.chars();
|
help = hook->helptext.c_str();
|
||||||
else
|
else
|
||||||
help = hook->info->pCmd->GetHelpText();
|
help = hook->info->pCmd->GetHelpText();
|
||||||
UTIL_ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
|
UTIL_ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
|
||||||
|
|||||||
@ -32,6 +32,14 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
#ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||||
#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
#define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <am-inlinelist.h>
|
||||||
|
#include <am-refcounting.h>
|
||||||
|
#include <am-utility.h>
|
||||||
|
#include <sm_stringhashmap.h>
|
||||||
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
@ -41,12 +49,7 @@
|
|||||||
#include <IAdminSystem.h>
|
#include <IAdminSystem.h>
|
||||||
#include "concmd_cleaner.h"
|
#include "concmd_cleaner.h"
|
||||||
#include "GameHooks.h"
|
#include "GameHooks.h"
|
||||||
#include <am-autoptr.h>
|
#include <sm_namehashset.h>
|
||||||
#include <sm_stringhashmap.h>
|
|
||||||
#include <am-utility.h>
|
|
||||||
#include <am-inlinelist.h>
|
|
||||||
#include <am-linkedlist.h>
|
|
||||||
#include <am-refcounting.h>
|
|
||||||
|
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
|
|
||||||
@ -55,7 +58,7 @@ struct ConCmdInfo;
|
|||||||
|
|
||||||
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
struct CommandGroup : public ke::Refcounted<CommandGroup>
|
||||||
{
|
{
|
||||||
ke::LinkedList<CmdHook *> hooks;
|
std::list<CmdHook *> hooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AdminCmdInfo
|
struct AdminCmdInfo
|
||||||
@ -78,10 +81,11 @@ struct CmdHook : public ke::InlineListNode<CmdHook>
|
|||||||
Client
|
Client
|
||||||
};
|
};
|
||||||
|
|
||||||
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description)
|
CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description, IPlugin *plugin)
|
||||||
: type(type),
|
: type(type),
|
||||||
info(cmd),
|
info(cmd),
|
||||||
pf(fun),
|
pf(fun),
|
||||||
|
plugin(plugin),
|
||||||
helptext(description)
|
helptext(description)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -89,8 +93,9 @@ struct CmdHook : public ke::InlineListNode<CmdHook>
|
|||||||
Type type;
|
Type type;
|
||||||
ConCmdInfo *info;
|
ConCmdInfo *info;
|
||||||
IPluginFunction *pf; /* function hook */
|
IPluginFunction *pf; /* function hook */
|
||||||
ke::AString helptext; /* help text */
|
IPlugin *plugin; /* owning plugin */
|
||||||
ke::AutoPtr<AdminCmdInfo> admin; /* admin requirements, if any */
|
std::string helptext; /* help text */
|
||||||
|
std::unique_ptr<AdminCmdInfo> admin; /* admin requirements, if any */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ke::InlineList<CmdHook> CmdHookList;
|
typedef ke::InlineList<CmdHook> CmdHookList;
|
||||||
@ -104,12 +109,32 @@ struct ConCmdInfo
|
|||||||
pCmd = nullptr;
|
pCmd = nullptr;
|
||||||
eflags = 0;
|
eflags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
bool sourceMod; /**< Determines whether or not concmd was created by a SourceMod plugin */
|
||||||
ConCommand *pCmd; /**< Pointer to the command itself */
|
ConCommand *pCmd; /**< Pointer to the command itself */
|
||||||
CmdHookList hooks; /**< Hook list */
|
CmdHookList hooks; /**< Hook list */
|
||||||
FlagBits eflags; /**< Effective admin flags */
|
FlagBits eflags; /**< Effective admin flags */
|
||||||
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
|
ke::RefPtr<CommandHook> sh_hook; /**< SourceHook hook, if any. */
|
||||||
IPlugin *pPlugin; /**< Owning plugin handle. */
|
IPlugin *pPlugin; /**< Owning plugin handle. */
|
||||||
|
|
||||||
|
struct ConCmdPolicy
|
||||||
|
{
|
||||||
|
static inline bool matches(const char *name, ConCmdInfo *info)
|
||||||
|
{
|
||||||
|
const char *conCmdChars = info->pCmd->GetName();
|
||||||
|
|
||||||
|
std::string concmdName = ke::Lowercase(conCmdChars);
|
||||||
|
std::string input = ke::Lowercase(name);
|
||||||
|
|
||||||
|
return concmdName == input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
|
{
|
||||||
|
std::string lower = ke::Lowercase(key.c_str());
|
||||||
|
return detail::CharsAndLength(lower.c_str()).hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef List<ConCmdInfo *> ConCmdList;
|
typedef List<ConCmdInfo *> ConCmdList;
|
||||||
@ -153,11 +178,6 @@ private:
|
|||||||
void AddToCmdList(ConCmdInfo *info);
|
void AddToCmdList(ConCmdInfo *info);
|
||||||
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
|
void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack);
|
||||||
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
|
||||||
|
|
||||||
// Case insensitive
|
|
||||||
ConCmdList::iterator FindInList(const char *name);
|
|
||||||
|
|
||||||
// Case sensitive
|
|
||||||
ConCmdInfo *FindInTrie(const char *name);
|
ConCmdInfo *FindInTrie(const char *name);
|
||||||
public:
|
public:
|
||||||
inline const List<ConCmdInfo *> & GetCommandList()
|
inline const List<ConCmdInfo *> & GetCommandList()
|
||||||
@ -167,7 +187,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap;
|
typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap;
|
||||||
|
|
||||||
StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */
|
NameHashSet<ConCmdInfo *, ConCmdInfo::ConCmdPolicy> m_Cmds; /* command lookup */
|
||||||
GroupMap m_CmdGrps; /* command group map */
|
GroupMap m_CmdGrps; /* command group map */
|
||||||
ConCmdList m_CmdList; /* command list */
|
ConCmdList m_CmdList; /* command list */
|
||||||
};
|
};
|
||||||
|
|||||||
@ -41,7 +41,11 @@ ConVarManager g_ConVarManager;
|
|||||||
|
|
||||||
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
||||||
typedef List<const ConVar *> ConVarList;
|
typedef List<const ConVar *> ConVarList;
|
||||||
NameHashSet<ConVarInfo *> convar_cache;
|
NameHashSet<ConVarInfo *, ConVarInfo::ConVarPolicy> convar_cache;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
eQueryCvarValueStatus_Cancelled = -1,
|
||||||
|
};
|
||||||
|
|
||||||
class ConVarReentrancyGuard
|
class ConVarReentrancyGuard
|
||||||
{
|
{
|
||||||
@ -206,18 +210,27 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
|||||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||||
{
|
{
|
||||||
ConVarList *pConVarList;
|
ConVarList *pConVarList;
|
||||||
List<ConVarQuery>::iterator iter;
|
|
||||||
|
|
||||||
/* If plugin has a convar list, free its memory */
|
/* If plugin has a convar list, free its memory */
|
||||||
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
||||||
{
|
{
|
||||||
delete pConVarList;
|
delete pConVarList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear any references to this plugin as the convar creator */
|
||||||
|
for (List<ConVarInfo *>::iterator iter = m_ConVars.begin(); iter != m_ConVars.end(); ++iter)
|
||||||
|
{
|
||||||
|
ConVarInfo *pInfo = (*iter);
|
||||||
|
|
||||||
|
if (pInfo->pPlugin == plugin)
|
||||||
|
{
|
||||||
|
pInfo->pPlugin = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
||||||
|
|
||||||
/* Remove convar queries for this plugin that haven't returned results yet */
|
/* Remove convar queries for this plugin that haven't returned results yet */
|
||||||
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||||
{
|
{
|
||||||
ConVarQuery &query = (*iter);
|
ConVarQuery &query = (*iter);
|
||||||
if (query.pCallback->GetParentRuntime() == pRuntime)
|
if (query.pCallback->GetParentRuntime() == pRuntime)
|
||||||
@ -238,6 +251,19 @@ void ConVarManager::OnClientDisconnected(int client)
|
|||||||
ConVarQuery &query = (*iter);
|
ConVarQuery &query = (*iter);
|
||||||
if (query.client == client)
|
if (query.client == client)
|
||||||
{
|
{
|
||||||
|
IPluginFunction *pCallback = query.pCallback;
|
||||||
|
if (pCallback)
|
||||||
|
{
|
||||||
|
cell_t ret;
|
||||||
|
|
||||||
|
pCallback->PushCell(query.cookie);
|
||||||
|
pCallback->PushCell(client);
|
||||||
|
pCallback->PushCell(eQueryCvarValueStatus_Cancelled);
|
||||||
|
pCallback->PushString("");
|
||||||
|
pCallback->PushString("");
|
||||||
|
pCallback->PushCell(query.value);
|
||||||
|
pCallback->Execute(&ret);
|
||||||
|
}
|
||||||
iter = m_ConVarQueries.erase(iter);
|
iter = m_ConVarQueries.erase(iter);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -330,6 +356,8 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
ConVarInfo *pInfo = NULL;
|
ConVarInfo *pInfo = NULL;
|
||||||
Handle_t hndl = 0;
|
Handle_t hndl = 0;
|
||||||
|
|
||||||
|
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
||||||
|
|
||||||
/* Find out if the convar exists already */
|
/* Find out if the convar exists already */
|
||||||
pConVar = icvar->FindVar(name);
|
pConVar = icvar->FindVar(name);
|
||||||
|
|
||||||
@ -337,11 +365,16 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
if (pConVar)
|
if (pConVar)
|
||||||
{
|
{
|
||||||
/* Add convar to plugin's list */
|
/* Add convar to plugin's list */
|
||||||
AddConVarToPluginList(pContext, pConVar);
|
AddConVarToPluginList(plugin, pConVar);
|
||||||
|
|
||||||
/* First find out if we already have a handle to it */
|
/* First find out if we already have a handle to it */
|
||||||
if (convar_cache_lookup(name, &pInfo))
|
if (convar_cache_lookup(name, &pInfo))
|
||||||
{
|
{
|
||||||
|
/* If the convar doesn't have an owning plugin, but SM created it, adopt it */
|
||||||
|
if (pInfo->sourceMod && pInfo->pPlugin == nullptr) {
|
||||||
|
pInfo->pPlugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
return pInfo->handle;
|
return pInfo->handle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -382,6 +415,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
pInfo->handle = hndl;
|
pInfo->handle = hndl;
|
||||||
pInfo->sourceMod = true;
|
pInfo->sourceMod = true;
|
||||||
pInfo->pChangeForward = NULL;
|
pInfo->pChangeForward = NULL;
|
||||||
|
pInfo->pPlugin = plugin;
|
||||||
|
|
||||||
/* Create a handle from the new convar */
|
/* Create a handle from the new convar */
|
||||||
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||||
@ -398,7 +432,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
|||||||
pInfo->pVar = pConVar;
|
pInfo->pVar = pConVar;
|
||||||
|
|
||||||
/* Add convar to plugin's list */
|
/* Add convar to plugin's list */
|
||||||
AddConVarToPluginList(pContext, pConVar);
|
AddConVarToPluginList(plugin, pConVar);
|
||||||
|
|
||||||
/* Insert struct into caches */
|
/* Insert struct into caches */
|
||||||
m_ConVars.push_back(pInfo);
|
m_ConVars.push_back(pInfo);
|
||||||
@ -552,15 +586,13 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
|
|||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar)
|
void ConVarManager::AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar)
|
||||||
{
|
{
|
||||||
ConVarList *pConVarList;
|
ConVarList *pConVarList;
|
||||||
ConVarList::iterator iter;
|
ConVarList::iterator iter;
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
const char *orig = pConVar->GetName();
|
const char *orig = pConVar->GetName();
|
||||||
|
|
||||||
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
|
||||||
|
|
||||||
/* Check plugin for an existing convar list */
|
/* Check plugin for an existing convar list */
|
||||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||||
{
|
{
|
||||||
@ -679,7 +711,7 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin)
|
||||||
{
|
{
|
||||||
ConVarInfo *pInfo;
|
ConVarInfo *pInfo;
|
||||||
HandleError error;
|
HandleError error;
|
||||||
@ -694,5 +726,10 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
|||||||
*pVar = pInfo->pVar;
|
*pVar = pInfo->pVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ppPlugin)
|
||||||
|
{
|
||||||
|
*ppPlugin = pInfo->pPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,16 +62,27 @@ struct ConVarInfo
|
|||||||
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
|
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
|
||||||
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
||||||
ConVar *pVar; /**< The actual convar */
|
ConVar *pVar; /**< The actual convar */
|
||||||
|
IPlugin *pPlugin; /**< Originally owning plugin */
|
||||||
List<IConVarChangeListener *> changeListeners;
|
List<IConVarChangeListener *> changeListeners;
|
||||||
|
|
||||||
static inline bool matches(const char *name, const ConVarInfo *info)
|
struct ConVarPolicy
|
||||||
{
|
{
|
||||||
return strcmp(name, info->pVar->GetName()) == 0;
|
static inline bool matches(const char *name, ConVarInfo *info)
|
||||||
}
|
{
|
||||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
const char *conVarChars = info->pVar->GetName();
|
||||||
{
|
|
||||||
return key.hash();
|
std::string convarName = ke::Lowercase(conVarChars);
|
||||||
}
|
std::string input = ke::Lowercase(name);
|
||||||
|
|
||||||
|
return convarName == input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
|
{
|
||||||
|
std::string lower = ke::Lowercase(key.c_str());
|
||||||
|
return detail::CharsAndLength(lower.c_str()).hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,7 +155,7 @@ public:
|
|||||||
|
|
||||||
bool IsQueryingSupported();
|
bool IsQueryingSupported();
|
||||||
|
|
||||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
|
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin = nullptr);
|
||||||
|
|
||||||
// Called via game hooks.
|
// Called via game hooks.
|
||||||
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||||
@ -161,7 +172,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Adds a convar to a plugin's list.
|
* Adds a convar to a plugin's list.
|
||||||
*/
|
*/
|
||||||
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
|
static void AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar);
|
||||||
private:
|
private:
|
||||||
HandleType_t m_ConVarType;
|
HandleType_t m_ConVarType;
|
||||||
List<ConVarInfo *> m_ConVars;
|
List<ConVarInfo *> m_ConVars;
|
||||||
|
|||||||
@ -307,7 +307,7 @@ bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
|
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||||
IChangeableForward *forward;
|
IChangeableForward *forward;
|
||||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||||
{
|
{
|
||||||
@ -329,7 +329,7 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command));
|
std::unique_ptr<char[]> str(UTIL_ToLowerCase(command));
|
||||||
IChangeableForward *forward;
|
IChangeableForward *forward;
|
||||||
if (!m_Listeners.retrieve(str.get(), &forward))
|
if (!m_Listeners.retrieve(str.get(), &forward))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -290,18 +290,18 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
|
|||||||
pBase = pBase->m_pGlobalClassNext;
|
pBase = pBase->m_pGlobalClassNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::AString vstr(value);
|
std::string vstr(value);
|
||||||
m_KeyValues.replace(option, ke::Move(vstr));
|
m_KeyValues.replace(option, std::move(vstr));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
const char *CoreConfig::GetCoreConfigValue(const char *key)
|
||||||
{
|
{
|
||||||
StringHashMap<ke::AString>::Result r = m_KeyValues.find(key);
|
StringHashMap<std::string>::Result r = m_KeyValues.find(key);
|
||||||
if (!r.found())
|
if (!r.found())
|
||||||
return NULL;
|
return NULL;
|
||||||
return r->value.chars();
|
return r->value.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SM_AreConfigsExecuted()
|
bool SM_AreConfigsExecuted()
|
||||||
|
|||||||
@ -68,7 +68,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
|
||||||
private:
|
private:
|
||||||
StringHashMap<ke::AString> m_KeyValues;
|
StringHashMap<std::string> m_KeyValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool SM_AreConfigsExecuted();
|
extern bool SM_AreConfigsExecuted();
|
||||||
|
|||||||
@ -484,7 +484,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
pForward->PushCell(BAD_HANDLE);
|
pForward->PushCell(BAD_HANDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pForward->PushString(pHook->name.chars());
|
pForward->PushString(pHook->name.c_str());
|
||||||
pForward->PushCell(bDontBroadcast);
|
pForward->PushCell(bDontBroadcast);
|
||||||
pForward->Execute(NULL);
|
pForward->Execute(NULL);
|
||||||
|
|
||||||
@ -505,7 +505,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
|
|||||||
{
|
{
|
||||||
assert(pHook->pPostHook == NULL);
|
assert(pHook->pPostHook == NULL);
|
||||||
assert(pHook->pPreHook == NULL);
|
assert(pHook->pPreHook == NULL);
|
||||||
m_EventHooks.remove(pHook->name.chars());
|
m_EventHooks.remove(pHook->name.c_str());
|
||||||
delete pHook;
|
delete pHook;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,11 +71,11 @@ struct EventHook
|
|||||||
IChangeableForward *pPostHook;
|
IChangeableForward *pPostHook;
|
||||||
bool postCopy;
|
bool postCopy;
|
||||||
unsigned int refCount;
|
unsigned int refCount;
|
||||||
ke::AString name;
|
std::string name;
|
||||||
|
|
||||||
static inline bool matches(const char *name, const EventHook *hook)
|
static inline bool matches(const char *name, const EventHook *hook)
|
||||||
{
|
{
|
||||||
return strcmp(name, hook->name.chars()) == 0;
|
return strcmp(name, hook->name.c_str()) == 0;
|
||||||
}
|
}
|
||||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -91,7 +91,7 @@ void GameHooks::OnVSPReceived()
|
|||||||
|
|
||||||
void GameHooks::Shutdown()
|
void GameHooks::Shutdown()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < hooks_.length(); i++)
|
for (size_t i = 0; i < hooks_.size(); i++)
|
||||||
SH_REMOVE_HOOK_ID(hooks_[i]);
|
SH_REMOVE_HOOK_ID(hooks_[i]);
|
||||||
hooks_.clear();
|
hooks_.clear();
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla
|
|||||||
const char *cvarName, const char *cvarValue){
|
const char *cvarName, const char *cvarValue){
|
||||||
int client = IndexOfEdict(pPlayer);
|
int client = IndexOfEdict(pPlayer);
|
||||||
|
|
||||||
# if SOURCE_ENGINE == SE_CSGO
|
# if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
|
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
|
||||||
return;
|
return;
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
@ -63,7 +63,7 @@ class CommandHook : public ke::Refcounted<CommandHook>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
|
// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
|
||||||
typedef ke::Lambda<bool(int, const ICommandArgs *)> Callback;
|
typedef ke::Function<bool(int, const ICommandArgs *)> Callback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
|
CommandHook(ConCommand *cmd, const Callback &callback, bool post);
|
||||||
@ -114,11 +114,11 @@ private:
|
|||||||
void SetCommandClient(int client);
|
void SetCommandClient(int client);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class HookList : public ke::Vector<int>
|
class HookList : public std::vector<int>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HookList &operator += (int hook_id) {
|
HookList &operator += (int hook_id) {
|
||||||
this->append(hook_id);
|
this->push_back(hook_id);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -45,9 +45,12 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
#include <cstrike15_usermessages.pb.h>
|
#include <cstrike15_usermessages.pb.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
#include <berimbau_usermessages.pb.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
#include <vietnam_usermessages.pb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef ICommandLine *(*FakeGetCommandLine)();
|
typedef ICommandLine *(*FakeGetCommandLine)();
|
||||||
|
|
||||||
#define TIER0_NAME FORMAT_SOURCE_BIN_NAME("tier0")
|
#define TIER0_NAME FORMAT_SOURCE_BIN_NAME("tier0")
|
||||||
@ -59,6 +62,7 @@ ConVar *sv_lan = NULL;
|
|||||||
static void *g_EntList = NULL;
|
static void *g_EntList = NULL;
|
||||||
static void **g_pEntInfoList = NULL;
|
static void **g_pEntInfoList = NULL;
|
||||||
static int entInfoOffset = -1;
|
static int entInfoOffset = -1;
|
||||||
|
static int utlVecOffsetOffset = -1;
|
||||||
|
|
||||||
static CEntInfo *EntInfoArray()
|
static CEntInfo *EntInfoArray()
|
||||||
{
|
{
|
||||||
@ -143,6 +147,7 @@ void CHalfLife2::OnSourceModAllInitialized_Post()
|
|||||||
m_CSGOBadList.add("m_nActiveCoinRank");
|
m_CSGOBadList.add("m_nActiveCoinRank");
|
||||||
m_CSGOBadList.add("m_nMusicID");
|
m_CSGOBadList.add("m_nMusicID");
|
||||||
#endif
|
#endif
|
||||||
|
g_pGameConf->GetOffset("CSendPropExtra_UtlVector::m_Offset", &utlVecOffsetOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult CHalfLife2::OnSourceModConfigChanged(const char *key, const char *value,
|
ConfigResult CHalfLife2::OnSourceModConfigChanged(const char *key, const char *value,
|
||||||
@ -180,7 +185,9 @@ void CHalfLife2::InitLogicalEntData()
|
|||||||
|| SOURCE_ENGINE == SE_CSS \
|
|| SOURCE_ENGINE == SE_CSS \
|
||||||
|| SOURCE_ENGINE == SE_SDK2013 \
|
|| SOURCE_ENGINE == SE_SDK2013 \
|
||||||
|| SOURCE_ENGINE == SE_BMS \
|
|| SOURCE_ENGINE == SE_BMS \
|
||||||
|| SOURCE_ENGINE == SE_NUCLEARDAWN
|
|| SOURCE_ENGINE == SE_BLADE \
|
||||||
|
|| SOURCE_ENGINE == SE_NUCLEARDAWN \
|
||||||
|
|| SOURCE_ENGINE == SE_PVKII
|
||||||
|
|
||||||
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
|
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
|
||||||
{
|
{
|
||||||
@ -317,23 +324,41 @@ bool UTIL_FindInSendTable(SendTable *pTable,
|
|||||||
sm_sendprop_info_t *info,
|
sm_sendprop_info_t *info,
|
||||||
unsigned int offset)
|
unsigned int offset)
|
||||||
{
|
{
|
||||||
const char *pname;
|
|
||||||
int props = pTable->GetNumProps();
|
int props = pTable->GetNumProps();
|
||||||
SendProp *prop;
|
for (int i = 0; i < props; i++)
|
||||||
|
|
||||||
for (int i=0; i<props; i++)
|
|
||||||
{
|
{
|
||||||
prop = pTable->GetProp(i);
|
SendProp *prop = pTable->GetProp(i);
|
||||||
pname = prop->GetName();
|
|
||||||
|
// Skip InsideArray props (SendPropArray / SendPropArray2),
|
||||||
|
// we'll find them later by their containing array.
|
||||||
|
if (prop->IsInsideArray()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *pname = prop->GetName();
|
||||||
|
SendTable *pInnerTable = prop->GetDataTable();
|
||||||
|
|
||||||
if (pname && strcmp(name, pname) == 0)
|
if (pname && strcmp(name, pname) == 0)
|
||||||
{
|
{
|
||||||
|
// get true offset of CUtlVector
|
||||||
|
if (utlVecOffsetOffset != -1 && prop->GetOffset() == 0 && pInnerTable && pInnerTable->GetNumProps())
|
||||||
|
{
|
||||||
|
SendProp *pLengthProxy = pInnerTable->GetProp(0);
|
||||||
|
const char *ipname = pLengthProxy->GetName();
|
||||||
|
if (ipname && strcmp(ipname, "lengthproxy") == 0 && pLengthProxy->GetExtraData())
|
||||||
|
{
|
||||||
|
info->prop = prop;
|
||||||
|
info->actual_offset = offset + *reinterpret_cast<size_t *>(reinterpret_cast<intptr_t>(pLengthProxy->GetExtraData()) + utlVecOffsetOffset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
info->prop = prop;
|
info->prop = prop;
|
||||||
info->actual_offset = offset + info->prop->GetOffset();
|
info->actual_offset = offset + info->prop->GetOffset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (prop->GetDataTable())
|
if (pInnerTable)
|
||||||
{
|
{
|
||||||
if (UTIL_FindInSendTable(prop->GetDataTable(),
|
if (UTIL_FindInSendTable(pInnerTable,
|
||||||
name,
|
name,
|
||||||
info,
|
info,
|
||||||
offset + prop->GetOffset())
|
offset + prop->GetOffset())
|
||||||
@ -388,6 +413,17 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
|
|||||||
return pInfo->sc;
|
return pInfo->sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerClass *CHalfLife2::FindEntityServerClass(CBaseEntity *pEntity)
|
||||||
|
{
|
||||||
|
IServerNetworkable* pNetwork = ((IServerUnknown *)pEntity)->GetNetworkable();
|
||||||
|
if (pNetwork == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pNetwork->GetServerClass();
|
||||||
|
}
|
||||||
|
|
||||||
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
|
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
|
||||||
{
|
{
|
||||||
DataTableInfo *pInfo = NULL;
|
DataTableInfo *pInfo = NULL;
|
||||||
@ -420,20 +456,25 @@ bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pInfo->lookup.retrieve(offset, info))
|
DataTableInfo::SendPropInfo temp;
|
||||||
{
|
|
||||||
sm_sendprop_info_t temp_info;
|
|
||||||
|
|
||||||
if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
|
if (!pInfo->lookup.retrieve(offset, &temp))
|
||||||
|
{
|
||||||
|
bool found = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp.info, 0);
|
||||||
|
temp.name = offset;
|
||||||
|
|
||||||
|
pInfo->lookup.insert(offset, temp);
|
||||||
|
|
||||||
|
if (found)
|
||||||
{
|
{
|
||||||
return false;
|
*info = temp.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
pInfo->lookup.insert(offset, temp_info);
|
return found;
|
||||||
*info = temp_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
*info = temp.info;
|
||||||
|
return info->prop != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
|
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
|
||||||
@ -467,15 +508,25 @@ bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatab
|
|||||||
m_Maps.add(i, pMap, new DataMapCache());
|
m_Maps.add(i, pMap, new DataMapCache());
|
||||||
|
|
||||||
DataMapCache *cache = i->value;
|
DataMapCache *cache = i->value;
|
||||||
|
DataMapCacheInfo temp;
|
||||||
|
|
||||||
if (!cache->retrieve(offset, pDataTable))
|
if (!cache->retrieve(offset, &temp))
|
||||||
{
|
{
|
||||||
if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable))
|
bool found = UTIL_FindDataMapInfo(pMap, offset, &temp.info);
|
||||||
return false;
|
temp.name = offset;
|
||||||
cache->insert(offset, *pDataTable);
|
|
||||||
|
cache->insert(offset, temp);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
*pDataTable = temp.info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
*pDataTable = temp.info;
|
||||||
|
return pDataTable->prop != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||||
@ -516,7 +567,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
char buffer[253];
|
char buffer[253];
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
|
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
CCSUsrMsg_SayText *pMsg;
|
CCSUsrMsg_SayText *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -543,7 +594,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
CCSUsrMsg_TextMsg *pMsg;
|
CCSUsrMsg_TextMsg *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -580,7 +631,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
|||||||
{
|
{
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
CCSUsrMsg_HintText *pMsg;
|
CCSUsrMsg_HintText *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -610,7 +661,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
|||||||
|
|
||||||
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
CCSUsrMsg_HintText *pMsg;
|
CCSUsrMsg_HintText *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -645,7 +696,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
cell_t players[] = {client};
|
cell_t players[] = {client};
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
CCSUsrMsg_VGUIMenu *pMsg;
|
CCSUsrMsg_VGUIMenu *pMsg;
|
||||||
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
|
||||||
{
|
{
|
||||||
@ -670,7 +721,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
|
|||||||
SubKey = data->GetFirstSubKey();
|
SubKey = data->GetFirstSubKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
pMsg->set_name(name);
|
pMsg->set_name(name);
|
||||||
pMsg->set_show(show);
|
pMsg->set_show(show);
|
||||||
|
|
||||||
@ -1059,8 +1110,26 @@ int CHalfLife2::ReferenceToIndex(cell_t entRef)
|
|||||||
|
|
||||||
return hndl.GetEntryIndex();
|
return hndl.GetEntryIndex();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CEntInfo *pInfo = LookupEntity(entRef);
|
||||||
|
if (!pInfo)
|
||||||
|
{
|
||||||
|
return INVALID_EHANDLE_INDEX;
|
||||||
|
}
|
||||||
|
IServerUnknown *pUnk = static_cast<IServerUnknown *>(pInfo->m_pEntity);
|
||||||
|
if (!pUnk)
|
||||||
|
{
|
||||||
|
return INVALID_EHANDLE_INDEX;
|
||||||
|
}
|
||||||
|
CBaseEntity *pEntity = pUnk->GetBaseEntity();
|
||||||
|
if (!pEntity)
|
||||||
|
{
|
||||||
|
return INVALID_EHANDLE_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
return entRef;
|
return entRef;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
|
cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
|
||||||
@ -1212,6 +1281,45 @@ bool IsWindowsReservedDeviceName(const char *pMapname)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
|
||||||
|
// This frees memory allocated by the game using the game's CRT on Windows,
|
||||||
|
// avoiding a crash due to heap corruption (issue #910).
|
||||||
|
template< class T, class I >
|
||||||
|
class CUtlMemoryGlobalMalloc : public CUtlMemory< T, I >
|
||||||
|
{
|
||||||
|
typedef CUtlMemory< T, I > BaseClass;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using BaseClass::BaseClass;
|
||||||
|
|
||||||
|
void Purge()
|
||||||
|
{
|
||||||
|
if (!IsExternallyAllocated())
|
||||||
|
{
|
||||||
|
if (m_pMemory)
|
||||||
|
{
|
||||||
|
UTLMEMORY_TRACK_FREE();
|
||||||
|
g_pMemAlloc->Free((void*)m_pMemory);
|
||||||
|
m_pMemory = 0;
|
||||||
|
}
|
||||||
|
m_nAllocationCount = 0;
|
||||||
|
}
|
||||||
|
BaseClass::Purge();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void CHalfLife2::FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec)
|
||||||
|
{
|
||||||
|
CUtlMemoryGlobalMalloc<unsigned char> *pMemory;
|
||||||
|
FOR_EACH_VEC(vec, i)
|
||||||
|
{
|
||||||
|
pMemory = (CUtlMemoryGlobalMalloc<unsigned char> *) &vec[i].m_Storage.m_Memory;
|
||||||
|
pMemory->Purge();
|
||||||
|
vec[i].m_Storage.SetLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax)
|
SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax)
|
||||||
{
|
{
|
||||||
/* We need to ensure user input does not contain reserved device names on windows */
|
/* We need to ensure user input does not contain reserved device names on windows */
|
||||||
@ -1245,8 +1353,13 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
|
|||||||
|
|
||||||
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> results;
|
||||||
|
pHelperCmd->AutoCompleteSuggest(pMapName, *(CUtlVector<CUtlString, CUtlMemory<CUtlString>>*)&results);
|
||||||
|
#else
|
||||||
CUtlVector<CUtlString> results;
|
CUtlVector<CUtlString> results;
|
||||||
pHelperCmd->AutoCompleteSuggest(pMapName, results);
|
pHelperCmd->AutoCompleteSuggest(pMapName, results);
|
||||||
|
#endif
|
||||||
if (results.Count() == 0)
|
if (results.Count() == 0)
|
||||||
return SMFindMapResult::NotFound;
|
return SMFindMapResult::NotFound;
|
||||||
|
|
||||||
@ -1258,16 +1371,22 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
|
|||||||
bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
|
bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
|
||||||
if (bExactMatch)
|
if (bExactMatch)
|
||||||
{
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
FreeUtlVectorUtlString(results);
|
||||||
|
#endif
|
||||||
return SMFindMapResult::Found;
|
return SMFindMapResult::Found;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]);
|
ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]);
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
FreeUtlVectorUtlString(results);
|
||||||
|
#endif
|
||||||
return SMFindMapResult::FuzzyMatch;
|
return SMFindMapResult::FuzzyMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM \
|
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM \
|
||||||
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS
|
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_PVKII
|
||||||
static IVEngineServer *engine23 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer023", nullptr));
|
static IVEngineServer *engine23 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer023", nullptr));
|
||||||
if (engine23)
|
if (engine23)
|
||||||
{
|
{
|
||||||
@ -1316,8 +1435,36 @@ bool CHalfLife2::IsMapValid(const char *map)
|
|||||||
return FindMap(map) == SMFindMapResult::Found;
|
return FindMap(map) == SMFindMapResult::Found;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add ep1 support for this. (No IServerTools available there)
|
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
class VKeyValuesSS_Helper {};
|
||||||
|
static bool VKeyValuesSS(CBaseEntity* pThisPtr, const char *pszKey, const char *pszValue, int offset)
|
||||||
|
{
|
||||||
|
void** this_ptr = *reinterpret_cast<void***>(&pThisPtr);
|
||||||
|
void** vtable = *reinterpret_cast<void***>(pThisPtr);
|
||||||
|
void* vfunc = vtable[offset];
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool (VKeyValuesSS_Helper::* mfpnew)(const char *, const char *);
|
||||||
|
#ifndef PLATFORM_POSIX
|
||||||
|
void* addr;
|
||||||
|
} u;
|
||||||
|
u.addr = vfunc;
|
||||||
|
#else
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
void* addr;
|
||||||
|
intptr_t adjustor;
|
||||||
|
} s;
|
||||||
|
} u;
|
||||||
|
u.s.addr = vfunc;
|
||||||
|
u.s.adjustor = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (bool)(reinterpret_cast<VKeyValuesSS_Helper*>(this_ptr)->*u.mfpnew)(pszKey, pszValue);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
string_t CHalfLife2::AllocPooledString(const char *pszValue)
|
string_t CHalfLife2::AllocPooledString(const char *pszValue)
|
||||||
{
|
{
|
||||||
// This is admittedly a giant hack, but it's a relatively safe method for
|
// This is admittedly a giant hack, but it's a relatively safe method for
|
||||||
@ -1327,28 +1474,58 @@ string_t CHalfLife2::AllocPooledString(const char *pszValue)
|
|||||||
// current targetname string_t, set it to our string to insert via SetKeyValue,
|
// current targetname string_t, set it to our string to insert via SetKeyValue,
|
||||||
// read back the new targetname value, restore the old value, and return the new one.
|
// read back the new targetname value, restore the old value, and return the new one.
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||||
|
CBaseEntity* pEntity = nullptr;
|
||||||
|
for (int i = 0; i < gpGlobals->maxEntities; ++i)
|
||||||
|
{
|
||||||
|
pEntity = ReferenceToEntity(i);
|
||||||
|
if (pEntity)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pEntity)
|
||||||
|
{
|
||||||
|
logger->LogError("Failed to locate a valid entity for AllocPooledString.");
|
||||||
|
return NULL_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity();
|
CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity();
|
||||||
|
#endif
|
||||||
auto *pDataMap = GetDataMap(pEntity);
|
auto *pDataMap = GetDataMap(pEntity);
|
||||||
assert(pDataMap);
|
assert(pDataMap);
|
||||||
|
|
||||||
static int offset = -1;
|
static int iNameOffset = -1;
|
||||||
if (offset == -1)
|
if (iNameOffset == -1)
|
||||||
{
|
{
|
||||||
sm_datatable_info_t info;
|
sm_datatable_info_t info;
|
||||||
bool found = FindDataMapInfo(pDataMap, "m_iName", &info);
|
bool found = FindDataMapInfo(pDataMap, "m_iName", &info);
|
||||||
assert(found);
|
assert(found);
|
||||||
offset = info.actual_offset;
|
iNameOffset = info.actual_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t *pProp = (string_t *) ((intp) pEntity + offset);
|
string_t* pProp = (string_t*)((intp)pEntity + iNameOffset);
|
||||||
string_t backup = *pProp;
|
string_t backup = *pProp;
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE < SE_ORANGEBOX
|
||||||
|
static int iFuncOffset;
|
||||||
|
if (!g_pGameConf->GetOffset("DispatchKeyValue", &iFuncOffset) || !iFuncOffset)
|
||||||
|
{
|
||||||
|
logger->LogError("Failed to locate DispatchKeyValue in core gamedata. AllocPooledString unsupported.");
|
||||||
|
return NULL_STRING;
|
||||||
|
}
|
||||||
|
VKeyValuesSS(pEntity, "targetname", pszValue, iFuncOffset);
|
||||||
|
#else
|
||||||
servertools->SetKeyValue(pEntity, "targetname", pszValue);
|
servertools->SetKeyValue(pEntity, "targetname", pszValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
string_t newString = *pProp;
|
string_t newString = *pProp;
|
||||||
*pProp = backup;
|
*pProp = backup;
|
||||||
|
|
||||||
return newString;
|
return newString;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const
|
bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const
|
||||||
{
|
{
|
||||||
@ -1396,7 +1573,9 @@ uint64_t CHalfLife2::GetServerSteamId64() const
|
|||||||
|| SOURCE_ENGINE == SE_DOI \
|
|| SOURCE_ENGINE == SE_DOI \
|
||||||
|| SOURCE_ENGINE == SE_SDK2013 \
|
|| SOURCE_ENGINE == SE_SDK2013 \
|
||||||
|| SOURCE_ENGINE == SE_ALIENSWARM \
|
|| SOURCE_ENGINE == SE_ALIENSWARM \
|
||||||
|| SOURCE_ENGINE == SE_TF2
|
|| SOURCE_ENGINE == SE_TF2 \
|
||||||
|
|| SOURCE_ENGINE == SE_PVKII \
|
||||||
|
|| SOURCE_ENGINE == SE_MCV
|
||||||
const CSteamID *sid = engine->GetGameServerSteamID();
|
const CSteamID *sid = engine->GetGameServerSteamID();
|
||||||
if (sid)
|
if (sid)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -74,7 +74,7 @@ using namespace SourceMod;
|
|||||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI
|
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI
|
||||||
#define SOURCE_BIN_PREFIX "lib"
|
#define SOURCE_BIN_PREFIX "lib"
|
||||||
#define SOURCE_BIN_SUFFIX "_srv"
|
#define SOURCE_BIN_SUFFIX "_srv"
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD || SOURCE_ENGINE == SE_PVKII
|
||||||
#define SOURCE_BIN_PREFIX "lib"
|
#define SOURCE_BIN_PREFIX "lib"
|
||||||
#define SOURCE_BIN_SUFFIX ""
|
#define SOURCE_BIN_SUFFIX ""
|
||||||
#else
|
#else
|
||||||
@ -89,16 +89,24 @@ using namespace SourceMod;
|
|||||||
|
|
||||||
struct DataTableInfo
|
struct DataTableInfo
|
||||||
{
|
{
|
||||||
struct SendPropPolicy
|
struct SendPropInfo
|
||||||
{
|
{
|
||||||
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
|
static inline bool matches(const char *name, const SendPropInfo &info)
|
||||||
{
|
{
|
||||||
return strcmp(name, info.prop->GetName()) == 0;
|
return strcmp(name, info.name.c_str()) == 0;
|
||||||
}
|
}
|
||||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
{
|
{
|
||||||
return key.hash();
|
return key.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SendPropInfo()
|
||||||
|
: name(), info{nullptr, 0}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
sm_sendprop_info_t info;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool matches(const char *name, const DataTableInfo *info)
|
static inline bool matches(const char *name, const DataTableInfo *info)
|
||||||
@ -116,22 +124,30 @@ struct DataTableInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerClass *sc;
|
ServerClass *sc;
|
||||||
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
|
NameHashSet<SendPropInfo> lookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DataMapCachePolicy
|
struct DataMapCacheInfo
|
||||||
{
|
{
|
||||||
static inline bool matches(const char *name, const sm_datatable_info_t &info)
|
static inline bool matches(const char *name, const DataMapCacheInfo &info)
|
||||||
{
|
{
|
||||||
return strcmp(name, info.prop->fieldName) == 0;
|
return strcmp(name, info.name.c_str()) == 0;
|
||||||
}
|
}
|
||||||
static inline uint32_t hash(const detail::CharsAndLength &key)
|
static inline uint32_t hash(const detail::CharsAndLength &key)
|
||||||
{
|
{
|
||||||
return key.hash();
|
return key.hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataMapCacheInfo()
|
||||||
|
: name(), info{nullptr, 0}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
sm_datatable_info_t info;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
|
typedef NameHashSet<DataMapCacheInfo> DataMapCache;
|
||||||
|
|
||||||
struct DelayedFakeCliCmd
|
struct DelayedFakeCliCmd
|
||||||
{
|
{
|
||||||
@ -179,6 +195,12 @@ enum class SMFindMapResult : cell_t {
|
|||||||
PossiblyAvailable
|
PossiblyAvailable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS
|
||||||
|
template< class T, class I = int >
|
||||||
|
class CUtlMemoryGlobalMalloc;
|
||||||
|
class CUtlString;
|
||||||
|
#endif
|
||||||
|
|
||||||
class CHalfLife2 :
|
class CHalfLife2 :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IGameHelpers
|
public IGameHelpers
|
||||||
@ -199,6 +221,7 @@ public: //IGameHelpers
|
|||||||
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
|
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
|
||||||
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
||||||
ServerClass *FindServerClass(const char *classname);
|
ServerClass *FindServerClass(const char *classname);
|
||||||
|
ServerClass *FindEntityServerClass(CBaseEntity *pEntity);
|
||||||
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);
|
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);
|
||||||
@ -229,10 +252,11 @@ public: //IGameHelpers
|
|||||||
bool IsMapValid(const char *map);
|
bool IsMapValid(const char *map);
|
||||||
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
|
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
|
||||||
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
|
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
|
||||||
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
void FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec);
|
||||||
string_t AllocPooledString(const char *pszValue);
|
|
||||||
#endif
|
#endif
|
||||||
|
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
|
||||||
|
string_t AllocPooledString(const char *pszValue);
|
||||||
bool GetServerSteam3Id(char *pszOut, size_t len) const override;
|
bool GetServerSteam3Id(char *pszOut, size_t len) const override;
|
||||||
uint64_t GetServerSteamId64() const override;
|
uint64_t GetServerSteamId64() const override;
|
||||||
public:
|
public:
|
||||||
@ -271,7 +295,7 @@ public:
|
|||||||
return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName);
|
return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
ke::HashSet<ke::AString, detail::StringHashMapPolicy> m_CSGOBadList;
|
ke::HashSet<std::string, detail::StringHashMapPolicy> m_CSGOBadList;
|
||||||
bool m_bFollowCSGOServerGuidelines = true;
|
bool m_bFollowCSGOServerGuidelines = true;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "MenuStyle_Valve.h"
|
#include "MenuStyle_Valve.h"
|
||||||
|
#include <IGameConfigs.h>
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "logic_bridge.h"
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
@ -68,6 +69,29 @@ void MenuManager::OnSourceModAllInitialized()
|
|||||||
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MenuManager::OnSourceModAllInitialized_Post()
|
||||||
|
{
|
||||||
|
const char* pTmp;
|
||||||
|
|
||||||
|
pTmp = g_pGameConf->GetKeyValue("MenuItemSound");
|
||||||
|
if (nullptr != pTmp)
|
||||||
|
{
|
||||||
|
m_SelectSound = pTmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTmp = g_pGameConf->GetKeyValue("MenuExitSound");
|
||||||
|
if (nullptr != pTmp)
|
||||||
|
{
|
||||||
|
m_ExitSound = pTmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTmp = g_pGameConf->GetKeyValue("MenuExitBackSound");
|
||||||
|
if (nullptr != pTmp)
|
||||||
|
{
|
||||||
|
m_ExitBackSound = pTmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MenuManager::OnSourceModAllShutdown()
|
void MenuManager::OnSourceModAllShutdown()
|
||||||
{
|
{
|
||||||
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
|
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
|
||||||
@ -699,30 +723,9 @@ bool MenuManager::MenuSoundsEnabled()
|
|||||||
return (sm_menu_sounds.GetInt() != 0);
|
return (sm_menu_sounds.GetInt() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
|
std::string *MenuManager::GetMenuSound(ItemSelection sel)
|
||||||
const char *value,
|
|
||||||
ConfigSource source,
|
|
||||||
char *error,
|
|
||||||
size_t maxlength)
|
|
||||||
{
|
{
|
||||||
if (strcmp(key, "MenuItemSound") == 0)
|
std::string *sound = nullptr;
|
||||||
{
|
|
||||||
m_SelectSound.assign(value);
|
|
||||||
return ConfigResult_Accept;
|
|
||||||
} else if (strcmp(key, "MenuExitBackSound") == 0) {
|
|
||||||
m_ExitBackSound.assign(value);
|
|
||||||
return ConfigResult_Accept;
|
|
||||||
} else if (strcmp(key, "MenuExitSound") == 0) {
|
|
||||||
m_ExitSound.assign(value);
|
|
||||||
return ConfigResult_Accept;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConfigResult_Ignore;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *MenuManager::GetMenuSound(ItemSelection sel)
|
|
||||||
{
|
|
||||||
const char *sound = NULL;
|
|
||||||
|
|
||||||
switch (sel)
|
switch (sel)
|
||||||
{
|
{
|
||||||
@ -732,7 +735,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
|||||||
{
|
{
|
||||||
if (m_SelectSound.size() > 0)
|
if (m_SelectSound.size() > 0)
|
||||||
{
|
{
|
||||||
sound = m_SelectSound.c_str();
|
sound = &m_SelectSound;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -740,7 +743,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
|||||||
{
|
{
|
||||||
if (m_ExitBackSound.size() > 0)
|
if (m_ExitBackSound.size() > 0)
|
||||||
{
|
{
|
||||||
sound = m_ExitBackSound.c_str();
|
sound = &m_ExitBackSound;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -748,7 +751,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
|||||||
{
|
{
|
||||||
if (m_ExitSound.size() > 0)
|
if (m_ExitSound.size() > 0)
|
||||||
{
|
{
|
||||||
sound = m_ExitSound.c_str();
|
sound = &m_ExitSound;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,8 +36,8 @@
|
|||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
@ -55,12 +55,8 @@ public:
|
|||||||
MenuManager();
|
MenuManager();
|
||||||
public: //SMGlobalClass
|
public: //SMGlobalClass
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
|
void OnSourceModAllInitialized_Post();
|
||||||
void OnSourceModAllShutdown();
|
void OnSourceModAllShutdown();
|
||||||
ConfigResult OnSourceModConfigChanged(const char *key,
|
|
||||||
const char *value,
|
|
||||||
ConfigSource source,
|
|
||||||
char *error,
|
|
||||||
size_t maxlength);
|
|
||||||
void OnSourceModLevelChange(const char *mapName);
|
void OnSourceModLevelChange(const char *mapName);
|
||||||
public: //IMenuManager
|
public: //IMenuManager
|
||||||
virtual const char *GetInterfaceName()
|
virtual const char *GetInterfaceName()
|
||||||
@ -99,7 +95,7 @@ public:
|
|||||||
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
|
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
|
||||||
public:
|
public:
|
||||||
bool MenuSoundsEnabled();
|
bool MenuSoundsEnabled();
|
||||||
const char *GetMenuSound(ItemSelection sel);
|
std::string *GetMenuSound(ItemSelection sel);
|
||||||
protected:
|
protected:
|
||||||
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
|
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
|
||||||
Handle_t CreateStyleHandle(IMenuStyle *style);
|
Handle_t CreateStyleHandle(IMenuStyle *style);
|
||||||
@ -109,9 +105,9 @@ private:
|
|||||||
CVector<IMenuStyle *> m_Styles;
|
CVector<IMenuStyle *> m_Styles;
|
||||||
HandleType_t m_StyleType;
|
HandleType_t m_StyleType;
|
||||||
HandleType_t m_MenuType;
|
HandleType_t m_MenuType;
|
||||||
String m_SelectSound;
|
std::string m_SelectSound = "";
|
||||||
String m_ExitBackSound;
|
std::string m_ExitBackSound = "";
|
||||||
String m_ExitSound;
|
std::string m_ExitSound = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MenuManager g_Menus;
|
extern MenuManager g_Menus;
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
* 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
|
||||||
@ -36,7 +36,7 @@
|
|||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include "CellRecipientFilter.h"
|
#include "CellRecipientFilter.h"
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
#include "Logger.h"
|
#include <bridge/include/ILogger.h>
|
||||||
#endif
|
#endif
|
||||||
#include "logic_bridge.h"
|
#include "logic_bridge.h"
|
||||||
#include "AutoHandleRooter.h"
|
#include "AutoHandleRooter.h"
|
||||||
@ -59,7 +59,7 @@ Handle_t BaseMenuStyle::GetHandle()
|
|||||||
void BaseMenuStyle::AddClientToWatch(int client)
|
void BaseMenuStyle::AddClientToWatch(int client)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
|
logger->LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
|
||||||
#endif
|
#endif
|
||||||
m_WatchList.push_back(client);
|
m_WatchList.push_back(client);
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ void BaseMenuStyle::AddClientToWatch(int client)
|
|||||||
void BaseMenuStyle::RemoveClientFromWatch(int client)
|
void BaseMenuStyle::RemoveClientFromWatch(int client)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
|
logger->LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
|
||||||
#endif
|
#endif
|
||||||
m_WatchList.remove(client);
|
m_WatchList.remove(client);
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ void BaseMenuStyle::RemoveClientFromWatch(int client)
|
|||||||
void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
|
void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
|
logger->LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
menu_states_t &states = player->states;
|
menu_states_t &states = player->states;
|
||||||
@ -99,7 +99,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool
|
|||||||
|
|
||||||
/* Fire callbacks */
|
/* Fire callbacks */
|
||||||
mh->OnMenuCancel(menu, client, reason);
|
mh->OnMenuCancel(menu, client, reason);
|
||||||
|
|
||||||
/* Only fire end if there's a valid menu */
|
/* Only fire end if there's a valid menu */
|
||||||
if (menu)
|
if (menu)
|
||||||
{
|
{
|
||||||
@ -115,7 +115,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool
|
|||||||
void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
|
logger->LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
|
||||||
#endif
|
#endif
|
||||||
int maxClients = g_Players.GetMaxClients();
|
int maxClients = g_Players.GetMaxClients();
|
||||||
for (int i=1; i<=maxClients; i++)
|
for (int i=1; i<=maxClients; i++)
|
||||||
@ -135,7 +135,7 @@ void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
|
|||||||
bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
|
bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
|
logger->LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
|
||||||
#endif
|
#endif
|
||||||
if (client < 1 || client > g_Players.MaxClients())
|
if (client < 1 || client > g_Players.MaxClients())
|
||||||
{
|
{
|
||||||
@ -191,7 +191,7 @@ MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
|
|||||||
void BaseMenuStyle::OnClientDisconnected(int client)
|
void BaseMenuStyle::OnClientDisconnected(int client)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
|
logger->LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
if (!player->bInMenu)
|
if (!player->bInMenu)
|
||||||
@ -214,7 +214,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
|
logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
|
||||||
m_WatchList.m_Size,
|
m_WatchList.m_Size,
|
||||||
m_WatchList.m_FirstLink,
|
m_WatchList.m_FirstLink,
|
||||||
m_WatchList.m_FreeNodes,
|
m_WatchList.m_FreeNodes,
|
||||||
@ -232,7 +232,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
if (total)
|
if (total)
|
||||||
{
|
{
|
||||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
|
logger->LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
client = do_lookup[i];
|
client = do_lookup[i];
|
||||||
player = GetMenuPlayer(client);
|
player = GetMenuPlayer(client);
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
|
logger->LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
|
||||||
client,
|
client,
|
||||||
player->bInMenu,
|
player->bInMenu,
|
||||||
player->menuHoldTime,
|
player->menuHoldTime,
|
||||||
@ -254,7 +254,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
if (!player->bInMenu || !player->menuHoldTime)
|
if (!player->bInMenu || !player->menuHoldTime)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
|
logger->LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
|
||||||
#endif
|
#endif
|
||||||
m_WatchList.remove(client);
|
m_WatchList.remove(client);
|
||||||
continue;
|
continue;
|
||||||
@ -269,7 +269,7 @@ void BaseMenuStyle::ProcessWatchList()
|
|||||||
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
|
logger->LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
|||||||
ItemSelection type = states.slots[key_press].type;
|
ItemSelection type = states.slots[key_press].type;
|
||||||
|
|
||||||
/* Check if we should play a sound about the type */
|
/* Check if we should play a sound about the type */
|
||||||
if (g_Menus.MenuSoundsEnabled() &&
|
if (g_Menus.MenuSoundsEnabled() &&
|
||||||
(!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
|
(!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
|
||||||
{
|
{
|
||||||
CellRecipientFilter filter;
|
CellRecipientFilter filter;
|
||||||
@ -311,9 +311,9 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
|||||||
clients[0] = client;
|
clients[0] = client;
|
||||||
filter.Initialize(clients, 1);
|
filter.Initialize(clients, 1);
|
||||||
|
|
||||||
const char *sound = g_Menus.GetMenuSound(type);
|
std::string *sound = g_Menus.GetMenuSound(type);
|
||||||
|
|
||||||
if (sound != NULL)
|
if (nullptr != sound && !sound->empty())
|
||||||
{
|
{
|
||||||
edict_t *pEdict = PEntityOfEntIndex(client);
|
edict_t *pEdict = PEntityOfEntIndex(client);
|
||||||
if (pEdict)
|
if (pEdict)
|
||||||
@ -323,23 +323,23 @@ 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
|
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||||
sound,
|
sound->c_str(),
|
||||||
-1,
|
-1,
|
||||||
#endif
|
#endif
|
||||||
sound,
|
sound->c_str(),
|
||||||
VOL_NORM,
|
VOL_NORM,
|
||||||
ATTN_NORM,
|
ATTN_NORM,
|
||||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||||
0,
|
0,
|
||||||
#endif
|
#endif
|
||||||
0,
|
0,
|
||||||
PITCH_NORM,
|
PITCH_NORM,
|
||||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|
||||||
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2
|
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
|
||||||
0,
|
0,
|
||||||
#endif
|
#endif
|
||||||
&pos);
|
&pos);
|
||||||
@ -412,7 +412,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
|
|||||||
bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
|
bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
|
logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
|
||||||
client,
|
client,
|
||||||
menu,
|
menu,
|
||||||
mh,
|
mh,
|
||||||
@ -475,7 +475,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
unsigned int time)
|
unsigned int time)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
|
logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
|
||||||
client,
|
client,
|
||||||
menu,
|
menu,
|
||||||
mh,
|
mh,
|
||||||
@ -487,7 +487,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
|
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
||||||
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
||||||
@ -498,7 +498,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (player->bAutoIgnore)
|
if (player->bAutoIgnore)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
|
||||||
#endif
|
#endif
|
||||||
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
|
||||||
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
mh->OnMenuEnd(menu, MenuEnd_Cancelled);
|
||||||
@ -517,7 +517,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (player->bInMenu)
|
if (player->bInMenu)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
_CancelClientMenu(client, MenuCancel_Interrupted, true);
|
_CancelClientMenu(client, MenuCancel_Interrupted, true);
|
||||||
}
|
}
|
||||||
@ -532,7 +532,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
if (!display)
|
if (!display)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
player->bAutoIgnore = false;
|
player->bAutoIgnore = false;
|
||||||
player->bInMenu = false;
|
player->bInMenu = false;
|
||||||
@ -562,7 +562,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
player->bAutoIgnore = false;
|
player->bAutoIgnore = false;
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
|
logger->LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -571,7 +571,7 @@ bool BaseMenuStyle::DoClientMenu(int client,
|
|||||||
bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
|
logger->LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
|
||||||
#endif
|
#endif
|
||||||
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
CBaseMenuPlayer *player = GetMenuPlayer(client);
|
||||||
menu_states_t &states = player->states;
|
menu_states_t &states = player->states;
|
||||||
@ -581,7 +581,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
|||||||
if (!display)
|
if (!display)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
|
logger->LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
|
||||||
#endif
|
#endif
|
||||||
if (player->menuHoldTime)
|
if (player->menuHoldTime)
|
||||||
{
|
{
|
||||||
@ -598,15 +598,15 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
|||||||
player->bAutoIgnore = false;
|
player->bAutoIgnore = false;
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
|
logger->LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
||||||
m_pStyle(pStyle), 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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -628,49 +628,49 @@ Handle_t CBaseMenu::GetHandle()
|
|||||||
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
|
||||||
{
|
{
|
||||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
if (m_Pagination == (unsigned)MENU_NO_PAGINATION
|
||||||
&& m_items.length() >= m_pStyle->GetMaxPageItems())
|
&& m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CItem item(m_items.length());
|
CItem item(m_items.size());
|
||||||
|
|
||||||
item.info = info;
|
item.info = info;
|
||||||
if (draw.display)
|
if (draw.display)
|
||||||
item.display = new ke::AString(draw.display);
|
item.display = std::make_unique<std::string>(draw.display);
|
||||||
item.style = draw.style;
|
item.style = draw.style;
|
||||||
|
|
||||||
m_items.append(ke::Move(item));
|
m_items.push_back(std::move(item));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
|
||||||
{
|
{
|
||||||
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
|
if (m_Pagination == (unsigned)MENU_NO_PAGINATION &&
|
||||||
m_items.length() >= m_pStyle->GetMaxPageItems())
|
m_items.size() >= m_pStyle->GetMaxPageItems())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position >= m_items.length())
|
if (position >= m_items.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CItem item(position);
|
CItem item(position);
|
||||||
item.info = info;
|
item.info = info;
|
||||||
if (draw.display)
|
if (draw.display)
|
||||||
item.display = new ke::AString(draw.display);
|
item.display = std::make_unique<std::string>(draw.display);
|
||||||
item.style = draw.style;
|
item.style = draw.style;
|
||||||
|
|
||||||
m_items.insert(position, ke::Move(item));
|
m_items.emplace(m_items.begin() + position, std::move(item));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::RemoveItem(unsigned int position)
|
bool CBaseMenu::RemoveItem(unsigned int position)
|
||||||
{
|
{
|
||||||
if (position >= m_items.length())
|
if (position >= m_items.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_items.remove(position);
|
m_items.erase(m_items.begin() + position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,21 +681,77 @@ void CBaseMenu::RemoveAllItems()
|
|||||||
|
|
||||||
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
|
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
|
||||||
{
|
{
|
||||||
if (position >= m_items.length())
|
if (position >= m_items.size())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (client > 0 && position < m_RandomMaps[client].length())
|
if (client > 0 && position < m_RandomMaps[client].size())
|
||||||
{
|
{
|
||||||
position = m_RandomMaps[client][position];
|
position = m_RandomMaps[client][position];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draw)
|
if (draw)
|
||||||
{
|
{
|
||||||
draw->display = m_items[position].display->chars();
|
draw->display = m_items[position].display->c_str();
|
||||||
draw->style = m_items[position].style;
|
draw->style = m_items[position].style;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_items[position].info.chars();
|
return m_items[position].info.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBaseMenu::ShufflePerClient(int start, int stop)
|
||||||
|
{
|
||||||
|
// limit map len to 255 items since it's using uint8
|
||||||
|
int length = MIN(GetItemCount(), 255);
|
||||||
|
if (stop >= 0)
|
||||||
|
length = MIN(length, stop);
|
||||||
|
|
||||||
|
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
// populate per-client map ...
|
||||||
|
m_RandomMaps[i].resize(length);
|
||||||
|
for (int j = 0; j < length; j++)
|
||||||
|
m_RandomMaps[i][j] = j;
|
||||||
|
|
||||||
|
// ... and random shuffle it
|
||||||
|
for (int j = length - 1; j > start; j--)
|
||||||
|
{
|
||||||
|
int x = rand() % (j - start + 1) + start;
|
||||||
|
uint8_t tmp = m_RandomMaps[i][x];
|
||||||
|
m_RandomMaps[i][x] = m_RandomMaps[i][j];
|
||||||
|
m_RandomMaps[i][j] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBaseMenu::SetClientMapping(int client, int *array, int length)
|
||||||
|
{
|
||||||
|
length = MIN(length, 255);
|
||||||
|
m_RandomMaps[client].resize(length);
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
m_RandomMaps[client][i] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBaseMenu::IsPerClientShuffled()
|
||||||
|
{
|
||||||
|
for (int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if(m_RandomMaps[i].size() > 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
||||||
|
{
|
||||||
|
if (client > 0 && position < m_RandomMaps[client].size())
|
||||||
|
{
|
||||||
|
position = m_RandomMaps[client][position];
|
||||||
|
return m_items[position].index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBaseMenu::ShufflePerClient(int start, int stop)
|
void CBaseMenu::ShufflePerClient(int start, int stop)
|
||||||
@ -756,7 +812,7 @@ unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
|
|||||||
|
|
||||||
unsigned int CBaseMenu::GetItemCount()
|
unsigned int CBaseMenu::GetItemCount()
|
||||||
{
|
{
|
||||||
return m_items.length();
|
return m_items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
|
||||||
@ -794,7 +850,7 @@ void CBaseMenu::SetDefaultTitle(const char *message)
|
|||||||
|
|
||||||
const char *CBaseMenu::GetDefaultTitle()
|
const char *CBaseMenu::GetDefaultTitle()
|
||||||
{
|
{
|
||||||
return m_Title.chars();
|
return m_Title.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBaseMenu::Cancel()
|
void CBaseMenu::Cancel()
|
||||||
@ -805,7 +861,7 @@ void CBaseMenu::Cancel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
logger->LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
||||||
this,
|
this,
|
||||||
m_bShouldDelete);
|
m_bShouldDelete);
|
||||||
#endif
|
#endif
|
||||||
@ -829,7 +885,7 @@ void CBaseMenu::Destroy(bool releaseHandle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
|
logger->LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
|
||||||
this,
|
this,
|
||||||
releaseHandle,
|
releaseHandle,
|
||||||
m_bCancelling,
|
m_bCancelling,
|
||||||
@ -886,5 +942,5 @@ IMenuHandler *CBaseMenu::GetHandler()
|
|||||||
|
|
||||||
unsigned int CBaseMenu::GetBaseMemUsage()
|
unsigned int CBaseMenu::GetBaseMemUsage()
|
||||||
{
|
{
|
||||||
return m_Title.length() + (m_items.length() * sizeof(CItem));
|
return m_Title.size() + (m_items.size() * sizeof(CItem));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
* 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
|
||||||
@ -32,9 +32,11 @@
|
|||||||
#ifndef _INCLUDE_MENUSTYLE_BASE_H
|
#ifndef _INCLUDE_MENUSTYLE_BASE_H
|
||||||
#define _INCLUDE_MENUSTYLE_BASE_H
|
#define _INCLUDE_MENUSTYLE_BASE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <IMenuManager.h>
|
#include <IMenuManager.h>
|
||||||
#include <IPlayerHelpers.h>
|
#include <IPlayerHelpers.h>
|
||||||
#include <am-autoptr.h>
|
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include "sm_fastlink.h"
|
#include "sm_fastlink.h"
|
||||||
@ -51,8 +53,8 @@ public:
|
|||||||
access = 0;
|
access = 0;
|
||||||
}
|
}
|
||||||
CItem(CItem &&other)
|
CItem(CItem &&other)
|
||||||
: info(ke::Move(other.info)),
|
: info(std::move(other.info)),
|
||||||
display(ke::Move(other.display))
|
display(std::move(other.display))
|
||||||
{
|
{
|
||||||
index = other.index;
|
index = other.index;
|
||||||
style = other.style;
|
style = other.style;
|
||||||
@ -61,8 +63,8 @@ public:
|
|||||||
CItem & operator =(CItem &&other)
|
CItem & operator =(CItem &&other)
|
||||||
{
|
{
|
||||||
index = other.index;
|
index = other.index;
|
||||||
info = ke::Move(other.info);
|
info = std::move(other.info);
|
||||||
display = ke::Move(other.display);
|
display = std::move(other.display);
|
||||||
style = other.style;
|
style = other.style;
|
||||||
access = other.access;
|
access = other.access;
|
||||||
return *this;
|
return *this;
|
||||||
@ -70,8 +72,8 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
ke::AString info;
|
std::string info;
|
||||||
ke::AutoPtr<ke::AString> display;
|
std::unique_ptr<std::string> display;
|
||||||
unsigned int style;
|
unsigned int style;
|
||||||
unsigned int access;
|
unsigned int access;
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ public:
|
|||||||
|
|
||||||
class CBaseMenu;
|
class CBaseMenu;
|
||||||
|
|
||||||
class BaseMenuStyle :
|
class BaseMenuStyle :
|
||||||
public IMenuStyle,
|
public IMenuStyle,
|
||||||
public IClientListener
|
public IClientListener
|
||||||
{
|
{
|
||||||
@ -111,11 +113,11 @@ public: //IClientListener
|
|||||||
public: //what derived must implement
|
public: //what derived must implement
|
||||||
virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0;
|
virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0;
|
||||||
virtual void SendDisplay(int client, IMenuPanel *display) =0;
|
virtual void SendDisplay(int client, IMenuPanel *display) =0;
|
||||||
public: //what derived may implement
|
public: //what derived may implement
|
||||||
virtual bool DoClientMenu(int client,
|
virtual bool DoClientMenu(int client,
|
||||||
CBaseMenu *menu,
|
CBaseMenu *menu,
|
||||||
unsigned int first_item,
|
unsigned int first_item,
|
||||||
IMenuHandler *mh,
|
IMenuHandler *mh,
|
||||||
unsigned int time);
|
unsigned int time);
|
||||||
virtual bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time);
|
virtual bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time);
|
||||||
virtual void AddClientToWatch(int client);
|
virtual void AddClientToWatch(int client);
|
||||||
@ -164,10 +166,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
void InternalDelete();
|
void InternalDelete();
|
||||||
protected:
|
protected:
|
||||||
ke::AString m_Title;
|
std::string m_Title;
|
||||||
IMenuStyle *m_pStyle;
|
IMenuStyle *m_pStyle;
|
||||||
unsigned int m_Pagination;
|
unsigned int m_Pagination;
|
||||||
ke::Vector<CItem> m_items;
|
std::vector<CItem> m_items;
|
||||||
bool m_bShouldDelete;
|
bool m_bShouldDelete;
|
||||||
bool m_bCancelling;
|
bool m_bCancelling;
|
||||||
IdentityToken_t *m_pOwner;
|
IdentityToken_t *m_pOwner;
|
||||||
@ -176,7 +178,7 @@ protected:
|
|||||||
Handle_t m_hHandle;
|
Handle_t m_hHandle;
|
||||||
IMenuHandler *m_pHandler;
|
IMenuHandler *m_pHandler;
|
||||||
unsigned int m_nFlags;
|
unsigned int m_nFlags;
|
||||||
ke::Vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
|
std::vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_MENUSTYLE_BASE_H
|
#endif //_INCLUDE_MENUSTYLE_BASE_H
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
#include <IGameConfigs.h>
|
#include <IGameConfigs.h>
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
#include "Logger.h"
|
#include <bridge/include/ILogger.h>
|
||||||
#endif
|
#endif
|
||||||
#include "logic_bridge.h"
|
#include "logic_bridge.h"
|
||||||
|
|
||||||
@ -45,6 +45,10 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
|
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
#include <game/shared/berimbau/protobuf/berimbau_usermessages.pb.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
#include <game/shared/vietnam/protobuf/vietnam_usermessages.pb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const char *g_RadioNumTable[];
|
extern const char *g_RadioNumTable[];
|
||||||
@ -59,7 +63,7 @@ unsigned int g_RadioMenuTimeout = 0;
|
|||||||
#define MAX_MENUSLOT_KEYS 10
|
#define MAX_MENUSLOT_KEYS 10
|
||||||
|
|
||||||
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS;
|
||||||
|
static bool s_RadioClosesOnInvalidSlot = false;
|
||||||
|
|
||||||
CRadioStyle::CRadioStyle()
|
CRadioStyle::CRadioStyle()
|
||||||
{
|
{
|
||||||
@ -122,6 +126,12 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *closes = g_pGameConf->GetKeyValue("RadioMenuClosesOnInvalidSlot");
|
||||||
|
if (closes != nullptr && strcmp(closes, "yes") == 0)
|
||||||
|
{
|
||||||
|
s_RadioClosesOnInvalidSlot = true;
|
||||||
|
}
|
||||||
|
|
||||||
g_Menus.SetDefaultStyle(this);
|
g_Menus.SetDefaultStyle(this);
|
||||||
|
|
||||||
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
|
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
|
||||||
@ -174,7 +184,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
|
|||||||
{
|
{
|
||||||
int count = pFilter->GetRecipientCount();
|
int count = pFilter->GetRecipientCount();
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
|
||||||
#else
|
#else
|
||||||
bf_read br(bf->GetBasePointer(), 3);
|
bf_read br(bf->GetBasePointer(), 3);
|
||||||
@ -197,7 +207,7 @@ void CRadioStyle::OnUserMessageSent(int msg_id)
|
|||||||
{
|
{
|
||||||
int client = g_last_clients[i];
|
int client = g_last_clients[i];
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
logger->LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
||||||
client,
|
client,
|
||||||
m_players[client].bInExternMenu);
|
m_players[client].bInExternMenu);
|
||||||
#endif
|
#endif
|
||||||
@ -462,7 +472,16 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
|||||||
sizeof(display_pkt),
|
sizeof(display_pkt),
|
||||||
text);
|
text);
|
||||||
}
|
}
|
||||||
display_keys = keys;
|
|
||||||
|
// Some games have implemented CHudMenu::SelectMenuItem to close the menu
|
||||||
|
// even if an invalid slot has been selected, which causes us a problem as
|
||||||
|
// we'll never get any notification from the client and we'll keep the menu
|
||||||
|
// alive on our end indefinitely. For these games, pretend that every slot
|
||||||
|
// is valid for selection so we're guaranteed to get a menuselect command.
|
||||||
|
// We don't want to do this for every game as the common SelectMenuItem
|
||||||
|
// implementation ignores invalid selections and keeps the menu open, which
|
||||||
|
// is a much nicer user experience.
|
||||||
|
display_keys = s_RadioClosesOnInvalidSlot ? 0x7ff : keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRadioMenuPlayer::Radio_Refresh()
|
void CRadioMenuPlayer::Radio_Refresh()
|
||||||
@ -483,9 +502,13 @@ void CRadioMenuPlayer::Radio_Refresh()
|
|||||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
// TODO: find what happens past 240 on CS:GO
|
// TODO: find what happens past 240 on CS:GO
|
||||||
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||||
|
if (!msg)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
msg->set_bits_valid_slots(display_keys);
|
msg->set_bits_valid_slots(display_keys);
|
||||||
msg->set_display_time(time);
|
msg->set_display_time(time);
|
||||||
msg->set_menu_string(ptr);
|
msg->set_menu_string(ptr);
|
||||||
@ -576,7 +599,7 @@ bool CRadioMenu::DisplayAtItem(int client,
|
|||||||
IMenuHandler *alt_handler)
|
IMenuHandler *alt_handler)
|
||||||
{
|
{
|
||||||
#if defined MENU_DEBUG
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
logger->LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
||||||
this,
|
this,
|
||||||
client,
|
client,
|
||||||
time);
|
time);
|
||||||
|
|||||||
@ -40,6 +40,7 @@
|
|||||||
#include "UserMessages.h"
|
#include "UserMessages.h"
|
||||||
#include "sm_fastlink.h"
|
#include "sm_fastlink.h"
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
|
#include <sh_string.h>
|
||||||
#include <compat_wrappers.h>
|
#include <compat_wrappers.h>
|
||||||
#include "logic/common_logic.h"
|
#include "logic/common_logic.h"
|
||||||
#include "AutoHandleRooter.h"
|
#include "AutoHandleRooter.h"
|
||||||
|
|||||||
@ -63,11 +63,7 @@ bool g_forcedChange = false;
|
|||||||
|
|
||||||
void NextMapManager::OnSourceModAllInitialized_Post()
|
void NextMapManager::OnSourceModAllInitialized_Post()
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#else
|
|
||||||
SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ConCommand *pCmd = FindCommand("changelevel");
|
ConCommand *pCmd = FindCommand("changelevel");
|
||||||
if (pCmd != NULL)
|
if (pCmd != NULL)
|
||||||
@ -79,11 +75,7 @@ void NextMapManager::OnSourceModAllInitialized_Post()
|
|||||||
|
|
||||||
void NextMapManager::OnSourceModShutdown()
|
void NextMapManager::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
|
||||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
||||||
#else
|
|
||||||
SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (changeLevelCmd != NULL)
|
if (changeLevelCmd != NULL)
|
||||||
{
|
{
|
||||||
@ -117,6 +109,8 @@ bool NextMapManager::SetNextMap(const char *map)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char g_nextMap[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
#if SOURCE_ENGINE != SE_DARKMESSIAH
|
||||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
|
||||||
#else
|
#else
|
||||||
@ -130,8 +124,16 @@ 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') {
|
||||||
|
ke::SafeStrcpy(g_nextMap, sizeof(g_nextMap), newmap);
|
||||||
|
newmap = g_nextMap;
|
||||||
|
|
||||||
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
|
// Clear the value so that if the map load fails later we don't get stuck in a loop.
|
||||||
|
// This might cause us to go off-cycle for a map, but nextmap will get us back on track.
|
||||||
|
sm_nextmap.SetValue("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newmap[0] == '\0' || !g_HL2.IsMapValid(newmap))
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
@ -150,6 +152,15 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
|
|||||||
|
|
||||||
void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
void NextMapManager::OnSourceModLevelChange( const char *mapName )
|
||||||
{
|
{
|
||||||
|
// If we were controlling the map change, reset sm_nextmap to be the name of the map we successfully changed to.
|
||||||
|
// This maintains an old API contract on the plugin side. We use the real map name even if it was different from
|
||||||
|
// the expected map name as if the expected map failed to load we let the game take over instead, but the nextmap
|
||||||
|
// plugin compares the sm_nextmap value to the current map to decide if it should advance the mapcycle.
|
||||||
|
if (g_nextMap[0] != '\0') {
|
||||||
|
sm_nextmap.SetValue(mapName);
|
||||||
|
g_nextMap[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip the first 'mapchange' when the server starts up */
|
/* Skip the first 'mapchange' when the server starts up */
|
||||||
if (m_tempChangeInfo.startTime != 0)
|
if (m_tempChangeInfo.startTime != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -96,7 +96,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
MapChangeData m_tempChangeInfo;
|
MapChangeData m_tempChangeInfo;
|
||||||
char lastMap[32];
|
char lastMap[PLATFORM_MAX_PATH];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NextMapManager g_NextMap;
|
extern NextMapManager g_NextMap;
|
||||||
|
|||||||
@ -59,6 +59,8 @@ bool g_OnMapStarted = false;
|
|||||||
IForward *PreAdminCheck = NULL;
|
IForward *PreAdminCheck = NULL;
|
||||||
IForward *PostAdminCheck = NULL;
|
IForward *PostAdminCheck = NULL;
|
||||||
IForward *PostAdminFilter = NULL;
|
IForward *PostAdminFilter = NULL;
|
||||||
|
IForward *ServerEnterHibernation = NULL;
|
||||||
|
IForward *ServerExitHibernation = NULL;
|
||||||
|
|
||||||
const unsigned int *g_NumPlayersToAuth = NULL;
|
const unsigned int *g_NumPlayersToAuth = NULL;
|
||||||
int lifestate_offset = -1;
|
int lifestate_offset = -1;
|
||||||
@ -97,7 +99,7 @@ SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, cons
|
|||||||
|
|
||||||
static void PrintfBuffer_FrameAction(void *data)
|
static void PrintfBuffer_FrameAction(void *data)
|
||||||
{
|
{
|
||||||
g_Players.OnPrintfFrameAction(reinterpret_cast<unsigned int>(data));
|
g_Players.OnPrintfFrameAction(static_cast<unsigned int>(reinterpret_cast<uintptr_t>(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConCommand *maxplayersCmd = NULL;
|
ConCommand *maxplayersCmd = NULL;
|
||||||
@ -196,12 +198,15 @@ void PlayerManager::OnSourceModAllInitialized()
|
|||||||
m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
|
m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
|
||||||
m_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
|
m_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
|
||||||
m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
|
m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
|
||||||
|
m_cllang = forwardsys->CreateForward("OnClientLanguageChanged", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
|
||||||
m_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
|
m_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
|
||||||
m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL);
|
m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL);
|
||||||
|
|
||||||
PreAdminCheck = forwardsys->CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
|
PreAdminCheck = forwardsys->CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
|
||||||
PostAdminCheck = forwardsys->CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
|
PostAdminCheck = forwardsys->CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
|
||||||
PostAdminFilter = forwardsys->CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
|
PostAdminFilter = forwardsys->CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
|
||||||
|
ServerEnterHibernation = forwardsys->CreateForward("OnServerEnterHibernation", ET_Ignore, 0, NULL);
|
||||||
|
ServerExitHibernation = forwardsys->CreateForward("OnServerExitHibernation", ET_Ignore, 0, NULL);
|
||||||
|
|
||||||
m_bIsListenServer = !engine->IsDedicatedServer();
|
m_bIsListenServer = !engine->IsDedicatedServer();
|
||||||
m_ListenClient = 0;
|
m_ListenClient = 0;
|
||||||
@ -249,12 +254,15 @@ void PlayerManager::OnSourceModShutdown()
|
|||||||
forwardsys->ReleaseForward(m_clcommandkv_post);
|
forwardsys->ReleaseForward(m_clcommandkv_post);
|
||||||
forwardsys->ReleaseForward(m_clinfochanged);
|
forwardsys->ReleaseForward(m_clinfochanged);
|
||||||
forwardsys->ReleaseForward(m_clauth);
|
forwardsys->ReleaseForward(m_clauth);
|
||||||
|
forwardsys->ReleaseForward(m_cllang);
|
||||||
forwardsys->ReleaseForward(m_onActivate);
|
forwardsys->ReleaseForward(m_onActivate);
|
||||||
forwardsys->ReleaseForward(m_onActivate2);
|
forwardsys->ReleaseForward(m_onActivate2);
|
||||||
|
|
||||||
forwardsys->ReleaseForward(PreAdminCheck);
|
forwardsys->ReleaseForward(PreAdminCheck);
|
||||||
forwardsys->ReleaseForward(PostAdminCheck);
|
forwardsys->ReleaseForward(PostAdminCheck);
|
||||||
forwardsys->ReleaseForward(PostAdminFilter);
|
forwardsys->ReleaseForward(PostAdminFilter);
|
||||||
|
forwardsys->ReleaseForward(ServerEnterHibernation);
|
||||||
|
forwardsys->ReleaseForward(ServerExitHibernation);
|
||||||
|
|
||||||
delete [] m_Players;
|
delete [] m_Players;
|
||||||
|
|
||||||
@ -410,7 +418,7 @@ void PlayerManager::RunAuthChecks()
|
|||||||
pPlayer = &m_Players[m_AuthQueue[i]];
|
pPlayer = &m_Players[m_AuthQueue[i]];
|
||||||
pPlayer->UpdateAuthIds();
|
pPlayer->UpdateAuthIds();
|
||||||
|
|
||||||
authstr = pPlayer->m_AuthID.chars();
|
authstr = pPlayer->m_AuthID.c_str();
|
||||||
|
|
||||||
if (!pPlayer->IsAuthStringValidated())
|
if (!pPlayer->IsAuthStringValidated())
|
||||||
{
|
{
|
||||||
@ -517,7 +525,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
|||||||
/* Get the client's language */
|
/* Get the client's language */
|
||||||
if (m_QueryLang)
|
if (m_QueryLang)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
pPlayer->m_LangId = translator->GetServerLanguage();
|
pPlayer->m_LangId = translator->GetServerLanguage();
|
||||||
#else
|
#else
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -525,10 +533,13 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
|
|||||||
{
|
{
|
||||||
unsigned int langid;
|
unsigned int langid;
|
||||||
pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage();
|
pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage();
|
||||||
|
|
||||||
|
OnClientLanguageChanged(client, pPlayer->m_LangId);
|
||||||
} else {
|
} else {
|
||||||
pPlayer->m_LangId = translator->GetServerLanguage();
|
pPlayer->m_LangId = translator->GetServerLanguage();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
pPlayer->m_OriginalLangId = pPlayer->m_LangId;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IClientListener *>::iterator iter;
|
List<IClientListener *>::iterator iter;
|
||||||
@ -646,7 +657,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
|||||||
|
|
||||||
int userId = engine->GetPlayerUserId(pEntity);
|
int userId = engine->GetPlayerUserId(pEntity);
|
||||||
#if (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|
#if (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|
||||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_PVKII)
|
||||||
static ConVar *tv_name = icvar->FindVar("tv_name");
|
static ConVar *tv_name = icvar->FindVar("tv_name");
|
||||||
#endif
|
#endif
|
||||||
#if SOURCE_ENGINE == SE_TF2
|
#if SOURCE_ENGINE == SE_TF2
|
||||||
@ -669,10 +680,13 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
|||||||
&& ((!m_bIsReplayActive && newCount == 1)
|
&& ((!m_bIsReplayActive && newCount == 1)
|
||||||
|| (m_bIsReplayActive && newCount == 2))
|
|| (m_bIsReplayActive && newCount == 2))
|
||||||
&& (m_SourceTVUserId == userId
|
&& (m_SourceTVUserId == userId
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_MCV
|
||||||
|
// It seems likely that MCV will change this at some point, but it's GOTV at the moment.
|
||||||
|| strcmp(playername, "GOTV") == 0
|
|| strcmp(playername, "GOTV") == 0
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
|| strcmp(playername, "BBTV") == 0
|
||||||
#elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|
#elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|
||||||
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_PVKII)
|
||||||
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
|
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
|
||||||
#else
|
#else
|
||||||
|| strcmp(playername, "SourceTV") == 0
|
|| strcmp(playername, "SourceTV") == 0
|
||||||
@ -714,19 +728,19 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
|
|||||||
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
|
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
|
||||||
{
|
{
|
||||||
pListener = (*iter);
|
pListener = (*iter);
|
||||||
pListener->OnClientAuthorized(client, steamId ? steamId : pPlayer->m_AuthID.chars());
|
pListener->OnClientAuthorized(client, steamId ? steamId : pPlayer->m_AuthID.c_str());
|
||||||
}
|
}
|
||||||
/* Finally, tell plugins */
|
/* Finally, tell plugins */
|
||||||
if (m_clauth->GetFunctionCount())
|
if (m_clauth->GetFunctionCount())
|
||||||
{
|
{
|
||||||
m_clauth->PushCell(client);
|
m_clauth->PushCell(client);
|
||||||
/* For legacy reasons, people are expecting the Steam2 id here if using Steam auth */
|
/* For legacy reasons, people are expecting the Steam2 id here if using Steam auth */
|
||||||
m_clauth->PushString(steamId ? steamId : pPlayer->m_AuthID.chars());
|
m_clauth->PushString(steamId ? steamId : pPlayer->m_AuthID.c_str());
|
||||||
m_clauth->Execute(NULL);
|
m_clauth->Execute(NULL);
|
||||||
}
|
}
|
||||||
pPlayer->Authorize_Post();
|
pPlayer->Authorize_Post();
|
||||||
}
|
}
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
else if(m_QueryLang)
|
else if(m_QueryLang)
|
||||||
{
|
{
|
||||||
// Not a bot
|
// Not a bot
|
||||||
@ -775,6 +789,11 @@ void PlayerManager::OnSourceModLevelEnd()
|
|||||||
|
|
||||||
void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
|
void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
|
||||||
{
|
{
|
||||||
|
cell_t res;
|
||||||
|
if (bHibernating)
|
||||||
|
ServerEnterHibernation->Execute(&res);
|
||||||
|
else
|
||||||
|
ServerExitHibernation->Execute(&res);
|
||||||
/* If bots were added at map start, but not fully inited before hibernation, there will
|
/* If bots were added at map start, but not fully inited before hibernation, there will
|
||||||
* be no OnClientDisconnect for them, despite them getting booted right before this.
|
* be no OnClientDisconnect for them, despite them getting booted right before this.
|
||||||
*/
|
*/
|
||||||
@ -786,7 +805,7 @@ void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
|
|||||||
CPlayer *pPlayer = &m_Players[i];
|
CPlayer *pPlayer = &m_Players[i];
|
||||||
if (pPlayer->IsConnected() && pPlayer->IsFakeClient())
|
if (pPlayer->IsConnected() && pPlayer->IsFakeClient())
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE >= SE_CSGO || SOURCE_ENGINE == SE_NUCLEARDAWN
|
#if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_MCV
|
||||||
// These games have the bug fixed where hltv/replay was getting kicked on hibernation
|
// These games have the bug fixed where hltv/replay was getting kicked on hibernation
|
||||||
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
|
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
|
||||||
continue;
|
continue;
|
||||||
@ -873,7 +892,7 @@ void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
|
|||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
|
|
||||||
size_t nMsgLen = strlen(szMsg);
|
size_t nMsgLen = strlen(szMsg);
|
||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE || SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
static const int nNumBitsWritten = 0;
|
static const int nNumBitsWritten = 0;
|
||||||
#else
|
#else
|
||||||
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
||||||
@ -891,7 +910,7 @@ void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
|
|||||||
if (player.m_PrintfBuffer.empty())
|
if (player.m_PrintfBuffer.empty())
|
||||||
g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
|
g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
|
||||||
|
|
||||||
player.m_PrintfBuffer.append(szMsg);
|
player.m_PrintfBuffer.push_back(szMsg);
|
||||||
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
@ -918,21 +937,21 @@ void PlayerManager::OnPrintfFrameAction(unsigned int serial)
|
|||||||
|
|
||||||
while (!player.m_PrintfBuffer.empty())
|
while (!player.m_PrintfBuffer.empty())
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_EPISODEONE
|
#if SOURCE_ENGINE == SE_EPISODEONE || SOURCE_ENGINE == SE_DARKMESSIAH
|
||||||
static const int nNumBitsWritten = 0;
|
static const int nNumBitsWritten = 0;
|
||||||
#else
|
#else
|
||||||
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ke::AString &string = player.m_PrintfBuffer.front();
|
std::string &string = player.m_PrintfBuffer.front();
|
||||||
|
|
||||||
// stop if we'd overflow the SVC_Print buffer (+7 as ceil)
|
// stop if we'd overflow the SVC_Print buffer (+7 as ceil)
|
||||||
if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize)
|
if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.chars());
|
SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.c_str());
|
||||||
|
|
||||||
player.m_PrintfBuffer.popFront();
|
player.m_PrintfBuffer.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.m_PrintfBuffer.empty())
|
if (!player.m_PrintfBuffer.empty())
|
||||||
@ -972,8 +991,6 @@ void ClientConsolePrint(edict_t *e, const char *fmt, ...)
|
|||||||
void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
unsigned int id = 0;
|
|
||||||
unsigned int start = 0;
|
|
||||||
|
|
||||||
AutoExtensionList extensions(extsys);
|
AutoExtensionList extensions(extsys);
|
||||||
if (!extensions->size())
|
if (!extensions->size())
|
||||||
@ -982,11 +999,6 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.ArgC() > 2)
|
|
||||||
{
|
|
||||||
start = atoi(args.Arg(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (; i < extensions->size(); i++)
|
for (; i < extensions->size(); i++)
|
||||||
{
|
{
|
||||||
@ -998,17 +1010,6 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
id++;
|
|
||||||
if (id < start)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id - start > 10)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
IExtensionInterface *api = ext->GetAPI();
|
IExtensionInterface *api = ext->GetAPI();
|
||||||
|
|
||||||
const char *name = api->GetExtensionName();
|
const char *name = api->GetExtensionName();
|
||||||
@ -1033,31 +1034,14 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
|
|||||||
len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, ": %s", description);
|
len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, ": %s", description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ClientConsolePrint(player->GetEdict(), "%s", buffer);
|
ClientConsolePrint(player->GetEdict(), "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; i < extensions->size(); i++)
|
|
||||||
{
|
|
||||||
char error[255];
|
|
||||||
if (extensions->at(i)->IsRunning(error, sizeof(error)))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < extensions->size())
|
|
||||||
{
|
|
||||||
ClientConsolePrint(player->GetEdict(), "To see more, type \"sm exts %d\"", id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
unsigned int id = 0;
|
|
||||||
edict_t *e = player->GetEdict();
|
edict_t *e = player->GetEdict();
|
||||||
unsigned int start = 0;
|
|
||||||
|
|
||||||
AutoPluginList plugins(scripts);
|
AutoPluginList plugins(scripts);
|
||||||
if (!plugins->size())
|
if (!plugins->size())
|
||||||
@ -1066,11 +1050,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.ArgC() > 2)
|
|
||||||
{
|
|
||||||
start = atoi(args.Arg(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceHook::List<SMPlugin *> m_FailList;
|
SourceHook::List<SMPlugin *> m_FailList;
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@ -1083,18 +1062,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count valid plugins */
|
|
||||||
id++;
|
|
||||||
if (id < start)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id - start > 10)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
const sm_plugininfo_t *info = pl->GetPublicInfo();
|
const sm_plugininfo_t *info = pl->GetPublicInfo();
|
||||||
len = ke::SafeSprintf(buffer, sizeof(buffer), " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
|
len = ke::SafeSprintf(buffer, sizeof(buffer), " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
|
||||||
@ -1112,21 +1079,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
|
|||||||
}
|
}
|
||||||
ClientConsolePrint(e, "%s", buffer);
|
ClientConsolePrint(e, "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if we can get more plugins */
|
|
||||||
for (; i < plugins->size(); i++)
|
|
||||||
{
|
|
||||||
if (plugins->at(i)->GetStatus() == Plugin_Running)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do we actually have more plugins? */
|
|
||||||
if (i < plugins->size())
|
|
||||||
{
|
|
||||||
ClientConsolePrint(e, "To see more, type \"sm plugins %d\"", id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
@ -1161,14 +1113,18 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
|||||||
}
|
}
|
||||||
else if (args.ArgC() > 1 && strcmp(args.Arg(1), "credits") == 0)
|
else if (args.ArgC() > 1 && strcmp(args.Arg(1), "credits") == 0)
|
||||||
{
|
{
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
"SourceMod would not be possible without:");
|
"SourceMod would not be possible without:");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" David \"BAILOPAN\" Anderson, Matt \"pRED\" Woodrow");
|
" David \"BAILOPAN\" Anderson, Matt \"pRED\" Woodrow");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" Scott \"DS\" Ehlert, Fyren");
|
" Scott \"DS\" Ehlert, Fyren");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" Nicholas \"psychonic\" Hastings, Asher \"asherkin\" Baker");
|
" Nicholas \"psychonic\" Hastings, Asher \"asherkin\" Baker");
|
||||||
|
ClientConsolePrint(pEntity,
|
||||||
|
" Ruben \"Dr!fter\" Gonzalez, Josh \"KyleS\" Allard");
|
||||||
|
ClientConsolePrint(pEntity,
|
||||||
|
" Michael \"Headline\" Flaherty, Jannik \"Peace-Maker\" Hartung");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
" Borja \"faluco\" Ferrer, Pavol \"PM OnoTo\" Marko");
|
" Borja \"faluco\" Ferrer, Pavol \"PM OnoTo\" Marko");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
@ -1183,7 +1139,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
|||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
"To see credits, type \"sm credits\"");
|
"To see credits, type \"sm credits\"");
|
||||||
ClientConsolePrint(pEntity,
|
ClientConsolePrint(pEntity,
|
||||||
"Visit http://www.sourcemod.net/");
|
"Visit https://www.sourcemod.net/");
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,7 +1164,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
|
|||||||
if (g_ConsoleDetours.IsEnabled())
|
if (g_ConsoleDetours.IsEnabled())
|
||||||
{
|
{
|
||||||
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, &cargs);
|
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, &cargs);
|
||||||
if (res2 >= Pl_Stop)
|
if (res2 >= Pl_Handled)
|
||||||
{
|
{
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
@ -1338,65 +1294,69 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
|||||||
m_clinfochanged->PushCell(client);
|
m_clinfochanged->PushCell(client);
|
||||||
m_clinfochanged->Execute(&res, NULL);
|
m_clinfochanged->Execute(&res, NULL);
|
||||||
|
|
||||||
if (pPlayer->IsFakeClient())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPlayerInfo *info = pPlayer->GetPlayerInfo();
|
IPlayerInfo *info = pPlayer->GetPlayerInfo();
|
||||||
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
|
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
|
||||||
const char *old_name = pPlayer->m_Name.c_str();
|
const char *old_name = pPlayer->m_Name.c_str();
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
|
||||||
const char *networkid_force;
|
|
||||||
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
|
|
||||||
{
|
|
||||||
unsigned int accountId = pPlayer->GetSteamAccountID();
|
|
||||||
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
|
|
||||||
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
|
|
||||||
|
|
||||||
pPlayer->Kick("NetworkID spoofing detected.");
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (strcmp(old_name, new_name) != 0)
|
if (strcmp(old_name, new_name) != 0)
|
||||||
{
|
{
|
||||||
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
|
if (!pPlayer->IsFakeClient())
|
||||||
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
|
||||||
{
|
{
|
||||||
if (!CheckSetAdminName(client, pPlayer, id))
|
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
|
||||||
|
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
|
||||||
{
|
{
|
||||||
char kickMsg[128];
|
if (!CheckSetAdminName(client, pPlayer, id))
|
||||||
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
|
{
|
||||||
pPlayer->Kick(kickMsg);
|
char kickMsg[128];
|
||||||
RETURN_META(MRES_IGNORED);
|
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
|
||||||
|
pPlayer->Kick(kickMsg);
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
|
else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
|
||||||
if (id == pPlayer->GetAdminId())
|
if (id == pPlayer->GetAdminId())
|
||||||
{
|
{
|
||||||
/* This player is changing their name; force them to drop admin privileges! */
|
/* This player is changing their name; force them to drop admin privileges! */
|
||||||
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pPlayer->SetName(new_name);
|
pPlayer->SetName(new_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_PassInfoVar.size() > 0)
|
if (!pPlayer->IsFakeClient())
|
||||||
{
|
{
|
||||||
/* Try for a password change */
|
if (m_PassInfoVar.size() > 0)
|
||||||
const char *old_pass = pPlayer->m_LastPassword.c_str();
|
|
||||||
const char *new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
|
|
||||||
if (strcmp(old_pass, new_pass) != 0)
|
|
||||||
{
|
{
|
||||||
pPlayer->m_LastPassword.assign(new_pass);
|
/* Try for a password change */
|
||||||
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
|
const char* old_pass = pPlayer->m_LastPassword.c_str();
|
||||||
|
const char* new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
|
||||||
|
if (strcmp(old_pass, new_pass) != 0)
|
||||||
{
|
{
|
||||||
/* If there is already an admin id assigned, this will just bail out. */
|
pPlayer->m_LastPassword.assign(new_pass);
|
||||||
pPlayer->DoBasicAdminChecks();
|
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
|
||||||
|
{
|
||||||
|
/* If there is already an admin id assigned, this will just bail out. */
|
||||||
|
pPlayer->DoBasicAdminChecks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
|
const char* networkid_force;
|
||||||
|
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
|
||||||
|
{
|
||||||
|
unsigned int accountId = pPlayer->GetSteamAccountID();
|
||||||
|
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
|
||||||
|
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
|
||||||
|
|
||||||
|
pPlayer->Kick("NetworkID spoofing detected.");
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify Extensions */
|
/* Notify Extensions */
|
||||||
List<IClientListener *>::iterator iter;
|
List<IClientListener *>::iterator iter;
|
||||||
IClientListener *pListener = NULL;
|
IClientListener *pListener = NULL;
|
||||||
@ -1410,6 +1370,13 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerManager::OnClientLanguageChanged(int client, unsigned int language)
|
||||||
|
{
|
||||||
|
m_cllang->PushCell(client);
|
||||||
|
m_cllang->PushCell(language);
|
||||||
|
m_cllang->Execute(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int PlayerManager::GetMaxClients()
|
int PlayerManager::GetMaxClients()
|
||||||
{
|
{
|
||||||
return m_maxClients;
|
return m_maxClients;
|
||||||
@ -1575,7 +1542,10 @@ void PlayerManager::InvalidatePlayer(CPlayer *pPlayer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_UserIdLookUp[engine->GetPlayerUserId(pPlayer->m_pEdict)] = 0;
|
auto userid = engine->GetPlayerUserId(pPlayer->m_pEdict);
|
||||||
|
if (userid != -1)
|
||||||
|
m_UserIdLookUp[userid] = 0;
|
||||||
|
|
||||||
pPlayer->Disconnect();
|
pPlayer->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2011,7 +1981,7 @@ void CmdMaxplayersCallback()
|
|||||||
g_Players.MaxPlayersChanged();
|
g_Players.MaxPlayersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= m_maxClients; i++)
|
for (int i = 1; i <= m_maxClients; i++)
|
||||||
@ -2019,7 +1989,10 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
|
|||||||
if (m_Players[i].m_LanguageCookie == cookie)
|
if (m_Players[i].m_LanguageCookie == cookie)
|
||||||
{
|
{
|
||||||
unsigned int langid;
|
unsigned int langid;
|
||||||
m_Players[i].m_LangId = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
|
unsigned int new_langid = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
|
||||||
|
m_Players[i].m_LangId = new_langid;
|
||||||
|
m_Players[i].m_OriginalLangId = new_langid;
|
||||||
|
OnClientLanguageChanged(i, new_langid);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2068,6 +2041,7 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|
|||||||
m_pEdict = pEntity;
|
m_pEdict = pEntity;
|
||||||
m_iIndex = IndexOfEdict(pEntity);
|
m_iIndex = IndexOfEdict(pEntity);
|
||||||
m_LangId = translator->GetServerLanguage();
|
m_LangId = translator->GetServerLanguage();
|
||||||
|
m_OriginalLangId = m_LangId;
|
||||||
|
|
||||||
m_Serial.bits.index = m_iIndex;
|
m_Serial.bits.index = m_iIndex;
|
||||||
m_Serial.bits.serial = g_PlayerSerialCount++;
|
m_Serial.bits.serial = g_PlayerSerialCount++;
|
||||||
@ -2088,7 +2062,9 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|
|||||||
|| SOURCE_ENGINE == SE_HL2DM \
|
|| SOURCE_ENGINE == SE_HL2DM \
|
||||||
|| SOURCE_ENGINE == SE_BMS \
|
|| SOURCE_ENGINE == SE_BMS \
|
||||||
|| SOURCE_ENGINE == SE_INSURGENCY \
|
|| SOURCE_ENGINE == SE_INSURGENCY \
|
||||||
|| SOURCE_ENGINE == SE_DOI
|
|| SOURCE_ENGINE == SE_DOI \
|
||||||
|
|| SOURCE_ENGINE == SE_BLADE \
|
||||||
|
|| SOURCE_ENGINE == SE_PVKII
|
||||||
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
|
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
|
||||||
#else
|
#else
|
||||||
#if SOURCE_ENGINE == SE_SDK2013
|
#if SOURCE_ENGINE == SE_SDK2013
|
||||||
@ -2264,7 +2240,7 @@ void CPlayer::Disconnect()
|
|||||||
m_bIsSourceTV = false;
|
m_bIsSourceTV = false;
|
||||||
m_bIsReplay = false;
|
m_bIsReplay = false;
|
||||||
m_Serial.value = -1;
|
m_Serial.value = -1;
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
m_LanguageCookie = InvalidQueryCvarCookie;
|
m_LanguageCookie = InvalidQueryCvarCookie;
|
||||||
#endif
|
#endif
|
||||||
ClearNetchannelQueue();
|
ClearNetchannelQueue();
|
||||||
@ -2273,7 +2249,7 @@ void CPlayer::Disconnect()
|
|||||||
void CPlayer::ClearNetchannelQueue(void)
|
void CPlayer::ClearNetchannelQueue(void)
|
||||||
{
|
{
|
||||||
while (!m_PrintfBuffer.empty())
|
while (!m_PrintfBuffer.empty())
|
||||||
m_PrintfBuffer.popFront();
|
m_PrintfBuffer.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayer::SetName(const char *name)
|
void CPlayer::SetName(const char *name)
|
||||||
@ -2306,11 +2282,6 @@ void CPlayer::SetName(const char *name)
|
|||||||
|
|
||||||
const char *CPlayer::GetName()
|
const char *CPlayer::GetName()
|
||||||
{
|
{
|
||||||
if (m_Info && m_pEdict->GetUnknown())
|
|
||||||
{
|
|
||||||
return m_Info->GetName();
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Name.c_str();
|
return m_Name.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2326,7 +2297,7 @@ const char *CPlayer::GetAuthString(bool validated)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_AuthID.chars();
|
return m_AuthID.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSteamID &CPlayer::GetSteamId(bool validated)
|
const CSteamID &CPlayer::GetSteamId(bool validated)
|
||||||
@ -2347,7 +2318,7 @@ const char *CPlayer::GetSteam2Id(bool validated)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_Steam2Id.chars();
|
return m_Steam2Id.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CPlayer::GetSteam3Id(bool validated)
|
const char *CPlayer::GetSteam3Id(bool validated)
|
||||||
@ -2357,14 +2328,14 @@ const char *CPlayer::GetSteam3Id(bool validated)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_Steam3Id.chars();
|
return m_Steam3Id.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CPlayer::GetSteamAccountID(bool validated)
|
unsigned int CPlayer::GetSteamAccountID(bool validated)
|
||||||
{
|
{
|
||||||
if (!IsFakeClient() && (!validated || IsAuthStringValidated()))
|
if (!IsFakeClient() && (!validated || IsAuthStringValidated()))
|
||||||
{
|
{
|
||||||
const CSteamID &id = GetSteamId();
|
const CSteamID &id = GetSteamId(validated);
|
||||||
if (id.IsValid())
|
if (id.IsValid())
|
||||||
return id.GetAccountID();
|
return id.GetAccountID();
|
||||||
}
|
}
|
||||||
@ -2491,7 +2462,7 @@ void CPlayer::Kick(const char *str)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
pClient->Disconnect(str);
|
pClient->Disconnect(str);
|
||||||
#else
|
#else
|
||||||
pClient->Disconnect("%s", str);
|
pClient->Disconnect("%s", str);
|
||||||
@ -2624,7 +2595,7 @@ void CPlayer::DoBasicAdminChecks()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check steam id */
|
/* Check steam id */
|
||||||
if ((id = adminsys->FindAdminByIdentity("steam", m_AuthID.chars())) != INVALID_ADMIN_ID)
|
if ((id = adminsys->FindAdminByIdentity("steam", m_AuthID.c_str())) != INVALID_ADMIN_ID)
|
||||||
{
|
{
|
||||||
if (g_Players.CheckSetAdmin(client, this, id))
|
if (g_Players.CheckSetAdmin(client, this, id))
|
||||||
{
|
{
|
||||||
@ -2638,9 +2609,18 @@ unsigned int CPlayer::GetLanguageId()
|
|||||||
return m_LangId;
|
return m_LangId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int CPlayer::GetOriginalLanguageId()
|
||||||
|
{
|
||||||
|
return m_OriginalLangId;
|
||||||
|
}
|
||||||
|
|
||||||
void CPlayer::SetLanguageId(unsigned int id)
|
void CPlayer::SetLanguageId(unsigned int id)
|
||||||
{
|
{
|
||||||
m_LangId = id;
|
if(m_LangId != id)
|
||||||
|
{
|
||||||
|
m_LangId = id;
|
||||||
|
g_Players.OnClientLanguageChanged(m_iIndex, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPlayer::GetUserId()
|
int CPlayer::GetUserId()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 sts=8 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
|
||||||
@ -96,6 +96,7 @@ public:
|
|||||||
bool IsInKickQueue();
|
bool IsInKickQueue();
|
||||||
IPlayerInfo *GetPlayerInfo();
|
IPlayerInfo *GetPlayerInfo();
|
||||||
unsigned int GetLanguageId();
|
unsigned int GetLanguageId();
|
||||||
|
unsigned int GetOriginalLanguageId();
|
||||||
void SetLanguageId(unsigned int id);
|
void SetLanguageId(unsigned int id);
|
||||||
int GetUserId();
|
int GetUserId();
|
||||||
bool RunAdminCacheChecks();
|
bool RunAdminCacheChecks();
|
||||||
@ -133,9 +134,9 @@ private:
|
|||||||
String m_Name;
|
String m_Name;
|
||||||
String m_Ip;
|
String m_Ip;
|
||||||
String m_IpNoPort;
|
String m_IpNoPort;
|
||||||
ke::AString m_AuthID;
|
std::string m_AuthID;
|
||||||
ke::AString m_Steam2Id;
|
std::string m_Steam2Id;
|
||||||
ke::AString m_Steam3Id;
|
std::string m_Steam3Id;
|
||||||
AdminId m_Admin = INVALID_ADMIN_ID;
|
AdminId m_Admin = INVALID_ADMIN_ID;
|
||||||
bool m_TempAdmin = false;
|
bool m_TempAdmin = false;
|
||||||
edict_t *m_pEdict = nullptr;
|
edict_t *m_pEdict = nullptr;
|
||||||
@ -145,16 +146,17 @@ private:
|
|||||||
bool m_bAdminCheckSignalled = false;
|
bool m_bAdminCheckSignalled = false;
|
||||||
int m_iIndex;
|
int m_iIndex;
|
||||||
unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
|
unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
|
||||||
|
unsigned int m_OriginalLangId = SOURCEMOD_LANGUAGE_ENGLISH;
|
||||||
int m_UserId = -1;
|
int m_UserId = -1;
|
||||||
bool m_bFakeClient = false;
|
bool m_bFakeClient = false;
|
||||||
bool m_bIsSourceTV = false;
|
bool m_bIsSourceTV = false;
|
||||||
bool m_bIsReplay = false;
|
bool m_bIsReplay = false;
|
||||||
serial_t m_Serial;
|
serial_t m_Serial;
|
||||||
CSteamID m_SteamId;
|
CSteamID m_SteamId;
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
||||||
#endif
|
#endif
|
||||||
ke::Deque<ke::AString> m_PrintfBuffer;
|
std::deque<std::string> m_PrintfBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerManager :
|
class PlayerManager :
|
||||||
@ -193,6 +195,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
void OnClientSettingsChanged(edict_t *pEntity);
|
void OnClientSettingsChanged(edict_t *pEntity);
|
||||||
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
||||||
|
void OnClientLanguageChanged(int client, unsigned int language);
|
||||||
void OnServerHibernationUpdate(bool bHibernating);
|
void OnServerHibernationUpdate(bool bHibernating);
|
||||||
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
||||||
void OnPrintfFrameAction(unsigned int serial);
|
void OnPrintfFrameAction(unsigned int serial);
|
||||||
@ -239,7 +242,7 @@ public:
|
|||||||
{
|
{
|
||||||
return m_bInCCKVHook;
|
return m_bInCCKVHook;
|
||||||
}
|
}
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
|
||||||
#endif
|
#endif
|
||||||
private:
|
private:
|
||||||
@ -257,6 +260,7 @@ private:
|
|||||||
IForward *m_clcommandkv_post;
|
IForward *m_clcommandkv_post;
|
||||||
IForward *m_clinfochanged;
|
IForward *m_clinfochanged;
|
||||||
IForward *m_clauth;
|
IForward *m_clauth;
|
||||||
|
IForward *m_cllang;
|
||||||
IForward *m_onActivate;
|
IForward *m_onActivate;
|
||||||
IForward *m_onActivate2;
|
IForward *m_onActivate2;
|
||||||
CPlayer *m_Players;
|
CPlayer *m_Players;
|
||||||
|
|||||||
@ -69,6 +69,13 @@ class DefaultMapTimer :
|
|||||||
public IConVarChangeListener
|
public IConVarChangeListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_BMS
|
||||||
|
static constexpr int kMapTimeScaleFactor = 60;
|
||||||
|
#else
|
||||||
|
static constexpr int kMapTimeScaleFactor = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
DefaultMapTimer()
|
DefaultMapTimer()
|
||||||
{
|
{
|
||||||
m_bInUse = false;
|
m_bInUse = false;
|
||||||
@ -81,7 +88,7 @@ public:
|
|||||||
|
|
||||||
int GetMapTimeLimit()
|
int GetMapTimeLimit()
|
||||||
{
|
{
|
||||||
return mp_timelimit->GetInt();
|
return (mp_timelimit->GetInt() / kMapTimeScaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMapTimerStatus(bool enabled)
|
void SetMapTimerStatus(bool enabled)
|
||||||
@ -105,7 +112,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extra_time /= 60;
|
extra_time /= (60 / kMapTimeScaleFactor);
|
||||||
|
|
||||||
mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
|
mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
|
||||||
}
|
}
|
||||||
@ -484,4 +491,3 @@ bool TimerSystem::GetMapTimeLeft(float *time_left)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -816,9 +816,6 @@ public:
|
|||||||
|
|
||||||
inline bool GetColor(const char *pszFieldName, Color *out)
|
inline bool GetColor(const char *pszFieldName, Color *out)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
CHECK_FIELD_TYPE(MESSAGE);
|
CHECK_FIELD_TYPE(MESSAGE);
|
||||||
CHECK_FIELD_NOT_REPEATED();
|
CHECK_FIELD_NOT_REPEATED();
|
||||||
@ -832,14 +829,10 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool SetColor(const char *pszFieldName, const Color &value)
|
inline bool SetColor(const char *pszFieldName, const Color &value)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
CHECK_FIELD_TYPE(MESSAGE);
|
CHECK_FIELD_TYPE(MESSAGE);
|
||||||
CHECK_FIELD_NOT_REPEATED();
|
CHECK_FIELD_NOT_REPEATED();
|
||||||
@ -851,14 +844,10 @@ public:
|
|||||||
msgRGBA->set_a(value.a());
|
msgRGBA->set_a(value.a());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
|
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
CHECK_FIELD_TYPE(MESSAGE);
|
CHECK_FIELD_TYPE(MESSAGE);
|
||||||
CHECK_FIELD_REPEATED();
|
CHECK_FIELD_REPEATED();
|
||||||
@ -873,14 +862,10 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
|
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
CHECK_FIELD_TYPE(MESSAGE);
|
CHECK_FIELD_TYPE(MESSAGE);
|
||||||
CHECK_FIELD_REPEATED();
|
CHECK_FIELD_REPEATED();
|
||||||
@ -893,14 +878,10 @@ public:
|
|||||||
msgRGBA->set_a(value.a());
|
msgRGBA->set_a(value.a());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool AddColor(const char *pszFieldName, const Color &value)
|
inline bool AddColor(const char *pszFieldName, const Color &value)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
GETCHECK_FIELD();
|
GETCHECK_FIELD();
|
||||||
CHECK_FIELD_TYPE(MESSAGE);
|
CHECK_FIELD_TYPE(MESSAGE);
|
||||||
CHECK_FIELD_REPEATED();
|
CHECK_FIELD_REPEATED();
|
||||||
@ -912,7 +893,6 @@ public:
|
|||||||
msgRGBA->set_a(value.a());
|
msgRGBA->set_a(value.a());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
|
inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
|
||||||
|
|||||||
@ -35,12 +35,16 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
#include <cstrike15_usermessage_helpers.h>
|
#include <cstrike15_usermessage_helpers.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
#include <berimbau_usermessage_helpers.h>
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
#include <vietnam_usermessage_helpers.h>
|
||||||
#endif
|
#endif
|
||||||
#include <amtl/am-string.h>
|
#include <amtl/am-string.h>
|
||||||
|
|
||||||
UserMessages g_UserMsgs;
|
UserMessages g_UserMsgs;
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||||
#else
|
#else
|
||||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
@ -49,7 +53,7 @@ SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRec
|
|||||||
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
|
||||||
#endif
|
#endif
|
||||||
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
|
||||||
#endif // ==SE_CSGO
|
#endif // ==SE_CSGO || ==SE_BLADE || ==SE_MCV
|
||||||
|
|
||||||
UserMessages::UserMessages()
|
UserMessages::UserMessages()
|
||||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||||
@ -93,7 +97,7 @@ void UserMessages::OnSourceModAllShutdown()
|
|||||||
{
|
{
|
||||||
if (m_HookCount)
|
if (m_HookCount)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
#else
|
#else
|
||||||
@ -111,6 +115,10 @@ int UserMessages::GetMessageIndex(const char *msg)
|
|||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
// Can split this per engine and/or game later
|
// Can split this per engine and/or game later
|
||||||
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
return g_BerimbauUsermessageHelpers.GetIndex(msg);
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
return g_VietnamUsermessageHelpers.GetIndex(msg);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int msgid;
|
int msgid;
|
||||||
@ -148,6 +156,10 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
|||||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msgid);
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
const char *pszName = g_VietnamUsermessageHelpers.GetName(msgid);
|
||||||
#endif
|
#endif
|
||||||
if (!pszName)
|
if (!pszName)
|
||||||
return false;
|
return false;
|
||||||
@ -297,7 +309,7 @@ bool UserMessages::EndMessage()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||||
{
|
{
|
||||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||||
@ -327,7 +339,7 @@ bool UserMessages::EndMessage()
|
|||||||
} else {
|
} else {
|
||||||
engine->MessageEnd();
|
engine->MessageEnd();
|
||||||
}
|
}
|
||||||
#endif // SE_CSGO
|
#endif // SE_CSGO || SE_BLADE || SE_MCV
|
||||||
|
|
||||||
m_InExec = false;
|
m_InExec = false;
|
||||||
m_CurFlags = 0;
|
m_CurFlags = 0;
|
||||||
@ -412,7 +424,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
|||||||
|
|
||||||
if (!m_HookCount++)
|
if (!m_HookCount++)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||||
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
#else
|
#else
|
||||||
@ -438,6 +450,10 @@ const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
|
|||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
return g_BerimbauUsermessageHelpers.GetPrototype(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
return g_VietnamUsermessageHelpers.GetPrototype(msg_type);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -487,7 +503,7 @@ void UserMessages::_DecRefCounter()
|
|||||||
{
|
{
|
||||||
if (--m_HookCount == 0)
|
if (--m_HookCount == 0)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
|
||||||
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
|
||||||
#else
|
#else
|
||||||
@ -499,12 +515,19 @@ void UserMessages::_DecRefCounter()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_BLADE
|
||||||
|
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msg_type);
|
||||||
|
#elif SOURCE_ENGINE == SE_MCV
|
||||||
|
const char *pszName = g_VietnamUsermessageHelpers.GetName(msg_type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
OnStartMessage_Pre(&filter, msg_type, pszName);
|
||||||
|
|
||||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||||
{
|
{
|
||||||
int size = msg.ByteSize();
|
int size = msg.ByteSize();
|
||||||
@ -517,9 +540,7 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
|
|||||||
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
OnStartMessage_Post(&filter, msg_type, pszName);
|
||||||
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OnMessageEnd_Pre();
|
OnMessageEnd_Pre();
|
||||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||||
@ -551,7 +572,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
|
|||||||
RETURN_META(res)
|
RETURN_META(res)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
@ -591,7 +612,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
|||||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||||
@ -756,7 +777,7 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
|
|
||||||
if (!handled && intercepted)
|
if (!handled && intercepted)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||||
#else
|
#else
|
||||||
bf_write *engine_bfw;
|
bf_write *engine_bfw;
|
||||||
@ -768,11 +789,11 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
|
||||||
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
|
||||||
ENGINE_CALL(MessageEnd)();
|
ENGINE_CALL(MessageEnd)();
|
||||||
#endif // SE_CSGO
|
#endif // SE_CSGO || SE_BLADE || SE_MCV
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
int size = m_OrigBuffer->ByteSize();
|
int size = m_OrigBuffer->ByteSize();
|
||||||
uint8 *data = (uint8 *)stackalloc(size);
|
uint8 *data = (uint8 *)stackalloc(size);
|
||||||
m_OrigBuffer->SerializePartialToArray(data, size);
|
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||||
@ -802,7 +823,7 @@ void UserMessages::OnMessageEnd_Pre()
|
|||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
delete pTempMsg;
|
delete pTempMsg;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
using namespace SourceHook;
|
using namespace SourceHook;
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
#define USE_PROTOBUF_USERMESSAGES
|
#define USE_PROTOBUF_USERMESSAGES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -102,12 +102,12 @@ public: //IUserMessages
|
|||||||
bool intercept=false);
|
bool intercept=false);
|
||||||
UserMessageType GetUserMessageType() const;
|
UserMessageType GetUserMessageType() const;
|
||||||
public:
|
public:
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||||
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||||
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
|
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
|
||||||
#else
|
#else
|
||||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||||
@ -82,7 +82,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
|
||||||
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
|
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
|
||||||
#else
|
#else
|
||||||
void LinkConCommandBase(ConCommandBase *pBase)
|
void LinkConCommandBase(ConCommandBase *pBase)
|
||||||
@ -108,20 +108,20 @@ public:
|
|||||||
listener = listener->next;
|
listener = listener->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (iter != tracked_bases.end())
|
while (iter != tracked_bases.end())
|
||||||
{
|
{
|
||||||
if ((*iter)->pBase == pBase)
|
if ((*iter)->pBase == pBase)
|
||||||
{
|
{
|
||||||
pInfo = (*iter);
|
pInfo = (*iter);
|
||||||
iter = tracked_bases.erase(iter);
|
iter = tracked_bases.erase(iter);
|
||||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
|
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
|
||||||
delete pInfo;
|
delete pInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
|
void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||||
import os
|
import os
|
||||||
|
|
||||||
for arch in SM.archs:
|
for cxx in builder.targets:
|
||||||
binary = SM.Library(builder, 'sourcemod.logic', arch)
|
binary = SM.Library(builder, cxx, 'sourcemod.logic')
|
||||||
binary.compiler.cxxincludes += [
|
binary.compiler.cxxincludes += [
|
||||||
builder.sourcePath,
|
builder.sourcePath,
|
||||||
os.path.join(builder.sourcePath, 'core', 'logic'),
|
os.path.join(builder.sourcePath, 'core', 'logic'),
|
||||||
@ -16,10 +16,10 @@ for arch in SM.archs:
|
|||||||
'SM_DEFAULT_THREADER',
|
'SM_DEFAULT_THREADER',
|
||||||
'SM_LOGIC'
|
'SM_LOGIC'
|
||||||
]
|
]
|
||||||
|
|
||||||
if builder.target.platform == 'linux':
|
if binary.compiler.target.platform == 'linux':
|
||||||
binary.compiler.postlink += ['-lpthread', '-lrt']
|
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||||
elif builder.target.platform == 'mac':
|
elif binary.compiler.target.platform == 'mac':
|
||||||
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
binary.compiler.cflags += ['-Wno-deprecated-declarations']
|
||||||
binary.compiler.postlink += ['-framework', 'CoreServices']
|
binary.compiler.postlink += ['-framework', 'CoreServices']
|
||||||
|
|
||||||
@ -35,8 +35,7 @@ for arch in SM.archs:
|
|||||||
'smn_maplists.cpp',
|
'smn_maplists.cpp',
|
||||||
'ADTFactory.cpp',
|
'ADTFactory.cpp',
|
||||||
'smn_adt_stack.cpp',
|
'smn_adt_stack.cpp',
|
||||||
'thread/ThreadWorker.cpp',
|
'BaseWorker.cpp',
|
||||||
'thread/BaseWorker.cpp',
|
|
||||||
'ThreadSupport.cpp',
|
'ThreadSupport.cpp',
|
||||||
'smn_float.cpp',
|
'smn_float.cpp',
|
||||||
'TextParsers.cpp',
|
'TextParsers.cpp',
|
||||||
@ -85,15 +84,12 @@ for arch in SM.archs:
|
|||||||
'smn_halflife.cpp',
|
'smn_halflife.cpp',
|
||||||
'FrameIterator.cpp',
|
'FrameIterator.cpp',
|
||||||
'DatabaseConfBuilder.cpp',
|
'DatabaseConfBuilder.cpp',
|
||||||
|
'LumpManager.cpp',
|
||||||
|
'smn_entitylump.cpp',
|
||||||
'NativeInvoker.cpp',
|
'NativeInvoker.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if arch == 'x64':
|
if binary.compiler.target.arch == 'x86_64':
|
||||||
binary.sources += ['PseudoAddrManager.cpp']
|
binary.sources += ['PseudoAddrManager.cpp']
|
||||||
|
|
||||||
if builder.target.platform == 'windows':
|
|
||||||
binary.sources += ['thread/WinThreads.cpp']
|
|
||||||
else:
|
|
||||||
binary.sources += ['thread/PosixThreads.cpp']
|
|
||||||
|
|
||||||
SM.binaries += [builder.Add(binary)]
|
SM.binaries += [builder.Add(binary)]
|
||||||
|
|||||||
@ -1581,7 +1581,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
|
|||||||
{
|
{
|
||||||
id = grp_table[i];
|
id = grp_table[i];
|
||||||
num = GetGroupImmunityCount(id);
|
num = GetGroupImmunityCount(id);
|
||||||
for (unsigned int j=0; j<num; i++)
|
for (unsigned int j=0; j<num; j++)
|
||||||
{
|
{
|
||||||
other = GetGroupImmunity(id, j);
|
other = GetGroupImmunity(id, j);
|
||||||
for (unsigned int k=0; k<pUser->grp_count; k++)
|
for (unsigned int k=0; k<pUser->grp_count; k++)
|
||||||
@ -1843,13 +1843,13 @@ bool AdminCache::DumpCache(const char *filename)
|
|||||||
fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
|
fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
|
||||||
if (pGroup->pCmdGrpTable != NULL)
|
if (pGroup->pCmdGrpTable != NULL)
|
||||||
{
|
{
|
||||||
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
for (OverrideMap::iterator iter = pGroup->pCmdGrpTable->iter(); !iter.empty(); iter.next())
|
||||||
iterator_group_grp_override(fp, iter->key.chars(), iter->value);
|
iterator_group_grp_override(fp, iter->key.c_str(), iter->value);
|
||||||
}
|
}
|
||||||
if (pGroup->pCmdTable != NULL)
|
if (pGroup->pCmdTable != NULL)
|
||||||
{
|
{
|
||||||
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next())
|
||||||
iterator_group_basic_override(fp, iter->key.chars(), iter->value);
|
iterator_group_basic_override(fp, iter->key.c_str(), iter->value);
|
||||||
}
|
}
|
||||||
fprintf(fp, "\t\t}\n");
|
fprintf(fp, "\t\t}\n");
|
||||||
|
|
||||||
@ -1924,9 +1924,9 @@ bool AdminCache::DumpCache(const char *filename)
|
|||||||
|
|
||||||
fprintf(fp, "\"Overrides\"\n{\n");
|
fprintf(fp, "\"Overrides\"\n{\n");
|
||||||
for (FlagMap::iterator iter = m_CmdGrpOverrides.iter(); !iter.empty(); iter.next())
|
for (FlagMap::iterator iter = m_CmdGrpOverrides.iter(); !iter.empty(); iter.next())
|
||||||
iterator_glob_grp_override(fp, iter->key.chars(), iter->value);
|
iterator_glob_grp_override(fp, iter->key.c_str(), iter->value);
|
||||||
for (FlagMap::iterator iter = m_CmdOverrides.iter(); !iter.empty(); iter.next())
|
for (FlagMap::iterator iter = m_CmdOverrides.iter(); !iter.empty(); iter.next())
|
||||||
iterator_glob_basic_override(fp, iter->key.chars(), iter->value);
|
iterator_glob_basic_override(fp, iter->key.c_str(), iter->value);
|
||||||
fprintf(fp, "}\n");
|
fprintf(fp, "}\n");
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|||||||
@ -40,7 +40,7 @@ BaseWorker::BaseWorker(IThreadWorkerCallbacks *hooks) :
|
|||||||
|
|
||||||
BaseWorker::~BaseWorker()
|
BaseWorker::~BaseWorker()
|
||||||
{
|
{
|
||||||
if (m_state != Worker_Stopped || m_state != Worker_Invalid)
|
if (m_state != Worker_Stopped && m_state != Worker_Invalid)
|
||||||
Stop(true);
|
Stop(true);
|
||||||
|
|
||||||
if (m_ThreadQueue.size())
|
if (m_ThreadQueue.size())
|
||||||
@ -43,6 +43,7 @@ class BaseWorker;
|
|||||||
class SWThreadHandle : public IThreadHandle
|
class SWThreadHandle : public IThreadHandle
|
||||||
{
|
{
|
||||||
friend class BaseWorker;
|
friend class BaseWorker;
|
||||||
|
friend class CompatWorker;
|
||||||
public:
|
public:
|
||||||
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
||||||
IThread *GetThread();
|
IThread *GetThread();
|
||||||
@ -31,8 +31,10 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "CDataPack.h"
|
#include "CDataPack.h"
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
|
|
||||||
CDataPack::CDataPack()
|
CDataPack::CDataPack()
|
||||||
{
|
{
|
||||||
@ -44,33 +46,15 @@ CDataPack::~CDataPack()
|
|||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ke::Vector<ke::AutoPtr<CDataPack>> sDataPackCache;
|
|
||||||
|
|
||||||
CDataPack *CDataPack::New()
|
|
||||||
{
|
|
||||||
if (sDataPackCache.empty())
|
|
||||||
return new CDataPack();
|
|
||||||
|
|
||||||
CDataPack *pack = sDataPackCache.back().take();
|
|
||||||
sDataPackCache.pop();
|
|
||||||
pack->Initialize();
|
|
||||||
return pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CDataPack::Free(CDataPack *pack)
|
|
||||||
{
|
|
||||||
sDataPackCache.append(static_cast<CDataPack *>(pack));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::Initialize()
|
void CDataPack::Initialize()
|
||||||
{
|
{
|
||||||
|
position = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
} while (this->RemoveItem());
|
} while (this->RemoveItem());
|
||||||
|
|
||||||
elements.clear();
|
elements.clear();
|
||||||
position = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::ResetSize()
|
void CDataPack::ResetSize()
|
||||||
@ -84,7 +68,7 @@ size_t CDataPack::CreateMemory(size_t size, void **addr)
|
|||||||
val.type = CDataPackType::Raw;
|
val.type = CDataPackType::Raw;
|
||||||
val.pData.vval = new uint8_t[size + sizeof(size)];
|
val.pData.vval = new uint8_t[size + sizeof(size)];
|
||||||
reinterpret_cast<size_t *>(val.pData.vval)[0] = size;
|
reinterpret_cast<size_t *>(val.pData.vval)[0] = size;
|
||||||
elements.insert(position, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
|
||||||
return position++;
|
return position++;
|
||||||
}
|
}
|
||||||
@ -94,7 +78,8 @@ void CDataPack::PackCell(cell_t cell)
|
|||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::Cell;
|
val.type = CDataPackType::Cell;
|
||||||
val.pData.cval = cell;
|
val.pData.cval = cell;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::PackFunction(cell_t function)
|
void CDataPack::PackFunction(cell_t function)
|
||||||
@ -102,7 +87,8 @@ void CDataPack::PackFunction(cell_t function)
|
|||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::Function;
|
val.type = CDataPackType::Function;
|
||||||
val.pData.cval = function;
|
val.pData.cval = function;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::PackFloat(float floatval)
|
void CDataPack::PackFloat(float floatval)
|
||||||
@ -110,16 +96,42 @@ void CDataPack::PackFloat(float floatval)
|
|||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::Float;
|
val.type = CDataPackType::Float;
|
||||||
val.pData.fval = floatval;
|
val.pData.fval = floatval;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::PackString(const char *string)
|
void CDataPack::PackString(const char *string)
|
||||||
{
|
{
|
||||||
InternalPack val;
|
InternalPack val;
|
||||||
val.type = CDataPackType::String;
|
val.type = CDataPackType::String;
|
||||||
ke::AString *sval = new ke::AString(string);
|
std::string *sval = new std::string(string);
|
||||||
val.pData.sval = sval;
|
val.pData.sval = sval;
|
||||||
elements.insert(position++, val);
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDataPack::PackCellArray(cell_t const *vals, cell_t count)
|
||||||
|
{
|
||||||
|
InternalPack val;
|
||||||
|
val.type = CDataPackType::CellArray;
|
||||||
|
|
||||||
|
val.pData.aval = new cell_t [count + 1];
|
||||||
|
memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count);
|
||||||
|
val.pData.aval[0] = count;
|
||||||
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDataPack::PackFloatArray(cell_t const *vals, cell_t count)
|
||||||
|
{
|
||||||
|
InternalPack val;
|
||||||
|
val.type = CDataPackType::FloatArray;
|
||||||
|
|
||||||
|
val.pData.aval = new cell_t [count + 1];
|
||||||
|
memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count);
|
||||||
|
val.pData.aval[0] = count;
|
||||||
|
elements.emplace(elements.begin() + position, val);
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDataPack::Reset() const
|
void CDataPack::Reset() const
|
||||||
@ -134,7 +146,7 @@ size_t CDataPack::GetPosition() const
|
|||||||
|
|
||||||
bool CDataPack::SetPosition(size_t pos) const
|
bool CDataPack::SetPosition(size_t pos) const
|
||||||
{
|
{
|
||||||
if (pos > elements.length())
|
if (pos > elements.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
position = pos;
|
position = pos;
|
||||||
@ -167,7 +179,7 @@ float CDataPack::ReadFloat() const
|
|||||||
|
|
||||||
bool CDataPack::IsReadable(size_t bytes) const
|
bool CDataPack::IsReadable(size_t bytes) const
|
||||||
{
|
{
|
||||||
return (position < elements.length());
|
return (position < elements.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CDataPack::ReadString(size_t *len) const
|
const char *CDataPack::ReadString(size_t *len) const
|
||||||
@ -180,11 +192,51 @@ const char *CDataPack::ReadString(size_t *len) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ke::AString &val = *elements[position++].pData.sval;
|
const std::string &val = *elements[position++].pData.sval;
|
||||||
if (len)
|
if (len)
|
||||||
*len = val.length();
|
*len = val.size();
|
||||||
|
|
||||||
return val.chars();
|
return val.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *CDataPack::ReadCellArray(cell_t *size) const
|
||||||
|
{
|
||||||
|
if (!IsReadable() || elements[position].type != CDataPackType::CellArray)
|
||||||
|
{
|
||||||
|
if(size)
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *val = elements[position].pData.aval;
|
||||||
|
cell_t *ptr = &(val[1]);
|
||||||
|
++position;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = val[0];
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *CDataPack::ReadFloatArray(cell_t *size) const
|
||||||
|
{
|
||||||
|
if (!IsReadable() || elements[position].type != CDataPackType::FloatArray)
|
||||||
|
{
|
||||||
|
if(size)
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *val = elements[position].pData.aval;
|
||||||
|
cell_t *ptr = &(val[1]);
|
||||||
|
++position;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = val[0];
|
||||||
|
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *CDataPack::ReadMemory(size_t *size) const
|
void *CDataPack::ReadMemory(size_t *size) const
|
||||||
@ -205,7 +257,7 @@ void *CDataPack::ReadMemory(size_t *size) const
|
|||||||
|
|
||||||
bool CDataPack::RemoveItem(size_t pos)
|
bool CDataPack::RemoveItem(size_t pos)
|
||||||
{
|
{
|
||||||
if (!elements.length())
|
if (!elements.size())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -214,7 +266,8 @@ bool CDataPack::RemoveItem(size_t pos)
|
|||||||
{
|
{
|
||||||
pos = position;
|
pos = position;
|
||||||
}
|
}
|
||||||
if (pos >= elements.length())
|
|
||||||
|
if (pos >= elements.size())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -228,7 +281,7 @@ bool CDataPack::RemoveItem(size_t pos)
|
|||||||
{
|
{
|
||||||
case CDataPackType::Raw:
|
case CDataPackType::Raw:
|
||||||
{
|
{
|
||||||
delete elements[pos].pData.vval;
|
delete [] elements[pos].pData.vval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,8 +290,15 @@ bool CDataPack::RemoveItem(size_t pos)
|
|||||||
delete elements[pos].pData.sval;
|
delete elements[pos].pData.sval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CDataPackType::CellArray:
|
||||||
|
case CDataPackType::FloatArray:
|
||||||
|
{
|
||||||
|
delete [] elements[pos].pData.aval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.remove(pos);
|
elements.erase(elements.begin() + pos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,9 @@ enum CDataPackType {
|
|||||||
Cell,
|
Cell,
|
||||||
Float,
|
Float,
|
||||||
String,
|
String,
|
||||||
Function
|
Function,
|
||||||
|
CellArray,
|
||||||
|
FloatArray,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDataPack
|
class CDataPack
|
||||||
@ -52,9 +54,6 @@ public:
|
|||||||
CDataPack();
|
CDataPack();
|
||||||
~CDataPack();
|
~CDataPack();
|
||||||
|
|
||||||
static CDataPack *New();
|
|
||||||
static void Free(CDataPack *pack);
|
|
||||||
|
|
||||||
public: // Originally IDataReader
|
public: // Originally IDataReader
|
||||||
/**
|
/**
|
||||||
* @brief Resets the position in the data stream to the beginning.
|
* @brief Resets the position in the data stream to the beginning.
|
||||||
@ -90,6 +89,21 @@ public: // Originally IDataReader
|
|||||||
*/
|
*/
|
||||||
float ReadFloat() const;
|
float ReadFloat() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads an array of values from the data stream.
|
||||||
|
*
|
||||||
|
* @param len The size of the array stored at this position to return.
|
||||||
|
* @return A cell array read from the current position.
|
||||||
|
*/
|
||||||
|
cell_t *ReadCellArray(cell_t *len) const;
|
||||||
|
/**
|
||||||
|
* @brief Reads an array of values from the data stream.
|
||||||
|
*
|
||||||
|
* @param len The size of the array stored at this position to return.
|
||||||
|
* @return A cell array read from the current position.
|
||||||
|
*/
|
||||||
|
cell_t *ReadFloatArray(cell_t *len) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns whether or not a specified number of bytes from the current stream
|
* @brief Returns whether or not a specified number of bytes from the current stream
|
||||||
* position to the end can be read.
|
* position to the end can be read.
|
||||||
@ -150,6 +164,21 @@ public: // Originally IDataPack
|
|||||||
*/
|
*/
|
||||||
void PackString(const char *string);
|
void PackString(const char *string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Packs an array of cells into the data stream.
|
||||||
|
*
|
||||||
|
* @param vals Cells to write.
|
||||||
|
* @param count Number of cells.
|
||||||
|
*/
|
||||||
|
void PackCellArray(cell_t const *vals, cell_t count);
|
||||||
|
/**
|
||||||
|
* @brief Packs an array of cells into the data stream.
|
||||||
|
*
|
||||||
|
* @param vals Cells to write.
|
||||||
|
* @param count Number of cells.
|
||||||
|
*/
|
||||||
|
void PackFloatArray(cell_t const *vals, cell_t count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a generic block of memory in the stream.
|
* @brief Creates a generic block of memory in the stream.
|
||||||
*
|
*
|
||||||
@ -172,7 +201,7 @@ public: // Originally IDataPack
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
inline size_t GetCapacity() const { return this->elements.length(); };
|
inline size_t GetCapacity() const { return this->elements.size(); };
|
||||||
inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; };
|
inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; };
|
||||||
bool RemoveItem(size_t pos = -1);
|
bool RemoveItem(size_t pos = -1);
|
||||||
|
|
||||||
@ -181,7 +210,8 @@ private:
|
|||||||
cell_t cval;
|
cell_t cval;
|
||||||
float fval;
|
float fval;
|
||||||
uint8_t *vval;
|
uint8_t *vval;
|
||||||
ke::AString *sval;
|
std::string *sval;
|
||||||
|
cell_t *aval;
|
||||||
} InternalPackValue;
|
} InternalPackValue;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -189,7 +219,7 @@ private:
|
|||||||
CDataPackType type;
|
CDataPackType type;
|
||||||
} InternalPack;
|
} InternalPack;
|
||||||
|
|
||||||
ke::Vector<InternalPack> elements;
|
std::vector<InternalPack> elements;
|
||||||
mutable size_t position;
|
mutable size_t position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ICellArray.h>
|
#include <ICellArray.h>
|
||||||
|
#include <amtl/am-bits.h>
|
||||||
|
|
||||||
extern HandleType_t htCellArray;
|
extern HandleType_t htCellArray;
|
||||||
|
|
||||||
@ -214,30 +215,34 @@ private:
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
size_t newAllocSize = m_AllocSize;
|
||||||
/* Set a base allocation size of 8 items */
|
/* Set a base allocation size of 8 items */
|
||||||
if (!m_AllocSize)
|
if (!newAllocSize)
|
||||||
{
|
{
|
||||||
m_AllocSize = 8;
|
newAllocSize = 8;
|
||||||
|
}
|
||||||
|
if (!ke::IsUintPtrAddSafe(m_Size, count))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
/* If it's not enough, keep doubling */
|
/* If it's not enough, keep doubling */
|
||||||
while (m_Size + count > m_AllocSize)
|
while (m_Size + count > newAllocSize)
|
||||||
{
|
{
|
||||||
m_AllocSize *= 2;
|
if (!ke::IsUintPtrMultiplySafe(newAllocSize, 2))
|
||||||
}
|
|
||||||
/* finally, allocate the new block */
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize));
|
|
||||||
if (!data) // allocation failure
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
newAllocSize *= 2;
|
||||||
m_Data = data;
|
|
||||||
} else {
|
|
||||||
m_Data = static_cast<cell_t*>(malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize));
|
|
||||||
}
|
}
|
||||||
return (m_Data != nullptr);
|
/* finally, allocate the new block */
|
||||||
|
cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * newAllocSize));
|
||||||
|
/* Update state if allocation was successful */
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
m_AllocSize = newAllocSize;
|
||||||
|
m_Data = data;
|
||||||
|
}
|
||||||
|
return (data != nullptr);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
cell_t *m_Data;
|
cell_t *m_Data;
|
||||||
|
|||||||
@ -34,17 +34,20 @@
|
|||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <amtl/am-thread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <bridge/include/ILogger.h>
|
#include <bridge/include/ILogger.h>
|
||||||
#include <bridge/include/CoreProvider.h>
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
#define DBPARSE_LEVEL_NONE 0
|
#define DBPARSE_LEVEL_NONE 0
|
||||||
#define DBPARSE_LEVEL_MAIN 1
|
#define DBPARSE_LEVEL_MAIN 1
|
||||||
#define DBPARSE_LEVEL_DATABASE 2
|
#define DBPARSE_LEVEL_DATABASE 2
|
||||||
|
|
||||||
DBManager g_DBMan;
|
DBManager g_DBMan;
|
||||||
static bool s_OneTimeThreaderErrorMsg = false;
|
|
||||||
|
|
||||||
DBManager::DBManager()
|
DBManager::DBManager()
|
||||||
: m_Terminate(false),
|
: m_Terminate(false),
|
||||||
@ -125,8 +128,8 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
|||||||
|
|
||||||
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
|
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::RefPtr<ConfDbInfo> pInfo = list->GetDatabaseConf(name);
|
ke::RefPtr<ConfDbInfo> pInfo = list.GetDatabaseConf(name);
|
||||||
|
|
||||||
if (!pInfo)
|
if (!pInfo)
|
||||||
{
|
{
|
||||||
@ -145,12 +148,12 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
|
|||||||
/* Try to assign a real driver pointer */
|
/* Try to assign a real driver pointer */
|
||||||
if (pInfo->info.driver[0] == '\0')
|
if (pInfo->info.driver[0] == '\0')
|
||||||
{
|
{
|
||||||
ke::AString defaultDriver = list->GetDefaultDriver();
|
std::string defaultDriver = list.GetDefaultDriver();
|
||||||
if (!m_pDefault && defaultDriver.length() > 0)
|
if (!m_pDefault && defaultDriver.length() > 0)
|
||||||
{
|
{
|
||||||
m_pDefault = FindOrLoadDriver(defaultDriver.chars());
|
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||||
}
|
}
|
||||||
dname = defaultDriver.length() ? defaultDriver.chars() : "default";
|
dname = defaultDriver.length() ? defaultDriver.c_str() : "default";
|
||||||
pInfo->realDriver = m_pDefault;
|
pInfo->realDriver = m_pDefault;
|
||||||
} else {
|
} else {
|
||||||
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
|
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
|
||||||
@ -206,17 +209,14 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
for (size_t i = 0; i < list->length(); i++)
|
for (auto conf : list) {
|
||||||
{
|
if (conf->realDriver == pDriver)
|
||||||
ke::RefPtr<ConfDbInfo> current = list->at(i);
|
|
||||||
if (current->realDriver == pDriver)
|
|
||||||
{
|
{
|
||||||
current->realDriver = NULL;
|
conf->realDriver = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Someone unloaded the default driver? Silly.. */
|
/* Someone unloaded the default driver? Silly.. */
|
||||||
if (pDriver == m_pDefault)
|
if (pDriver == m_pDefault)
|
||||||
{
|
{
|
||||||
@ -252,11 +252,11 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
|||||||
|
|
||||||
IDBDriver *DBManager::GetDefaultDriver()
|
IDBDriver *DBManager::GetDefaultDriver()
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::AString defaultDriver = list->GetDefaultDriver();
|
std::string defaultDriver = list.GetDefaultDriver();
|
||||||
if (!m_pDefault && defaultDriver.length() > 0)
|
if (!m_pDefault && defaultDriver.length() > 0)
|
||||||
{
|
{
|
||||||
m_pDefault = FindOrLoadDriver(defaultDriver.chars());
|
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_pDefault;
|
return m_pDefault;
|
||||||
@ -319,12 +319,12 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
|
|||||||
|
|
||||||
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::RefPtr<ConfDbInfo> info = list->GetDatabaseConf(name);
|
ke::RefPtr<ConfDbInfo> info = list.GetDatabaseConf(name);
|
||||||
if (!info)
|
if (!info)
|
||||||
{
|
{
|
||||||
// couldn't find requested conf, return default if exists
|
// couldn't find requested conf, return default if exists
|
||||||
info = list->GetDefaultConfiguration();
|
info = list.GetDefaultConfiguration();
|
||||||
if (!info)
|
if (!info)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -334,11 +334,10 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
|||||||
return &info->info;
|
return &info->info;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
|
ke::RefPtr<ConfDbInfo> DBManager::GetDatabaseConf(const char *name)
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name));
|
return list.GetDatabaseConf(name);
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||||
@ -377,13 +376,12 @@ void DBManager::KillWorkerThread()
|
|||||||
if (m_Worker)
|
if (m_Worker)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_QueueEvent);
|
std::lock_guard<std::mutex> lock(m_Lock);
|
||||||
m_Terminate = true;
|
m_Terminate = true;
|
||||||
m_QueueEvent.Notify();
|
m_QueueEvent.notify_all();
|
||||||
}
|
}
|
||||||
m_Worker->Join();
|
m_Worker->join();
|
||||||
m_Worker = nullptr;
|
m_Worker = nullptr;
|
||||||
s_OneTimeThreaderErrorMsg = false;
|
|
||||||
m_Terminate = false;
|
m_Terminate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,27 +397,17 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
|
|||||||
|
|
||||||
if (!m_Worker)
|
if (!m_Worker)
|
||||||
{
|
{
|
||||||
m_Worker = new ke::Thread([this]() -> void {
|
m_Worker = ke::NewThread("SM Database Worker", [this]() -> void {
|
||||||
Run();
|
Run();
|
||||||
}, "SM SQL Worker");
|
});
|
||||||
if (!m_Worker->Succeeded())
|
|
||||||
{
|
|
||||||
if (!s_OneTimeThreaderErrorMsg)
|
|
||||||
{
|
|
||||||
logger->LogError("[SM] Unable to create db threader (error unknown)");
|
|
||||||
s_OneTimeThreaderErrorMsg = true;
|
|
||||||
}
|
|
||||||
m_Worker = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add to the queue */
|
/* Add to the queue */
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_QueueEvent);
|
std::lock_guard<std::mutex> lock(m_Lock);
|
||||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio);
|
||||||
queue.push(op);
|
queue.push(op);
|
||||||
m_QueueEvent.Notify();
|
m_QueueEvent.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -450,7 +438,7 @@ void DBManager::Run()
|
|||||||
|
|
||||||
void DBManager::ThreadMain()
|
void DBManager::ThreadMain()
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_QueueEvent);
|
std::unique_lock<std::mutex> lock(m_Lock);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// The lock has been acquired. Grab everything we can out of the
|
// The lock has been acquired. Grab everything we can out of the
|
||||||
@ -458,46 +446,43 @@ void DBManager::ThreadMain()
|
|||||||
// we process all operations we can before checking to terminate.
|
// we process all operations we can before checking to terminate.
|
||||||
// There's no risk of starvation since the main thread blocks on us
|
// There's no risk of starvation since the main thread blocks on us
|
||||||
// terminating.
|
// terminating.
|
||||||
while (true)
|
auto queue = &m_OpQueue.GetLikelyQueue();
|
||||||
{
|
if (queue->empty()) {
|
||||||
Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
|
// If the queue is empty and we've been asked to stop, leave now.
|
||||||
if (queue.empty())
|
if (m_Terminate)
|
||||||
break;
|
return;
|
||||||
|
|
||||||
IDBThreadOperation *op = queue.first();
|
// Otherwise, wait for something to happen.
|
||||||
queue.pop();
|
m_QueueEvent.wait(lock);
|
||||||
|
continue;
|
||||||
// Unlock the queue when we run the query, so the main thread can
|
|
||||||
// keep pumping events. We re-acquire the lock to check for more
|
|
||||||
// items. It's okay if we terminate while unlocked; the main
|
|
||||||
// thread would be blocked and we'd need to flush the queue
|
|
||||||
// anyway, so after we've depleted the queue here, we'll just
|
|
||||||
// reach the terminate at the top of the loop.
|
|
||||||
{
|
|
||||||
ke::AutoUnlock unlock(&m_QueueEvent);
|
|
||||||
op->RunThreadPart();
|
|
||||||
|
|
||||||
ke::AutoLock lock(&m_ThinkLock);
|
|
||||||
m_ThinkQueue.push(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!m_Terminate)
|
|
||||||
{
|
|
||||||
ke::AutoUnlock unlock(&m_QueueEvent);
|
|
||||||
#ifdef _WIN32
|
|
||||||
Sleep(20);
|
|
||||||
#else
|
|
||||||
usleep(20000);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Terminate)
|
IDBThreadOperation *op = queue->first();
|
||||||
return;
|
queue->pop();
|
||||||
|
|
||||||
// Release the lock and wait for a signal.
|
// Unlock the queue when we run the query, so the main thread can
|
||||||
m_QueueEvent.Wait();
|
// keep pumping events. We re-acquire the lock to check for more
|
||||||
|
// items. It's okay if we terminate while unlocked; the main
|
||||||
|
// thread would be blocked and we'd need to flush the queue
|
||||||
|
// anyway, so after we've depleted the queue here, we'll just
|
||||||
|
// reach the terminate at the top of the loop.
|
||||||
|
lock.unlock();
|
||||||
|
op->RunThreadPart();
|
||||||
|
|
||||||
|
// Re-acquire the lock and give the data back to the main thread
|
||||||
|
// immediately. We use a separate lock to minimize game thread
|
||||||
|
// contention.
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> think_lock(m_ThinkLock);
|
||||||
|
m_ThinkQueue.push(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we add a 20ms delay after processing a query. This is
|
||||||
|
// questionable but the intent is to avoid starving the game thread.
|
||||||
|
if (!m_Terminate)
|
||||||
|
std::this_thread::sleep_for(20ms);
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,7 +497,7 @@ void DBManager::RunFrame()
|
|||||||
/* Dump one thing per-frame so the server stays sane. */
|
/* Dump one thing per-frame so the server stays sane. */
|
||||||
IDBThreadOperation *op;
|
IDBThreadOperation *op;
|
||||||
{
|
{
|
||||||
ke::AutoLock lock(&m_ThinkLock);
|
std::lock_guard<std::mutex> lock(m_ThinkLock);
|
||||||
op = m_ThinkQueue.first();
|
op = m_ThinkQueue.first();
|
||||||
m_ThinkQueue.pop();
|
m_ThinkQueue.pop();
|
||||||
}
|
}
|
||||||
@ -591,10 +576,10 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::AString DBManager::GetDefaultDriverName()
|
std::string DBManager::GetDefaultDriverName()
|
||||||
{
|
{
|
||||||
ConfDbInfoList *list = m_Builder.GetConfigList();
|
ConfDbInfoList &list = m_Builder.GetConfigList();
|
||||||
return list->GetDefaultDriver();
|
return list.GetDefaultDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
|
||||||
|
|||||||
@ -38,7 +38,10 @@
|
|||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <am-thread-utils.h>
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include "sm_simple_prioqueue.h"
|
#include "sm_simple_prioqueue.h"
|
||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
#include "DatabaseConfBuilder.h"
|
#include "DatabaseConfBuilder.h"
|
||||||
@ -68,7 +71,7 @@ public: //IDBManager
|
|||||||
void AddDriver(IDBDriver *pDrivera);
|
void AddDriver(IDBDriver *pDrivera);
|
||||||
void RemoveDriver(IDBDriver *pDriver);
|
void RemoveDriver(IDBDriver *pDriver);
|
||||||
const DatabaseInfo *FindDatabaseConf(const char *name);
|
const DatabaseInfo *FindDatabaseConf(const char *name);
|
||||||
ConfDbInfo *GetDatabaseConf(const char *name);
|
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name);
|
||||||
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
|
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
|
||||||
unsigned int GetDriverCount();
|
unsigned int GetDriverCount();
|
||||||
IDBDriver *GetDriver(unsigned int index);
|
IDBDriver *GetDriver(unsigned int index);
|
||||||
@ -84,7 +87,7 @@ public: //IPluginsListener
|
|||||||
public:
|
public:
|
||||||
IDBDriver *FindOrLoadDriver(const char *name);
|
IDBDriver *FindOrLoadDriver(const char *name);
|
||||||
IDBDriver *GetDefaultDriver();
|
IDBDriver *GetDefaultDriver();
|
||||||
ke::AString GetDefaultDriverName();
|
std::string GetDefaultDriverName();
|
||||||
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
|
bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio);
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
inline HandleType_t GetDatabaseType()
|
inline HandleType_t GetDatabaseType()
|
||||||
@ -101,9 +104,10 @@ private:
|
|||||||
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
PrioQueue<IDBThreadOperation *> m_OpQueue;
|
||||||
Queue<IDBThreadOperation *> m_ThinkQueue;
|
Queue<IDBThreadOperation *> m_ThinkQueue;
|
||||||
CVector<bool> m_drSafety; /* which drivers are safe? */
|
CVector<bool> m_drSafety; /* which drivers are safe? */
|
||||||
ke::AutoPtr<ke::Thread> m_Worker;
|
std::unique_ptr<std::thread> m_Worker;
|
||||||
ke::ConditionVariable m_QueueEvent;
|
std::condition_variable m_QueueEvent;
|
||||||
ke::Mutex m_ThinkLock;
|
std::mutex m_ThinkLock;
|
||||||
|
std::mutex m_Lock;
|
||||||
bool m_Terminate;
|
bool m_Terminate;
|
||||||
|
|
||||||
DatabaseConfBuilder m_Builder;
|
DatabaseConfBuilder m_Builder;
|
||||||
|
|||||||
@ -36,8 +36,8 @@
|
|||||||
#define DBPARSE_LEVEL_DATABASE 2
|
#define DBPARSE_LEVEL_DATABASE 2
|
||||||
|
|
||||||
DatabaseConfBuilder::DatabaseConfBuilder()
|
DatabaseConfBuilder::DatabaseConfBuilder()
|
||||||
: m_ParseList(nullptr),
|
: m_ParseList(),
|
||||||
m_InfoList(new ConfDbInfoList())
|
m_InfoList()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ DatabaseConfBuilder::~DatabaseConfBuilder()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfoList *DatabaseConfBuilder::GetConfigList()
|
ConfDbInfoList &DatabaseConfBuilder::GetConfigList()
|
||||||
{
|
{
|
||||||
return m_InfoList;
|
return m_InfoList;
|
||||||
}
|
}
|
||||||
@ -59,9 +59,9 @@ void DatabaseConfBuilder::StartParse()
|
|||||||
{
|
{
|
||||||
SMCError err;
|
SMCError err;
|
||||||
SMCStates states = {0, 0};
|
SMCStates states = {0, 0};
|
||||||
if ((err = textparsers->ParseFile_SMC(m_Filename.chars(), this, &states)) != SMCError_Okay)
|
if ((err = textparsers->ParseFile_SMC(m_Filename.c_str(), this, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.chars());
|
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.c_str());
|
||||||
if (err != SMCError_Custom)
|
if (err != SMCError_Custom)
|
||||||
{
|
{
|
||||||
const char *txt = textparsers->GetSMCErrorString(err);
|
const char *txt = textparsers->GetSMCErrorString(err);
|
||||||
@ -75,7 +75,7 @@ void DatabaseConfBuilder::ReadSMC_ParseStart()
|
|||||||
m_ParseLevel = 0;
|
m_ParseLevel = 0;
|
||||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||||
|
|
||||||
m_ParseList = new ConfDbInfoList();
|
m_ParseList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCResult DatabaseConfBuilder::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
SMCResult DatabaseConfBuilder::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
@ -116,7 +116,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_KeyValue(const SMCStates *states, const c
|
|||||||
{
|
{
|
||||||
if (strcmp(key, "driver_default") == 0)
|
if (strcmp(key, "driver_default") == 0)
|
||||||
{
|
{
|
||||||
m_ParseList->SetDefaultDriver(value);
|
m_ParseList.SetDefaultDriver(value);
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||||
if (strcmp(key, "driver") == 0)
|
if (strcmp(key, "driver") == 0)
|
||||||
@ -153,15 +153,15 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
|
|
||||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||||
{
|
{
|
||||||
m_ParseCurrent->info.driver = m_ParseCurrent->driver.chars();
|
m_ParseCurrent->info.driver = m_ParseCurrent->driver.c_str();
|
||||||
m_ParseCurrent->info.database = m_ParseCurrent->database.chars();
|
m_ParseCurrent->info.database = m_ParseCurrent->database.c_str();
|
||||||
m_ParseCurrent->info.host = m_ParseCurrent->host.chars();
|
m_ParseCurrent->info.host = m_ParseCurrent->host.c_str();
|
||||||
m_ParseCurrent->info.user = m_ParseCurrent->user.chars();
|
m_ParseCurrent->info.user = m_ParseCurrent->user.c_str();
|
||||||
m_ParseCurrent->info.pass = m_ParseCurrent->pass.chars();
|
m_ParseCurrent->info.pass = m_ParseCurrent->pass.c_str();
|
||||||
|
|
||||||
/* Save it.. */
|
/* Save it.. */
|
||||||
m_ParseCurrent->AddRef();
|
m_ParseCurrent->AddRef();
|
||||||
m_ParseList->append(m_ParseCurrent);
|
m_ParseList.push_back(m_ParseCurrent);
|
||||||
m_ParseCurrent = nullptr;
|
m_ParseCurrent = nullptr;
|
||||||
|
|
||||||
/* Go up one level */
|
/* Go up one level */
|
||||||
@ -176,9 +176,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
|
|
||||||
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
|
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||||
{
|
{
|
||||||
m_InfoList->ReleaseMembers();
|
m_InfoList.clear();
|
||||||
delete m_InfoList;
|
|
||||||
m_InfoList = m_ParseList;
|
m_InfoList = m_ParseList;
|
||||||
|
m_ParseList.clear();
|
||||||
m_ParseList = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
|
#include <am-refcounting.h>
|
||||||
#include <am-refcounting-threadsafe.h>
|
#include <am-refcounting-threadsafe.h>
|
||||||
|
|
||||||
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
|
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
|
||||||
@ -46,58 +47,53 @@ public:
|
|||||||
ConfDbInfo() : realDriver(NULL)
|
ConfDbInfo() : realDriver(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ke::AString name;
|
std::string name;
|
||||||
ke::AString driver;
|
std::string driver;
|
||||||
ke::AString host;
|
std::string host;
|
||||||
ke::AString user;
|
std::string user;
|
||||||
ke::AString pass;
|
std::string pass;
|
||||||
ke::AString database;
|
std::string database;
|
||||||
IDBDriver *realDriver;
|
IDBDriver *realDriver;
|
||||||
DatabaseInfo info;
|
DatabaseInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfDbInfoList : public ke::Vector<ConfDbInfo *>
|
class ConfDbInfoList : public std::vector<ke::RefPtr<ConfDbInfo>>
|
||||||
{
|
{
|
||||||
/* Allow internal usage of ConfDbInfoList */
|
/* Allow internal usage of ConfDbInfoList */
|
||||||
friend class DBManager;
|
friend class DBManager;
|
||||||
friend class DatabaseConfBuilder;
|
friend class DatabaseConfBuilder;
|
||||||
private:
|
private:
|
||||||
ke::AString& GetDefaultDriver() {
|
std::string& GetDefaultDriver() {
|
||||||
return m_DefDriver;
|
return m_DefDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfo *GetDatabaseConf(const char *name) {
|
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name) {
|
||||||
for (size_t i = 0; i < this->length(); i++)
|
for (size_t i = 0; i < this->size(); i++)
|
||||||
{
|
{
|
||||||
ConfDbInfo *current = this->at(i);
|
ke::RefPtr<ConfDbInfo> current = this->at(i);
|
||||||
/* If we run into the default configuration, then we'll save it
|
/* If we run into the default configuration, then we'll save it
|
||||||
* for the next call to GetDefaultConfiguration */
|
* for the next call to GetDefaultConfiguration */
|
||||||
if (strcmp(current->name.chars(), "default") == 0)
|
if (strcmp(current->name.c_str(), "default") == 0)
|
||||||
{
|
{
|
||||||
m_DefaultConfig = current;
|
m_DefaultConfig = current;
|
||||||
}
|
}
|
||||||
if (strcmp(current->name.chars(), name) == 0)
|
if (strcmp(current->name.c_str(), name) == 0)
|
||||||
{
|
{
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
ConfDbInfo *GetDefaultConfiguration() {
|
|
||||||
|
ke::RefPtr<ConfDbInfo> GetDefaultConfiguration() {
|
||||||
return m_DefaultConfig;
|
return m_DefaultConfig;
|
||||||
}
|
}
|
||||||
void SetDefaultDriver(const char *input) {
|
void SetDefaultDriver(const char *input) {
|
||||||
m_DefDriver = ke::AString(input);
|
m_DefDriver = std::string(input);
|
||||||
}
|
|
||||||
void ReleaseMembers() {
|
|
||||||
for (size_t i = 0; i < this->length(); i++) {
|
|
||||||
ConfDbInfo *current = this->at(i);
|
|
||||||
current->Release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
ConfDbInfo *m_DefaultConfig;
|
ke::RefPtr<ConfDbInfo> m_DefaultConfig;
|
||||||
ke::AString m_DefDriver;
|
std::string m_DefDriver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +104,7 @@ public:
|
|||||||
~DatabaseConfBuilder();
|
~DatabaseConfBuilder();
|
||||||
void StartParse();
|
void StartParse();
|
||||||
void SetPath(char* path);
|
void SetPath(char* path);
|
||||||
ConfDbInfoList *GetConfigList();
|
ConfDbInfoList &GetConfigList();
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
@ -120,10 +116,10 @@ private:
|
|||||||
unsigned int m_ParseLevel;
|
unsigned int m_ParseLevel;
|
||||||
unsigned int m_ParseState;
|
unsigned int m_ParseState;
|
||||||
ConfDbInfo *m_ParseCurrent;
|
ConfDbInfo *m_ParseCurrent;
|
||||||
ConfDbInfoList *m_ParseList;
|
ConfDbInfoList m_ParseList;
|
||||||
private:
|
private:
|
||||||
ke::AString m_Filename;
|
std::string m_Filename;
|
||||||
ConfDbInfoList *m_InfoList;
|
ConfDbInfoList m_InfoList;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
|
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
|
||||||
|
|||||||
@ -69,13 +69,13 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
|
|||||||
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
|
||||||
|
|
||||||
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||||
const char *error = g_pSourcePawn2->GetErrorString(err);
|
|
||||||
|
|
||||||
if (error)
|
if (err >= 0) {
|
||||||
{
|
const char *error = g_pSourcePawn2->GetErrorString(err);
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
if (error)
|
||||||
} else {
|
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
else
|
||||||
|
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] %s", buffer);
|
g_Logger.LogError("[SM] %s", buffer);
|
||||||
@ -194,22 +194,22 @@ void DebugReport::ReportError(const IErrorReport &report, IFrameIterator &iter)
|
|||||||
g_Logger.LogError("[SM] Blaming: %s", blame);
|
g_Logger.LogError("[SM] Blaming: %s", blame);
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::Vector<ke::AString> arr = GetStackTrace(&iter);
|
std::vector<std::string> arr = GetStackTrace(&iter);
|
||||||
for (size_t i = 0; i < arr.length(); i++)
|
for (size_t i = 0; i < arr.size(); i++)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("%s", arr[i].chars());
|
g_Logger.LogError("%s", arr[i].c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
|
std::vector<std::string> DebugReport::GetStackTrace(IFrameIterator *iter)
|
||||||
{
|
{
|
||||||
char temp[3072];
|
char temp[3072];
|
||||||
ke::Vector<ke::AString> trace;
|
std::vector<std::string> trace;
|
||||||
iter->Reset();
|
iter->Reset();
|
||||||
|
|
||||||
if (!iter->Done())
|
if (!iter->Done())
|
||||||
{
|
{
|
||||||
trace.append("[SM] Call stack trace:");
|
trace.push_back("[SM] Call stack trace:");
|
||||||
|
|
||||||
for (int index = 0; !iter->Done(); iter->Next(), index++)
|
for (int index = 0; !iter->Done(); iter->Next(), index++)
|
||||||
{
|
{
|
||||||
@ -221,7 +221,7 @@ ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
|
|||||||
if (iter->IsNativeFrame())
|
if (iter->IsNativeFrame())
|
||||||
{
|
{
|
||||||
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] %s", index, fn);
|
g_pSM->Format(temp, sizeof(temp), "[SM] [%d] %s", index, fn);
|
||||||
trace.append(temp);
|
trace.push_back(temp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (iter->IsScriptedFrame())
|
if (iter->IsScriptedFrame())
|
||||||
@ -237,7 +237,7 @@ ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter)
|
|||||||
file,
|
file,
|
||||||
fn);
|
fn);
|
||||||
|
|
||||||
trace.append(temp);
|
trace.push_back(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,10 +47,12 @@ public: // IDebugListener
|
|||||||
void ReportError(const IErrorReport &report, IFrameIterator &iter);
|
void ReportError(const IErrorReport &report, IFrameIterator &iter);
|
||||||
void OnDebugSpew(const char *msg, ...);
|
void OnDebugSpew(const char *msg, ...);
|
||||||
public:
|
public:
|
||||||
|
// If err is -1, caller assumes the automatic reporting by SourcePawn is
|
||||||
|
// good enough, and only wants the supplemental logging provided here.
|
||||||
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
||||||
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
|
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
|
||||||
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
|
||||||
ke::Vector<ke::AString> GetStackTrace(IFrameIterator *iter);
|
std::vector<std::string> GetStackTrace(IFrameIterator *iter);
|
||||||
private:
|
private:
|
||||||
int _GetPluginIndex(IPluginContext *ctx);
|
int _GetPluginIndex(IPluginContext *ctx);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,6 +30,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include <ILibrarySys.h>
|
#include <ILibrarySys.h>
|
||||||
#include <ISourceMod.h>
|
#include <ISourceMod.h>
|
||||||
@ -76,7 +79,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -85,7 +88,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s.%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s.%s." PLATFORM_LIB_EXT,
|
||||||
filename,
|
filename,
|
||||||
bridge->gamesuffix);
|
bridge->gamesuffix);
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s.2.ep2v." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s.2.ep2v." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
|
else if (strcmp(bridge->gamesuffix, "2.nd") == 0)
|
||||||
@ -108,7 +111,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s.2.l4d2." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s.2.l4d2." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +122,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/auto.%s/%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "auto.%s/%s." PLATFORM_LIB_EXT,
|
||||||
filename,
|
filename,
|
||||||
bridge->gamesuffix);
|
bridge->gamesuffix);
|
||||||
|
|
||||||
@ -129,7 +132,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired)
|
|||||||
g_pSM->BuildPath(Path_SM,
|
g_pSM->BuildPath(Path_SM,
|
||||||
path,
|
path,
|
||||||
PLATFORM_MAX_PATH,
|
PLATFORM_MAX_PATH,
|
||||||
"extensions/%s." PLATFORM_LIB_EXT,
|
"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT,
|
||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,6 +240,8 @@ void CLocalExtension::Unload()
|
|||||||
m_pLib->CloseLibrary();
|
m_pLib->CloseLibrary();
|
||||||
m_pLib = NULL;
|
m_pLib = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bFullyLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
bool CRemoteExtension::Reload(char *error, size_t maxlength)
|
||||||
@ -301,7 +306,7 @@ bool CExtension::Load(char *error, size_t maxlength)
|
|||||||
/* Check if we're past load time */
|
/* Check if we're past load time */
|
||||||
if (!bridge->IsMapLoading())
|
if (!bridge->IsMapLoading())
|
||||||
{
|
{
|
||||||
m_pAPI->OnExtensionsAllLoaded();
|
MarkAllLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -390,11 +395,6 @@ void CExtension::AddDependency(const IfaceInfo *pInfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
|
|
||||||
{
|
|
||||||
return (i1.iface == i2.iface) && (i1.owner == i2.owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
|
void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
|
||||||
{
|
{
|
||||||
IfaceInfo info;
|
IfaceInfo info;
|
||||||
@ -496,7 +496,7 @@ void CExtensionManager::TryAutoload()
|
|||||||
|
|
||||||
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
|
g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions");
|
||||||
|
|
||||||
ke::AutoPtr<IDirectory> pDir(libsys->OpenDirectory(path));
|
std::unique_ptr<IDirectory> pDir(libsys->OpenDirectory(path));
|
||||||
if (!pDir)
|
if (!pDir)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -628,9 +628,15 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
|||||||
|
|
||||||
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
|
if (strstr(file, "..") != NULL)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(error, maxlength, "Cannot load extensions outside the \"extensions\" folder.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove platform extension if it's there. Compat hack. */
|
/* Remove platform extension if it's there. Compat hack. */
|
||||||
const char *ext = libsys->GetFileExtension(file);
|
const char *ext = libsys->GetFileExtension(file);
|
||||||
if (strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
if (ext && strcmp(ext, PLATFORM_LIB_EXT) == 0)
|
||||||
{
|
{
|
||||||
char path2[PLATFORM_MAX_PATH];
|
char path2[PLATFORM_MAX_PATH];
|
||||||
ke::SafeStrcpy(path2, sizeof(path2), file);
|
ke::SafeStrcpy(path2, sizeof(path2), file);
|
||||||
@ -1171,7 +1177,6 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand
|
|||||||
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
|
rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srand(static_cast<int>(time(NULL)));
|
|
||||||
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
pExt->unload_code = (rand() % 877) + 123; //123 to 999
|
||||||
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
|
||||||
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
|
||||||
@ -1364,7 +1369,7 @@ bool CLocalExtension::IsSameFile(const char *file)
|
|||||||
|
|
||||||
bool CRemoteExtension::IsSameFile(const char *file)
|
bool CRemoteExtension::IsSameFile(const char *file)
|
||||||
{
|
{
|
||||||
/* :TODO: this could be better, but no one uses this API anyway. */
|
/* Check full path and name passed in from LoadExternal */
|
||||||
return strcmp(file, m_Path.c_str()) == 0;
|
return strcmp(file, m_Path.c_str()) == 0 || strcmp(file, m_File.c_str()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,7 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned
|
|||||||
{
|
{
|
||||||
scripts->AddFunctionsToForward(name, fwd);
|
scripts->AddFunctionsToForward(name, fwd);
|
||||||
|
|
||||||
m_managed.append(fwd);
|
m_managed.push_back(fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fwd;
|
return fwd;
|
||||||
@ -78,7 +78,7 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType
|
|||||||
|
|
||||||
if (fwd)
|
if (fwd)
|
||||||
{
|
{
|
||||||
m_unmanaged.append(fwd);
|
m_unmanaged.push_back(fwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fwd;
|
return fwd;
|
||||||
@ -751,9 +751,9 @@ bool CForward::AddFunction(IPluginFunction *func)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (func->IsRunnable())
|
if (func->IsRunnable())
|
||||||
m_functions.append(func);
|
m_functions.push_back(func);
|
||||||
else
|
else
|
||||||
m_paused.append(func);
|
m_paused.push_back(func);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -780,7 +780,7 @@ const char *CForward::GetForwardName()
|
|||||||
|
|
||||||
unsigned int CForward::GetFunctionCount()
|
unsigned int CForward::GetFunctionCount()
|
||||||
{
|
{
|
||||||
return m_functions.length();
|
return m_functions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecType CForward::GetExecType()
|
ExecType CForward::GetExecType()
|
||||||
|
|||||||
@ -36,7 +36,7 @@ SafeFrameIterator::SafeFrameIterator(IFrameIterator *it)
|
|||||||
while (!it->Done())
|
while (!it->Done())
|
||||||
{
|
{
|
||||||
FrameInfo info = FrameInfo(it);
|
FrameInfo info = FrameInfo(it);
|
||||||
frames.append(info);
|
frames.push_back(info);
|
||||||
it->Next();
|
it->Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ SafeFrameIterator::SafeFrameIterator(IFrameIterator *it)
|
|||||||
|
|
||||||
bool SafeFrameIterator::Done() const
|
bool SafeFrameIterator::Done() const
|
||||||
{
|
{
|
||||||
return current >= frames.length();
|
return current >= frames.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafeFrameIterator::Next()
|
bool SafeFrameIterator::Next()
|
||||||
@ -77,7 +77,7 @@ const char *SafeFrameIterator::FunctionName() const
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return frames[current].FunctionName.chars();
|
return frames[current].FunctionName.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *SafeFrameIterator::FilePath() const
|
const char *SafeFrameIterator::FilePath() const
|
||||||
@ -87,5 +87,5 @@ const char *SafeFrameIterator::FilePath() const
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return frames[current].FilePath.chars();
|
return frames[current].FilePath.c_str();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,16 +48,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
struct FrameInfo
|
struct FrameInfo
|
||||||
{
|
{
|
||||||
ke::AString FunctionName;
|
std::string FunctionName;
|
||||||
ke::AString FilePath;
|
std::string FilePath;
|
||||||
unsigned LineNumber;
|
unsigned LineNumber;
|
||||||
|
|
||||||
FrameInfo(IFrameIterator *it)
|
FrameInfo(IFrameIterator *it)
|
||||||
{
|
{
|
||||||
LineNumber = it->LineNumber();
|
LineNumber = it->LineNumber();
|
||||||
|
|
||||||
FunctionName = it->FunctionName();
|
if (it->FunctionName())
|
||||||
FilePath = it->FilePath();
|
FunctionName = it->FunctionName();
|
||||||
|
if (it->FilePath())
|
||||||
|
FilePath = it->FilePath();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,5 +75,5 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
size_t current;
|
size_t current;
|
||||||
ke::Vector<FrameInfo> frames;
|
std::vector<FrameInfo> frames;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_string.h>
|
#include <sh_string.h>
|
||||||
#include "GameConfigs.h"
|
#include "GameConfigs.h"
|
||||||
@ -46,6 +47,7 @@
|
|||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <bridge/include/ILogger.h>
|
#include <bridge/include/ILogger.h>
|
||||||
#include <bridge/include/CoreProvider.h>
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
#include <bridge/include/IFileSystemBridge.h>
|
||||||
|
|
||||||
#if defined PLATFORM_POSIX
|
#if defined PLATFORM_POSIX
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
@ -85,15 +87,12 @@ static const char *g_pParseEngine = NULL;
|
|||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
#if defined PLATFORM_WINDOWS
|
||||||
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_SERVER_BINARY "server.dll"
|
|
||||||
#elif defined PLATFORM_LINUX
|
#elif defined PLATFORM_LINUX
|
||||||
#define PLATFORM_NAME "linux" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_NAME "linux" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_COMPAT_ALT "mac" PLATFORM_ARCH_SUFFIX /* Alternate platform name if game data is missing for primary one */
|
#define PLATFORM_COMPAT_ALT "mac" PLATFORM_ARCH_SUFFIX /* Alternate platform name if game data is missing for primary one */
|
||||||
#define PLATFORM_SERVER_BINARY "server_i486.so"
|
|
||||||
#elif defined PLATFORM_APPLE
|
#elif defined PLATFORM_APPLE
|
||||||
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
|
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
|
||||||
#define PLATFORM_SERVER_BINARY "server.dylib"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct TempSigInfo
|
struct TempSigInfo
|
||||||
@ -106,8 +105,6 @@ struct TempSigInfo
|
|||||||
char sig[1024];
|
char sig[1024];
|
||||||
char library[64];
|
char library[64];
|
||||||
} s_TempSig;
|
} s_TempSig;
|
||||||
unsigned int s_ServerBinCRC;
|
|
||||||
bool s_ServerBinCRC_Ok = false;
|
|
||||||
|
|
||||||
static bool DoesGameMatch(const char *value)
|
static bool DoesGameMatch(const char *value)
|
||||||
{
|
{
|
||||||
@ -153,6 +150,23 @@ static inline bool IsPlatformCompatible(const char *platform, bool *hadPrimaryMa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline time_t GetFileModTime(const char *path)
|
||||||
|
{
|
||||||
|
char filepath[PLATFORM_MAX_PATH];
|
||||||
|
g_pSM->BuildPath(Path_SM, filepath, sizeof(filepath), "gamedata/%s.txt", path);
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
struct _stat64 s;
|
||||||
|
if (_stat64(filepath, &s) != 0)
|
||||||
|
#elif defined PLATFORM_POSIX
|
||||||
|
struct stat s;
|
||||||
|
if (stat(filepath, &s) != 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return s.st_mtime;
|
||||||
|
}
|
||||||
|
|
||||||
CGameConfig::CGameConfig(const char *file, const char *engine)
|
CGameConfig::CGameConfig(const char *file, const char *engine)
|
||||||
{
|
{
|
||||||
strncopy(m_File, file, sizeof(m_File));
|
strncopy(m_File, file, sizeof(m_File));
|
||||||
@ -160,6 +174,8 @@ CGameConfig::CGameConfig(const char *file, const char *engine)
|
|||||||
m_CustomLevel = 0;
|
m_CustomLevel = 0;
|
||||||
m_CustomHandler = NULL;
|
m_CustomHandler = NULL;
|
||||||
|
|
||||||
|
m_ModTime = GetFileModTime(file);
|
||||||
|
|
||||||
if (!engine)
|
if (!engine)
|
||||||
m_pEngine = bridge->GetSourceEngineName();
|
m_pEngine = bridge->GetSourceEngineName();
|
||||||
else
|
else
|
||||||
@ -206,7 +222,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
{
|
{
|
||||||
bShouldBeReadingDefault = true;
|
bShouldBeReadingDefault = true;
|
||||||
m_ParseState = PSTATE_GAMEDEFS;
|
m_ParseState = PSTATE_GAMEDEFS;
|
||||||
strncopy(m_Game, name, sizeof(m_Game));
|
m_Game = name;
|
||||||
} else {
|
} else {
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
}
|
}
|
||||||
@ -222,7 +238,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
{
|
{
|
||||||
m_ParseState = PSTATE_GAMEDEFS_KEYS;
|
m_ParseState = PSTATE_GAMEDEFS_KEYS;
|
||||||
}
|
}
|
||||||
else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
|
else if ((strcmp(name, "#supported") == 0) && (m_Game == "#default"))
|
||||||
{
|
{
|
||||||
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
|
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
|
||||||
/* Ignore this section unless we get a game. */
|
/* Ignore this section unless we get a game. */
|
||||||
@ -261,23 +277,23 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_KEYS:
|
case PSTATE_GAMEDEFS_KEYS:
|
||||||
{
|
{
|
||||||
strncopy(m_Key, name, sizeof(m_Key));
|
m_Key = name;
|
||||||
m_ParseState = PSTATE_GAMEDEFS_KEYS_PLATFORM;
|
m_ParseState = PSTATE_GAMEDEFS_KEYS_PLATFORM;
|
||||||
matched_platform = false;
|
matched_platform = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_OFFSETS:
|
case PSTATE_GAMEDEFS_OFFSETS:
|
||||||
{
|
{
|
||||||
m_Prop[0] = '\0';
|
m_Prop.clear();
|
||||||
m_Class[0] = '\0';
|
m_Class.clear();
|
||||||
strncopy(m_offset, name, sizeof(m_offset));
|
m_offset = name;
|
||||||
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
|
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
|
||||||
matched_platform = false;
|
matched_platform = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_SIGNATURES:
|
case PSTATE_GAMEDEFS_SIGNATURES:
|
||||||
{
|
{
|
||||||
strncopy(m_offset, name, sizeof(m_offset));
|
m_offset = name;
|
||||||
s_TempSig.Reset();
|
s_TempSig.Reset();
|
||||||
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
|
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
|
||||||
matched_platform = false;
|
matched_platform = false;
|
||||||
@ -287,39 +303,25 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
{
|
{
|
||||||
char error[255];
|
char error[255];
|
||||||
error[0] = '\0';
|
error[0] = '\0';
|
||||||
if (strcmp(name, "server") != 0)
|
GameBinaryInfo binInfo;
|
||||||
|
if (!g_GameConfigs.TryGetGameBinaryInfo(name, &binInfo))
|
||||||
{
|
{
|
||||||
ke::SafeSprintf(error, sizeof(error), "Unrecognized library \"%s\"", name);
|
ke::SafeSprintf(error, sizeof(error), "Unrecognized library \"%s\"", name);
|
||||||
}
|
}
|
||||||
else if (!s_ServerBinCRC_Ok)
|
else if (!binInfo.m_crcOK)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
ke::SafeSprintf(error, sizeof(error), "Could not get CRC for binary: %s", name);
|
||||||
char path[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
|
|
||||||
if ((fp = fopen(path, "rb")) == NULL)
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(error, sizeof(error), "Could not open binary: %s", path);
|
|
||||||
} else {
|
|
||||||
size_t size;
|
|
||||||
void *buffer;
|
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
size = ftell(fp);
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
|
|
||||||
buffer = malloc(size);
|
|
||||||
fread(buffer, size, 1, fp);
|
|
||||||
s_ServerBinCRC = UTIL_CRC32(buffer, size);
|
|
||||||
free(buffer);
|
|
||||||
s_ServerBinCRC_Ok = true;
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bCurrentBinCRC_Ok = binInfo.m_crcOK;
|
||||||
|
bCurrentBinCRC = binInfo.m_crc;
|
||||||
|
}
|
||||||
|
|
||||||
if (error[0] != '\0')
|
if (error[0] != '\0')
|
||||||
{
|
{
|
||||||
m_IgnoreLevel = 1;
|
m_IgnoreLevel = 1;
|
||||||
logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile);
|
logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game.c_str(), m_CurFile);
|
||||||
logger->LogError("[SM] %s", error);
|
logger->LogError("[SM] %s", error);
|
||||||
} else {
|
} else {
|
||||||
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
|
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
|
||||||
@ -334,12 +336,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
}
|
}
|
||||||
case PSTATE_GAMEDEFS_ADDRESSES:
|
case PSTATE_GAMEDEFS_ADDRESSES:
|
||||||
{
|
{
|
||||||
m_Address[0] = '\0';
|
m_Address.clear();
|
||||||
m_AddressSignature[0] = '\0';
|
m_AddressSignature.clear();
|
||||||
m_AddressReadCount = 0;
|
m_AddressReadCount = 0;
|
||||||
m_AddressLastIsOffset = false;
|
m_AddressLastIsOffset = false;
|
||||||
|
|
||||||
strncopy(m_Address, name, sizeof(m_Address));
|
m_Address = name;
|
||||||
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS;
|
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -355,7 +357,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
|
|||||||
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0 &&
|
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0 &&
|
||||||
strcmp(name, "linux64") != 0 && strcmp(name, "windows64") != 0 && strcmp(name, "mac64") != 0)
|
strcmp(name, "linux64") != 0 && strcmp(name, "windows64") != 0 && strcmp(name, "mac64") != 0)
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address, m_CurFile);
|
logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address.c_str(), m_CurFile);
|
||||||
logger->LogError("[SM] Unrecognized platform \"%s\"", name);
|
logger->LogError("[SM] Unrecognized platform \"%s\"", name);
|
||||||
}
|
}
|
||||||
m_IgnoreLevel = 1;
|
m_IgnoreLevel = 1;
|
||||||
@ -392,21 +394,21 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
{
|
{
|
||||||
if (strcmp(key, "class") == 0)
|
if (strcmp(key, "class") == 0)
|
||||||
{
|
{
|
||||||
strncopy(m_Class, value, sizeof(m_Class));
|
m_Class = value;
|
||||||
} else if (strcmp(key, "prop") == 0) {
|
} else if (strcmp(key, "prop") == 0) {
|
||||||
strncopy(m_Prop, value, sizeof(m_Prop));
|
m_Prop = value;
|
||||||
} else if (IsPlatformCompatible(key, &matched_platform)) {
|
} else if (IsPlatformCompatible(key, &matched_platform)) {
|
||||||
m_Offsets.replace(m_offset, atoi(value));
|
m_Offsets.replace(m_offset.c_str(), static_cast<int>(strtol(value, NULL, 0)));
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
|
||||||
ke::AString vstr(value);
|
std::string vstr(value);
|
||||||
m_Keys.replace(key, ke::Move(vstr));
|
m_Keys.replace(key, std::move(vstr));
|
||||||
}
|
}
|
||||||
else if (m_ParseState == PSTATE_GAMEDEFS_KEYS_PLATFORM) {
|
else if (m_ParseState == PSTATE_GAMEDEFS_KEYS_PLATFORM) {
|
||||||
if (IsPlatformCompatible(key, &matched_platform))
|
if (IsPlatformCompatible(key, &matched_platform))
|
||||||
{
|
{
|
||||||
ke::AString vstr(value);
|
std::string vstr(value);
|
||||||
m_Keys.replace(m_Key, ke::Move(vstr));
|
m_Keys.replace(m_Key.c_str(), std::move(vstr));
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
|
||||||
if (strcmp(key, "game") == 0)
|
if (strcmp(key, "game") == 0)
|
||||||
@ -442,12 +444,12 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
|
||||||
if (DoesPlatformMatch(key)
|
if (DoesPlatformMatch(key)
|
||||||
&& s_ServerBinCRC_Ok
|
&& bCurrentBinCRC_Ok
|
||||||
&& !bShouldBeReadingDefault)
|
&& !bShouldBeReadingDefault)
|
||||||
{
|
{
|
||||||
unsigned int crc = 0;
|
unsigned int crc = 0;
|
||||||
sscanf(value, "%08X", &crc);
|
sscanf(value, "%08X", &crc);
|
||||||
if (s_ServerBinCRC == crc)
|
if (bCurrentBinCRC == crc)
|
||||||
{
|
{
|
||||||
bShouldBeReadingDefault = true;
|
bShouldBeReadingDefault = true;
|
||||||
}
|
}
|
||||||
@ -457,7 +459,7 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
int limit = sizeof(m_AddressRead)/sizeof(m_AddressRead[0]);
|
int limit = sizeof(m_AddressRead)/sizeof(m_AddressRead[0]);
|
||||||
if (m_AddressLastIsOffset)
|
if (m_AddressLastIsOffset)
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address, m_CurFile);
|
logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address.c_str(), m_CurFile);
|
||||||
}
|
}
|
||||||
else if (m_AddressReadCount < limit)
|
else if (m_AddressReadCount < limit)
|
||||||
{
|
{
|
||||||
@ -465,15 +467,15 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
|
|||||||
{
|
{
|
||||||
m_AddressLastIsOffset = true;
|
m_AddressLastIsOffset = true;
|
||||||
}
|
}
|
||||||
m_AddressRead[m_AddressReadCount] = atoi(value);
|
m_AddressRead[m_AddressReadCount] = static_cast<int>(strtol(value, NULL, 0));
|
||||||
m_AddressReadCount++;
|
m_AddressReadCount++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address, limit, m_CurFile);
|
logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address.c_str(), limit, m_CurFile);
|
||||||
}
|
}
|
||||||
} else if (strcmp(key, "signature") == 0) {
|
} else if (strcmp(key, "signature") == 0) {
|
||||||
strncopy(m_AddressSignature, value, sizeof(m_AddressSignature));
|
m_AddressSignature = value;
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
|
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
|
||||||
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
|
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
|
||||||
@ -529,25 +531,24 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
|
||||||
{
|
{
|
||||||
/* Parse the offset... */
|
/* Parse the offset... */
|
||||||
if (m_Class[0] != '\0'
|
if (!m_Class.empty() && !m_Prop.empty())
|
||||||
&& m_Prop[0] != '\0')
|
|
||||||
{
|
{
|
||||||
SendProp *pProp = gamehelpers->FindInSendTable(m_Class, m_Prop);
|
SendProp *pProp = gamehelpers->FindInSendTable(m_Class.c_str(), m_Prop.c_str());
|
||||||
if (pProp)
|
if (pProp)
|
||||||
{
|
{
|
||||||
int val = gamehelpers->GetSendPropOffset(pProp);
|
int val = gamehelpers->GetSendPropOffset(pProp);
|
||||||
m_Offsets.replace(m_offset, val);
|
m_Offsets.replace(m_offset.c_str(), val);
|
||||||
m_Props.replace(m_offset, pProp);
|
m_Props.replace(m_offset.c_str(), pProp);
|
||||||
} else {
|
} else {
|
||||||
/* Check if it's a non-default game and no offsets exist */
|
/* Check if it's a non-default game and no offsets exist */
|
||||||
if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
|
if ((m_Game != "*" && m_Game != "#default")
|
||||||
&& (!m_Offsets.retrieve(m_offset)))
|
&& (!m_Offsets.retrieve(m_offset.c_str())))
|
||||||
{
|
{
|
||||||
logger->LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
|
logger->LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
|
||||||
m_Class,
|
m_Class.c_str(),
|
||||||
m_Prop,
|
m_Prop.c_str(),
|
||||||
m_CurFile,
|
m_CurFile,
|
||||||
m_Game);
|
m_Game.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -585,14 +586,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
|
strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
|
||||||
}
|
}
|
||||||
void *addrInBase = NULL;
|
void *addrInBase = NULL;
|
||||||
if (strcmp(s_TempSig.library, "server") == 0)
|
GameBinaryInfo binInfo;
|
||||||
|
if (g_GameConfigs.TryGetGameBinaryInfo(s_TempSig.library, &binInfo))
|
||||||
{
|
{
|
||||||
addrInBase = bridge->serverFactory;
|
addrInBase = binInfo.m_pAddr;
|
||||||
} else if (strcmp(s_TempSig.library, "engine") == 0) {
|
|
||||||
addrInBase = bridge->engineFactory;
|
|
||||||
} else if (strcmp(s_TempSig.library, "matchmaking_ds") == 0) {
|
|
||||||
addrInBase = bridge->matchmakingDSFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *final_addr = NULL;
|
void *final_addr = NULL;
|
||||||
if (addrInBase == NULL)
|
if (addrInBase == NULL)
|
||||||
{
|
{
|
||||||
@ -655,7 +654,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Sigs.replace(m_offset, final_addr);
|
m_Sigs.replace(m_offset.c_str(), final_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
|
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
|
||||||
@ -671,10 +670,10 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
|||||||
{
|
{
|
||||||
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES;
|
m_ParseState = PSTATE_GAMEDEFS_ADDRESSES;
|
||||||
|
|
||||||
if (m_Address[0] != '\0' && m_AddressSignature[0] != '\0')
|
if (!m_Address.empty() && !m_AddressSignature.empty())
|
||||||
{
|
{
|
||||||
AddressConf addrConf(m_AddressSignature, sizeof(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset);
|
AddressConf addrConf(std::move(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset);
|
||||||
m_Addresses.replace(m_Address, addrConf);
|
m_Addresses.replace(m_Address.c_str(), addrConf);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -792,7 +791,10 @@ public:
|
|||||||
(!had_game && matched_engine) ||
|
(!had_game && matched_engine) ||
|
||||||
(matched_engine && matched_game))
|
(matched_engine && matched_game))
|
||||||
{
|
{
|
||||||
fileList->push_back(cur_file);
|
if (fileList->find(cur_file) == fileList->end())
|
||||||
|
{
|
||||||
|
fileList->push_back(cur_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state = MSTATE_MAIN;
|
state = MSTATE_MAIN;
|
||||||
}
|
}
|
||||||
@ -1001,10 +1003,10 @@ bool CGameConfig::GetOffset(const char *key, int *value)
|
|||||||
|
|
||||||
const char *CGameConfig::GetKeyValue(const char *key)
|
const char *CGameConfig::GetKeyValue(const char *key)
|
||||||
{
|
{
|
||||||
StringHashMap<ke::AString>::Result r = m_Keys.find(key);
|
StringHashMap<std::string>::Result r = m_Keys.find(key);
|
||||||
if (!r.found())
|
if (!r.found())
|
||||||
return NULL;
|
return NULL;
|
||||||
return r->value.chars();
|
return r->value.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
//memory addresses below 0x10000 are automatically considered invalid for dereferencing
|
//memory addresses below 0x10000 are automatically considered invalid for dereferencing
|
||||||
@ -1022,7 +1024,7 @@ bool CGameConfig::GetAddress(const char *key, void **retaddr)
|
|||||||
AddressConf &addrConf = r->value;
|
AddressConf &addrConf = r->value;
|
||||||
|
|
||||||
void *addr;
|
void *addr;
|
||||||
if (!GetMemSig(addrConf.signatureName, &addr))
|
if (!GetMemSig(addrConf.signatureName.c_str(), &addr))
|
||||||
{
|
{
|
||||||
*retaddr = NULL;
|
*retaddr = NULL;
|
||||||
return false;
|
return false;
|
||||||
@ -1055,11 +1057,11 @@ static inline unsigned minOf(unsigned a, unsigned b)
|
|||||||
return a <= b ? a : b;
|
return a <= b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGameConfig::AddressConf::AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset)
|
CGameConfig::AddressConf::AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset)
|
||||||
{
|
{
|
||||||
unsigned readLimit = minOf(readCount, sizeof(this->read) / sizeof(this->read[0]));
|
unsigned readLimit = minOf(readCount, sizeof(this->read) / sizeof(this->read[0]));
|
||||||
|
|
||||||
strncopy(signatureName, sigName, sizeof(signatureName) / sizeof(signatureName[0]));
|
this->signatureName = std::move(sigName);
|
||||||
this->readCount = readLimit;
|
this->readCount = readLimit;
|
||||||
memcpy(&this->read[0], read, sizeof(this->read[0])*readLimit);
|
memcpy(&this->read[0], read, sizeof(this->read[0])*readLimit);
|
||||||
|
|
||||||
@ -1081,6 +1083,42 @@ bool CGameConfig::GetMemSig(const char *key, void **addr)
|
|||||||
return m_Sigs.retrieve(key, addr);
|
return m_Sigs.retrieve(key, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameBinPathManager::Init()
|
||||||
|
{
|
||||||
|
char search_path[PLATFORM_MAX_PATH * 8];
|
||||||
|
bridge->filesystem->GetSearchPath("GAMEBIN", false, search_path, sizeof(search_path));
|
||||||
|
|
||||||
|
char addons_folder[12];
|
||||||
|
ke::SafeSprintf(addons_folder, sizeof(addons_folder), "%caddons%c", PLATFORM_SEP_CHAR, PLATFORM_SEP_CHAR);
|
||||||
|
|
||||||
|
std::istringstream iss(search_path);
|
||||||
|
for (std::string path; std::getline(iss, path, ';');)
|
||||||
|
{
|
||||||
|
if (path.length() > 0
|
||||||
|
&& path.find(addons_folder) == std::string::npos
|
||||||
|
&& m_lookup.find(path) == m_lookup.cend()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_lookup.insert(path);
|
||||||
|
m_ordered.push_back(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iss.clear();
|
||||||
|
|
||||||
|
bridge->filesystem->GetSearchPath("EXECUTABLE_PATH", false, search_path, sizeof(search_path));
|
||||||
|
iss.str(search_path);
|
||||||
|
|
||||||
|
for (std::string path; std::getline(iss, path, ';');)
|
||||||
|
{
|
||||||
|
if (m_lookup.find(path) == m_lookup.cend())
|
||||||
|
{
|
||||||
|
m_lookup.insert(path);
|
||||||
|
m_ordered.push_back(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameConfigManager::GameConfigManager()
|
GameConfigManager::GameConfigManager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -1091,6 +1129,8 @@ GameConfigManager::~GameConfigManager()
|
|||||||
|
|
||||||
void GameConfigManager::OnSourceModStartup(bool late)
|
void GameConfigManager::OnSourceModStartup(bool late)
|
||||||
{
|
{
|
||||||
|
m_gameBinPathManager.Init();
|
||||||
|
|
||||||
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
|
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
|
||||||
|
|
||||||
strncopy(g_Game, g_pSM->GetGameFolderName(), sizeof(g_Game));
|
strncopy(g_Game, g_pSM->GetGameFolderName(), sizeof(g_Game));
|
||||||
@ -1132,9 +1172,17 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon
|
|||||||
|
|
||||||
if (m_Lookup.retrieve(file, &pConfig))
|
if (m_Lookup.retrieve(file, &pConfig))
|
||||||
{
|
{
|
||||||
|
bool ret = true;
|
||||||
|
time_t modtime = GetFileModTime(file);
|
||||||
|
if (pConfig->m_ModTime != modtime)
|
||||||
|
{
|
||||||
|
pConfig->m_ModTime = modtime;
|
||||||
|
ret = pConfig->Reparse(error, maxlength);
|
||||||
|
}
|
||||||
|
|
||||||
pConfig->AddRef();
|
pConfig->AddRef();
|
||||||
*_pConfig = pConfig;
|
*_pConfig = pConfig;
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pConfig = new CGameConfig(file);
|
pConfig = new CGameConfig(file);
|
||||||
@ -1205,3 +1253,75 @@ void GameConfigManager::RemoveCachedConfig(CGameConfig *config)
|
|||||||
{
|
{
|
||||||
m_Lookup.remove(config->m_File);
|
m_Lookup.remove(config->m_File);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameConfigManager::CacheGameBinaryInfo(const char* pszName)
|
||||||
|
{
|
||||||
|
GameBinaryInfo info;
|
||||||
|
|
||||||
|
char name[64];
|
||||||
|
bridge->FormatSourceBinaryName(pszName, name, sizeof(name));
|
||||||
|
|
||||||
|
char binary_path[PLATFORM_MAX_PATH];
|
||||||
|
for (auto it = m_gameBinPathManager.Paths().begin(); it != m_gameBinPathManager.Paths().end(); ++it)
|
||||||
|
{
|
||||||
|
ke::SafeSprintf(binary_path, sizeof(binary_path), "%s%s%s", it->c_str(), it->back() == PLATFORM_SEP_CHAR ? "" : PLATFORM_SEP, name);
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
HMODULE hModule = LoadLibraryA(binary_path);
|
||||||
|
if (hModule)
|
||||||
|
{
|
||||||
|
info.m_pAddr = GetProcAddress(hModule, "CreateInterface");
|
||||||
|
FreeLibrary(hModule);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void *pHandle = dlopen(binary_path, RTLD_NOW);
|
||||||
|
if (pHandle)
|
||||||
|
{
|
||||||
|
info.m_pAddr = dlsym(pHandle, "CreateInterface");
|
||||||
|
dlclose(pHandle);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (info.m_pAddr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't bother trying to get CRC if we couldn't find the bin loaded
|
||||||
|
if (info.m_pAddr)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if ((fp = fopen(binary_path, "rb")) == 0)
|
||||||
|
{
|
||||||
|
info.m_crc = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
void* buffer;
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
size = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
buffer = malloc(size);
|
||||||
|
fread(buffer, size, 1, fp);
|
||||||
|
info.m_crc = UTIL_CRC32(buffer, size);
|
||||||
|
free(buffer);
|
||||||
|
info.m_crcOK = true;
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// But insert regardless, to cache the first lookup (even as failed)
|
||||||
|
m_gameBinInfos.insert(pszName, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameConfigManager::TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest)
|
||||||
|
{
|
||||||
|
if (m_gameBinInfos.retrieve(pszName, pDest))
|
||||||
|
return pDest->m_pAddr != nullptr;
|
||||||
|
|
||||||
|
CacheGameBinaryInfo(pszName);
|
||||||
|
|
||||||
|
return m_gameBinInfos.retrieve(pszName, pDest);
|
||||||
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
#include <sm_stringhashmap.h>
|
#include <sm_stringhashmap.h>
|
||||||
#include <sm_namehashset.h>
|
#include <sm_namehashset.h>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
@ -81,16 +82,18 @@ private:
|
|||||||
char m_CurFile[PLATFORM_MAX_PATH];
|
char m_CurFile[PLATFORM_MAX_PATH];
|
||||||
StringHashMap<int> m_Offsets;
|
StringHashMap<int> m_Offsets;
|
||||||
StringHashMap<SendProp *> m_Props;
|
StringHashMap<SendProp *> m_Props;
|
||||||
StringHashMap<ke::AString> m_Keys;
|
StringHashMap<std::string> m_Keys;
|
||||||
StringHashMap<void *> m_Sigs;
|
StringHashMap<void *> m_Sigs;
|
||||||
/* Parse states */
|
/* Parse states */
|
||||||
int m_ParseState;
|
int m_ParseState;
|
||||||
unsigned int m_IgnoreLevel;
|
unsigned int m_IgnoreLevel;
|
||||||
char m_Class[64];
|
std::string m_Class;
|
||||||
char m_Prop[64];
|
std::string m_Prop;
|
||||||
char m_offset[64];
|
std::string m_offset;
|
||||||
char m_Game[256];
|
std::string m_Game;
|
||||||
char m_Key[64];
|
std::string m_Key;
|
||||||
|
unsigned int bCurrentBinCRC;
|
||||||
|
bool bCurrentBinCRC_Ok = false;
|
||||||
bool bShouldBeReadingDefault;
|
bool bShouldBeReadingDefault;
|
||||||
bool had_game;
|
bool had_game;
|
||||||
bool matched_game;
|
bool matched_game;
|
||||||
@ -105,24 +108,49 @@ private:
|
|||||||
/* Support for reading Addresses */
|
/* Support for reading Addresses */
|
||||||
struct AddressConf
|
struct AddressConf
|
||||||
{
|
{
|
||||||
char signatureName[64];
|
std::string signatureName;
|
||||||
int readCount;
|
int readCount;
|
||||||
int read[8];
|
int read[8];
|
||||||
bool lastIsOffset;
|
bool lastIsOffset;
|
||||||
|
|
||||||
AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset);
|
AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset);
|
||||||
|
|
||||||
AddressConf() {}
|
AddressConf() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
char m_Address[64];
|
std::string m_Address;
|
||||||
char m_AddressSignature[64];
|
std::string m_AddressSignature;
|
||||||
int m_AddressReadCount;
|
int m_AddressReadCount;
|
||||||
int m_AddressRead[8];
|
int m_AddressRead[8];
|
||||||
bool m_AddressLastIsOffset;
|
bool m_AddressLastIsOffset;
|
||||||
StringHashMap<AddressConf> m_Addresses;
|
StringHashMap<AddressConf> m_Addresses;
|
||||||
const char *m_pEngine;
|
const char *m_pEngine;
|
||||||
const char *m_pBaseEngine;
|
const char *m_pBaseEngine;
|
||||||
|
time_t m_ModTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GameBinaryInfo
|
||||||
|
{
|
||||||
|
void *m_pAddr = nullptr;
|
||||||
|
uint32_t m_crc = 0;
|
||||||
|
bool m_crcOK = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GameBinPathManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GameBinPathManager() {}
|
||||||
|
~GameBinPathManager() {}
|
||||||
|
public:
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
inline const std::vector<std::string>& Paths() const
|
||||||
|
{
|
||||||
|
return m_ordered;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unordered_set<std::string> m_lookup;
|
||||||
|
std::vector<std::string> m_ordered;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameConfigManager :
|
class GameConfigManager :
|
||||||
@ -147,11 +175,16 @@ public: //SMGlobalClass
|
|||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
void OnSourceModAllShutdown();
|
void OnSourceModAllShutdown();
|
||||||
public:
|
public:
|
||||||
|
bool TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest);
|
||||||
void RemoveCachedConfig(CGameConfig *config);
|
void RemoveCachedConfig(CGameConfig *config);
|
||||||
|
private:
|
||||||
|
void CacheGameBinaryInfo(const char* pszName);
|
||||||
private:
|
private:
|
||||||
NameHashSet<CGameConfig *> m_Lookup;
|
NameHashSet<CGameConfig *> m_Lookup;
|
||||||
|
StringHashMap<GameBinaryInfo> m_gameBinInfos;
|
||||||
public:
|
public:
|
||||||
StringHashMap<ITextListener_SMC *> m_customHandlers;
|
StringHashMap<ITextListener_SMC *> m_customHandlers;
|
||||||
|
GameBinPathManager m_gameBinPathManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GameConfigManager g_GameConfigs;
|
extern GameConfigManager g_GameConfigs;
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
@ -38,10 +39,20 @@
|
|||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <bridge/include/ILogger.h>
|
#include <bridge/include/ILogger.h>
|
||||||
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
#include <ISourceMod.h>
|
||||||
|
|
||||||
|
#include "sm_platform.h"
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
#include "sm_invalidparamhandler.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
HandleSystem g_HandleSys;
|
HandleSystem g_HandleSys;
|
||||||
|
|
||||||
QHandle *ignore_handle;
|
QHandle *ignore_handle;
|
||||||
|
extern ConVar *g_datetime_format;
|
||||||
|
|
||||||
inline HandleType_t TypeParent(HandleType_t type)
|
inline HandleType_t TypeParent(HandleType_t type)
|
||||||
{
|
{
|
||||||
@ -206,7 +217,7 @@ HandleType_t HandleSystem::CreateType(const char *name,
|
|||||||
pType->dispatch = dispatch;
|
pType->dispatch = dispatch;
|
||||||
if (name && name[0] != '\0')
|
if (name && name[0] != '\0')
|
||||||
{
|
{
|
||||||
pType->name = new ke::AString(name);
|
pType->name = std::make_unique<std::string>(name);
|
||||||
m_TypeLookup.insert(name, pType);
|
m_TypeLookup.insert(name, pType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,6 +301,28 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (owner)
|
||||||
|
{
|
||||||
|
owner->num_handles++;
|
||||||
|
if (!owner->warned_handle_usage && owner->num_handles >= HANDLESYS_WARN_USAGE)
|
||||||
|
{
|
||||||
|
owner->warned_handle_usage = true;
|
||||||
|
|
||||||
|
std::string path = "<unknown>";
|
||||||
|
if (auto plugin = scripts->FindPluginByIdentity(owner))
|
||||||
|
{
|
||||||
|
path = "plugin "s + plugin->GetFilename();
|
||||||
|
}
|
||||||
|
else if (auto ext = g_Extensions.GetExtensionFromIdent(owner))
|
||||||
|
{
|
||||||
|
path = "extension "s + ext->GetFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger->LogError("[SM] Warning: %s is using more than %d handles!",
|
||||||
|
path.c_str(), HANDLESYS_WARN_USAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QHandle *pHandle = &m_Handles[handle];
|
QHandle *pHandle = &m_Handles[handle];
|
||||||
|
|
||||||
assert(pHandle->set == false);
|
assert(pHandle->set == false);
|
||||||
@ -311,7 +344,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
|
|||||||
|
|
||||||
/* Create the hash value */
|
/* Create the hash value */
|
||||||
Handle_t hash = pHandle->serial;
|
Handle_t hash = pHandle->serial;
|
||||||
hash <<= 16;
|
hash <<= HANDLESYS_HANDLE_BITS;
|
||||||
hash |= handle;
|
hash |= handle;
|
||||||
|
|
||||||
/* Add a reference count to the type */
|
/* Add a reference count to the type */
|
||||||
@ -430,7 +463,7 @@ Handle_t HandleSystem::CreateHandleInt(HandleType_t type,
|
|||||||
|
|
||||||
pHandle->object = object;
|
pHandle->object = object;
|
||||||
pHandle->clone = 0;
|
pHandle->clone = 0;
|
||||||
|
pHandle->timestamp = g_pSM->GetAdjustedTime();
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +508,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
|||||||
unsigned int *in_index,
|
unsigned int *in_index,
|
||||||
bool ignoreFree)
|
bool ignoreFree)
|
||||||
{
|
{
|
||||||
unsigned int serial = (handle >> 16);
|
unsigned int serial = (handle >> HANDLESYS_HANDLE_BITS);
|
||||||
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
||||||
|
|
||||||
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
|
||||||
@ -631,7 +664,7 @@ Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
|
|||||||
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
unsigned int serial = (hndl >> 16);
|
unsigned int serial = (hndl >> HANDLESYS_HANDLE_BITS);
|
||||||
#endif
|
#endif
|
||||||
index = (hndl & HANDLESYS_HANDLE_MASK);
|
index = (hndl & HANDLESYS_HANDLE_MASK);
|
||||||
|
|
||||||
@ -655,6 +688,9 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
|
|||||||
|
|
||||||
QHandleType *pType = &m_Types[pHandle->type];
|
QHandleType *pType = &m_Types[pHandle->type];
|
||||||
|
|
||||||
|
if (pHandle->owner && pHandle->owner->num_handles > 0)
|
||||||
|
pHandle->owner->num_handles--;
|
||||||
|
|
||||||
if (pHandle->clone)
|
if (pHandle->clone)
|
||||||
{
|
{
|
||||||
/* If we're a clone, decrease the parent reference count */
|
/* If we're a clone, decrease the parent reference count */
|
||||||
@ -925,7 +961,7 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
|
|||||||
|
|
||||||
/* Remove it from the type cache. */
|
/* Remove it from the type cache. */
|
||||||
if (pType->name)
|
if (pType->name)
|
||||||
m_TypeLookup.remove(pType->name->chars());
|
m_TypeLookup.remove(pType->name->c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1014,6 +1050,8 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
|
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
|
||||||
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
|
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
|
||||||
|
|
||||||
|
const QHandle *oldest = nullptr;
|
||||||
|
const QHandle *newest = nullptr;
|
||||||
for (unsigned int i = 1; i <= m_HandleTail; ++i)
|
for (unsigned int i = 1; i <= m_HandleTail; ++i)
|
||||||
{
|
{
|
||||||
const QHandle &Handle = m_Handles[i];
|
const QHandle &Handle = m_Handles[i];
|
||||||
@ -1030,6 +1068,15 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
highest_index = ((Handle.type) + 1);
|
highest_index = ((Handle.type) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!oldest || oldest->timestamp > Handle.timestamp)
|
||||||
|
{
|
||||||
|
oldest = &Handle;
|
||||||
|
}
|
||||||
|
if (!newest || newest->timestamp < Handle.timestamp)
|
||||||
|
{
|
||||||
|
newest = &Handle;
|
||||||
|
}
|
||||||
|
|
||||||
if (Handle.clone != 0)
|
if (Handle.clone != 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -1051,13 +1098,39 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_Types[i].name)
|
if (m_Types[i].name)
|
||||||
pTypeName = m_Types[i].name->chars();
|
pTypeName = m_Types[i].name->c_str();
|
||||||
else
|
else
|
||||||
pTypeName = "ANON";
|
pTypeName = "ANON";
|
||||||
|
|
||||||
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
|
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *fmt = bridge->GetCvarString(g_datetime_format);
|
||||||
|
|
||||||
|
char oldstamp[256], newstamp[256]; // 256 should be more than enough
|
||||||
|
|
||||||
|
// scope for InvalidParameterHandler
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
InvalidParameterHandler p;
|
||||||
|
#endif
|
||||||
|
size_t written = strftime(oldstamp, sizeof(oldstamp), fmt, localtime(&oldest->timestamp));
|
||||||
|
if (!written)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(oldstamp, sizeof(oldstamp), "INVALID");
|
||||||
|
}
|
||||||
|
|
||||||
|
written = strftime(newstamp, sizeof(newstamp), fmt, localtime(&newest->timestamp));
|
||||||
|
if (!written)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(newstamp, sizeof(newstamp), "INVALID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
|
||||||
|
HANDLE_LOG_VERY_BAD("Oldest Living Handle: %s created at %s", m_Types[oldest->type].name->c_str(), oldstamp);
|
||||||
|
HANDLE_LOG_VERY_BAD("Newest Living Handle: %s created at %s", m_Types[newest->type].name->c_str(), newstamp);
|
||||||
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
|
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
|
||||||
delete [] pCount;
|
delete [] pCount;
|
||||||
|
|
||||||
@ -1081,8 +1154,10 @@ static void rep(const HandleReporter &fn, const char *fmt, ...)
|
|||||||
void HandleSystem::Dump(const HandleReporter &fn)
|
void HandleSystem::Dump(const HandleReporter &fn)
|
||||||
{
|
{
|
||||||
unsigned int total_size = 0;
|
unsigned int total_size = 0;
|
||||||
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
|
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", "Handle", "Owner", "Type", "Memory", "Time Created");
|
||||||
rep(fn, "--------------------------------------------------------------------------");
|
rep(fn, "---------------------------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
const char *fmt = bridge->GetCvarString(g_datetime_format);
|
||||||
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
||||||
{
|
{
|
||||||
if (m_Handles[i].set != HandleSet_Used)
|
if (m_Handles[i].set != HandleSet_Used)
|
||||||
@ -1090,12 +1165,12 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Get the index */
|
/* Get the index */
|
||||||
unsigned int index = (m_Handles[i].serial << 16) | i;
|
unsigned int index = (m_Handles[i].serial << HANDLESYS_HANDLE_BITS) | i;
|
||||||
/* Determine the owner */
|
/* Determine the owner */
|
||||||
const char *owner = "UNKNOWN";
|
const char *owner = "UNKNOWN";
|
||||||
if (m_Handles[i].owner)
|
if (m_Handles[i].owner)
|
||||||
{
|
{
|
||||||
IdentityToken_t *pOwner = m_Handles[i].owner;
|
IdentityToken_t *pOwner = m_Handles[i].owner;
|
||||||
if (pOwner == g_pCoreIdent)
|
if (pOwner == g_pCoreIdent)
|
||||||
{
|
{
|
||||||
owner = "CORE";
|
owner = "CORE";
|
||||||
@ -1131,7 +1206,7 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
|||||||
unsigned int parentIdx;
|
unsigned int parentIdx;
|
||||||
bool bresult;
|
bool bresult;
|
||||||
if (pType->name)
|
if (pType->name)
|
||||||
type = pType->name->chars();
|
type = pType->name->c_str();
|
||||||
|
|
||||||
if ((parentIdx = m_Handles[i].clone) != 0)
|
if ((parentIdx = m_Handles[i].clone) != 0)
|
||||||
{
|
{
|
||||||
@ -1150,19 +1225,33 @@ void HandleSystem::Dump(const HandleReporter &fn)
|
|||||||
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
|
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char date[256]; // 256 should be more than enough
|
||||||
|
size_t written = 0;
|
||||||
|
// scope for InvalidParameterHandler
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
InvalidParameterHandler p;
|
||||||
|
#endif
|
||||||
|
written = strftime(date, sizeof(date), fmt, localtime(&m_Handles[i].timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!written)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(date, sizeof(date), "INVALID");
|
||||||
|
}
|
||||||
|
|
||||||
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|
||||||
|| !bresult)
|
|| !bresult)
|
||||||
{
|
{
|
||||||
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
|
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, "-1", date);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "%d", size);
|
ke::SafeSprintf(buffer, sizeof(buffer), "%d", size);
|
||||||
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
|
rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, buffer, date);
|
||||||
total_size += size;
|
total_size += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
|
rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,22 +32,27 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||||
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||||
|
|
||||||
#include <IHandleSys.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sm_namehashset.h>
|
|
||||||
#include <amtl/am-autoptr.h>
|
#include <memory>
|
||||||
|
|
||||||
#include <amtl/am-string.h>
|
#include <amtl/am-string.h>
|
||||||
#include <amtl/am-function.h>
|
#include <amtl/am-function.h>
|
||||||
|
#include <IHandleSys.h>
|
||||||
|
#include <sm_namehashset.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
|
|
||||||
#define HANDLESYS_MAX_HANDLES (1<<15)
|
#define HANDLESYS_HANDLE_BITS 20
|
||||||
|
#define HANDLESYS_MAX_HANDLES ((1 << HANDLESYS_HANDLE_BITS) - 1)
|
||||||
#define HANDLESYS_MAX_TYPES (1<<9)
|
#define HANDLESYS_MAX_TYPES (1<<9)
|
||||||
#define HANDLESYS_MAX_SUBTYPES 0xF
|
#define HANDLESYS_MAX_SUBTYPES 0xF
|
||||||
#define HANDLESYS_SUBTYPE_MASK 0xF
|
#define HANDLESYS_SUBTYPE_MASK 0xF
|
||||||
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
||||||
#define HANDLESYS_MAX_SERIALS 0xFFFF
|
#define HANDLESYS_SERIAL_BITS (32 - HANDLESYS_HANDLE_BITS)
|
||||||
#define HANDLESYS_SERIAL_MASK 0xFFFF0000
|
#define HANDLESYS_MAX_SERIALS (1 << HANDLESYS_SERIAL_BITS)
|
||||||
#define HANDLESYS_HANDLE_MASK 0x0000FFFF
|
#define HANDLESYS_SERIAL_MASK (((1 << HANDLESYS_SERIAL_BITS) - 1) << HANDLESYS_HANDLE_BITS)
|
||||||
|
#define HANDLESYS_HANDLE_MASK ((1 << HANDLESYS_HANDLE_BITS) - 1)
|
||||||
|
#define HANDLESYS_WARN_USAGE 100000
|
||||||
|
|
||||||
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
|
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
|
||||||
|
|
||||||
@ -88,6 +93,7 @@ struct QHandle
|
|||||||
bool access_special; /* Whether or not access rules are special or type-derived */
|
bool access_special; /* Whether or not access rules are special or type-derived */
|
||||||
bool is_destroying; /* Whether or not the handle is being destroyed */
|
bool is_destroying; /* Whether or not the handle is being destroyed */
|
||||||
HandleAccess sec; /* Security rules */
|
HandleAccess sec; /* Security rules */
|
||||||
|
time_t timestamp; /* Creation timestamp */
|
||||||
/* The following variables are unrelated to the Handle array, and used
|
/* The following variables are unrelated to the Handle array, and used
|
||||||
* as an inlined chain of information */
|
* as an inlined chain of information */
|
||||||
unsigned int freeID; /* ID of a free handle in the free handle chain */
|
unsigned int freeID; /* ID of a free handle in the free handle chain */
|
||||||
@ -105,7 +111,7 @@ struct QHandleType
|
|||||||
TypeAccess typeSec;
|
TypeAccess typeSec;
|
||||||
HandleAccess hndlSec;
|
HandleAccess hndlSec;
|
||||||
unsigned int opened;
|
unsigned int opened;
|
||||||
ke::AutoPtr<ke::AString> name;
|
std::unique_ptr<std::string> name;
|
||||||
|
|
||||||
static inline bool matches(const char *key, const QHandleType *type)
|
static inline bool matches(const char *key, const QHandleType *type)
|
||||||
{
|
{
|
||||||
@ -117,7 +123,7 @@ struct QHandleType
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ke::Lambda<void(const char *)> HandleReporter;
|
typedef ke::Function<void(const char *)> HandleReporter;
|
||||||
|
|
||||||
class HandleSystem :
|
class HandleSystem :
|
||||||
public IHandleSys
|
public IHandleSys
|
||||||
|
|||||||
@ -319,7 +319,7 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
char buff[PLATFORM_MAX_PATH];
|
char buff[PLATFORM_MAX_PATH];
|
||||||
ke::SafeSprintf(buff, sizeof(buff), "%04d%02d%02d", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
ke::SafeSprintf(buff, sizeof(buff), "%04d%02d%02d", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
|
||||||
|
|
||||||
ke::AString currentDate(buff);
|
std::string currentDate(buff);
|
||||||
|
|
||||||
if (m_Mode == LoggingMode_PerMap)
|
if (m_Mode == LoggingMode_PerMap)
|
||||||
{
|
{
|
||||||
@ -327,7 +327,7 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
{
|
{
|
||||||
for (size_t iter = 0; iter < static_cast<size_t>(-1); ++iter)
|
for (size_t iter = 0; iter < static_cast<size_t>(-1); ++iter)
|
||||||
{
|
{
|
||||||
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.chars(), iter);
|
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.c_str(), iter);
|
||||||
if (!libsys->IsPathFile(buff))
|
if (!libsys->IsPathFile(buff))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -336,12 +336,12 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.chars());
|
ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.chars());
|
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_NormalFileName.compare(buff))
|
if (m_NormalFileName.compare(buff))
|
||||||
@ -353,11 +353,11 @@ void Logger::_UpdateFiles(bool bLevelChange)
|
|||||||
{
|
{
|
||||||
if (bLevelChange)
|
if (bLevelChange)
|
||||||
{
|
{
|
||||||
LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.chars());
|
LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.chars());
|
g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.c_str());
|
||||||
if (bLevelChange || m_ErrorFileName.compare(buff))
|
if (bLevelChange || m_ErrorFileName.compare(buff))
|
||||||
{
|
{
|
||||||
_CloseError();
|
_CloseError();
|
||||||
@ -369,7 +369,7 @@ FILE *Logger::_OpenNormal()
|
|||||||
{
|
{
|
||||||
_UpdateFiles();
|
_UpdateFiles();
|
||||||
|
|
||||||
FILE *pFile = fopen(m_NormalFileName.chars(), "a+");
|
FILE *pFile = fopen(m_NormalFileName.c_str(), "a+");
|
||||||
if (pFile == NULL)
|
if (pFile == NULL)
|
||||||
{
|
{
|
||||||
_LogFatalOpen(m_NormalFileName);
|
_LogFatalOpen(m_NormalFileName);
|
||||||
@ -383,7 +383,7 @@ FILE *Logger::_OpenNormal()
|
|||||||
char date[32];
|
char date[32];
|
||||||
|
|
||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||||
fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.chars(), SOURCEMOD_VERSION);
|
fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.c_str(), SOURCEMOD_VERSION);
|
||||||
m_DamagedNormalFile = true;
|
m_DamagedNormalFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ FILE *Logger::_OpenError()
|
|||||||
{
|
{
|
||||||
_UpdateFiles();
|
_UpdateFiles();
|
||||||
|
|
||||||
FILE *pFile = fopen(m_ErrorFileName.chars(), "a+");
|
FILE *pFile = fopen(m_ErrorFileName.c_str(), "a+");
|
||||||
if (pFile == NULL)
|
if (pFile == NULL)
|
||||||
{
|
{
|
||||||
_LogFatalOpen(m_ErrorFileName);
|
_LogFatalOpen(m_ErrorFileName);
|
||||||
@ -409,7 +409,7 @@ FILE *Logger::_OpenError()
|
|||||||
char date[32];
|
char date[32];
|
||||||
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
|
||||||
fprintf(pFile, "L %s: SourceMod error session started\n", date);
|
fprintf(pFile, "L %s: SourceMod error session started\n", date);
|
||||||
fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.chars(), m_ErrorFileName.chars());
|
fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.c_str(), m_ErrorFileName.c_str());
|
||||||
m_DamagedErrorFile = true;
|
m_DamagedErrorFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,11 +423,11 @@ FILE *Logger::_OpenFatal()
|
|||||||
return fopen(path, "at");
|
return fopen(path, "at");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::_LogFatalOpen(ke::AString &str)
|
void Logger::_LogFatalOpen(std::string &str)
|
||||||
{
|
{
|
||||||
char error[255];
|
char error[255];
|
||||||
libsys->GetPlatformError(error, sizeof(error));
|
libsys->GetPlatformError(error, sizeof(error));
|
||||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.chars());
|
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.c_str());
|
||||||
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
LogFatal("[SM] Platform returned error: \"%s\"", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -92,13 +92,13 @@ private:
|
|||||||
FILE *_OpenError();
|
FILE *_OpenError();
|
||||||
FILE *_OpenFatal();
|
FILE *_OpenFatal();
|
||||||
|
|
||||||
void _LogFatalOpen(ke::AString &str);
|
void _LogFatalOpen(std::string &str);
|
||||||
void _PrintToGameLog(const char *fmt, va_list ap);
|
void _PrintToGameLog(const char *fmt, va_list ap);
|
||||||
void _UpdateFiles(bool bLevelChange = false);
|
void _UpdateFiles(bool bLevelChange = false);
|
||||||
private:
|
private:
|
||||||
ke::AString m_NormalFileName;
|
std::string m_NormalFileName;
|
||||||
ke::AString m_ErrorFileName;
|
std::string m_ErrorFileName;
|
||||||
ke::AString m_CurrentMapName;
|
std::string m_CurrentMapName;
|
||||||
|
|
||||||
int m_Day;
|
int m_Day;
|
||||||
|
|
||||||
|
|||||||
131
core/logic/LumpManager.cpp
Normal file
131
core/logic/LumpManager.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* =============================================================================
|
||||||
|
* Entity Lump Manager
|
||||||
|
* Copyright (C) 2021-2022 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LumpManager.h"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
EntityLumpParseResult::operator bool() const {
|
||||||
|
return m_Status == Status_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityLumpParseResult EntityLumpManager::Parse(const char* pMapEntities) {
|
||||||
|
m_Entities.clear();
|
||||||
|
|
||||||
|
std::istringstream mapEntities(pMapEntities);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
std::string token;
|
||||||
|
mapEntities >> std::ws >> token >> std::ws;
|
||||||
|
|
||||||
|
// Assert that we're at the start of a new block, otherwise we're done parsing
|
||||||
|
if (token != "{") {
|
||||||
|
if (token == "\0") {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return EntityLumpParseResult {
|
||||||
|
Status_UnexpectedChar, mapEntities.tellg()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse key / value pairs until we reach a closing brace. We currently assume there
|
||||||
|
* are only quoted keys / values up to the next closing brace.
|
||||||
|
*
|
||||||
|
* The SDK suggests that there are cases that could use non-quoted symbols and nested
|
||||||
|
* braces (`shared/mapentities_shared.cpp::MapEntity_ParseToken`), but I haven't seen
|
||||||
|
* those in practice.
|
||||||
|
*/
|
||||||
|
EntityLumpEntry entry;
|
||||||
|
while (mapEntities.peek() != '}') {
|
||||||
|
std::string key, value;
|
||||||
|
|
||||||
|
if (mapEntities.peek() != '"') {
|
||||||
|
return EntityLumpParseResult {
|
||||||
|
Status_UnexpectedChar, mapEntities.tellg()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
mapEntities >> quoted(key) >> std::ws;
|
||||||
|
|
||||||
|
if (mapEntities.peek() != '"') {
|
||||||
|
return EntityLumpParseResult {
|
||||||
|
Status_UnexpectedChar, mapEntities.tellg()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
mapEntities >> quoted(value) >> std::ws;
|
||||||
|
|
||||||
|
entry.emplace_back(key, value);
|
||||||
|
}
|
||||||
|
mapEntities.get();
|
||||||
|
m_Entities.push_back(std::make_shared<EntityLumpEntry>(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
return EntityLumpParseResult{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string EntityLumpManager::Dump() {
|
||||||
|
std::ostringstream stream;
|
||||||
|
for (const auto& entry : m_Entities) {
|
||||||
|
// ignore empty entries
|
||||||
|
if (entry->empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stream << "{\n";
|
||||||
|
for (const auto& pair : *entry) {
|
||||||
|
stream << '"' << pair.first << "\" \"" << pair.second << '"' << '\n';
|
||||||
|
}
|
||||||
|
stream << "}\n";
|
||||||
|
}
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<EntityLumpEntry> EntityLumpManager::Get(size_t index) {
|
||||||
|
return m_Entities[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityLumpManager::Erase(size_t index) {
|
||||||
|
m_Entities.erase(m_Entities.begin() + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityLumpManager::Insert(size_t index) {
|
||||||
|
m_Entities.emplace(m_Entities.begin() + index, std::make_shared<EntityLumpEntry>());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EntityLumpManager::Append() {
|
||||||
|
auto it = m_Entities.emplace(m_Entities.end(), std::make_shared<EntityLumpEntry>());
|
||||||
|
return std::distance(m_Entities.begin(), it);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EntityLumpManager::Length() {
|
||||||
|
return m_Entities.size();
|
||||||
|
}
|
||||||
116
core/logic/LumpManager.h
Normal file
116
core/logic/LumpManager.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 :
|
||||||
|
* =============================================================================
|
||||||
|
* Entity Lump Manager
|
||||||
|
* Copyright (C) 2021-2022 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_LUMPMANAGER_H_
|
||||||
|
#define _INCLUDE_LUMPMANAGER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity lump manager. Provides a list that stores a list of key / value pairs and the
|
||||||
|
* functionality to (de)serialize it from / to an entity string.
|
||||||
|
* This file and its corresponding .cpp should be compilable independently of SourceMod;
|
||||||
|
* the SourceMod interop is located within smn_entitylump.
|
||||||
|
*
|
||||||
|
* @file lumpmanager.h
|
||||||
|
* @brief Class definition for object that parses lumps.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A container of key / value pairs.
|
||||||
|
*/
|
||||||
|
using EntityLumpEntry = std::vector<std::pair<std::string, std::string>>;
|
||||||
|
|
||||||
|
enum EntityLumpParseStatus {
|
||||||
|
Status_OK,
|
||||||
|
Status_UnexpectedChar,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result of parsing an entity lump. On a parse error, m_Status is not Status_OK and
|
||||||
|
* m_Position indicates the offset within the string that caused the parse error.
|
||||||
|
*/
|
||||||
|
struct EntityLumpParseResult {
|
||||||
|
EntityLumpParseStatus m_Status;
|
||||||
|
std::streamoff m_Position;
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
const char* Description() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Manages entity lump entries.
|
||||||
|
*/
|
||||||
|
class EntityLumpManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Parses the map entities string into an internal representation.
|
||||||
|
*/
|
||||||
|
EntityLumpParseResult Parse(const char* pMapEntities);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dumps the current internal representation out to an std::string.
|
||||||
|
*/
|
||||||
|
std::string Dump();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a weak reference to an EntityLumpEntry. Used for handles on the scripting side.
|
||||||
|
*/
|
||||||
|
std::weak_ptr<EntityLumpEntry> Get(size_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes an EntityLumpEntry at the given index, shifting down all entries after it by one.
|
||||||
|
*/
|
||||||
|
void Erase(size_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inserts a new EntityLumpEntry at the given index, shifting up the entries previously at the index and after it up by one.
|
||||||
|
*/
|
||||||
|
void Insert(size_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new EntityLumpEntry to the end. Returns the index of the entry.
|
||||||
|
*/
|
||||||
|
size_t Append();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of EntityLumpEntry items in the list.
|
||||||
|
*/
|
||||||
|
size_t Length();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<EntityLumpEntry>> m_Entities;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _INCLUDE_LUMPMANAGER_H_
|
||||||
@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;
|
|||||||
|
|
||||||
MemoryUtils::MemoryUtils()
|
MemoryUtils::MemoryUtils()
|
||||||
{
|
{
|
||||||
|
m_InfoMap.init();
|
||||||
#ifdef PLATFORM_APPLE
|
#ifdef PLATFORM_APPLE
|
||||||
|
|
||||||
task_dyld_info_data_t dyld_info;
|
task_dyld_info_data_t dyld_info;
|
||||||
@ -77,20 +78,19 @@ void MemoryUtils::OnSourceModAllInitialized()
|
|||||||
|
|
||||||
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
|
||||||
{
|
{
|
||||||
DynLibInfo lib;
|
const DynLibInfo* lib = nullptr;
|
||||||
bool found;
|
|
||||||
char *ptr, *end;
|
|
||||||
|
|
||||||
memset(&lib, 0, sizeof(DynLibInfo));
|
if ((lib = GetLibraryInfo(libPtr)) == nullptr)
|
||||||
|
|
||||||
if (!GetLibraryInfo(libPtr, lib))
|
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
// Search in the original unaltered state of the binary.
|
||||||
end = ptr + lib.memorySize - len;
|
char *start = lib->originalCopy.get();
|
||||||
|
char *ptr = start;
|
||||||
|
char *end = ptr + lib->memorySize - len;
|
||||||
|
|
||||||
|
bool found;
|
||||||
while (ptr < end)
|
while (ptr < end)
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
@ -103,8 +103,9 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate the found offset into the actual live binary memory space.
|
||||||
if (found)
|
if (found)
|
||||||
return ptr;
|
return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start);
|
||||||
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -116,6 +117,8 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
{
|
{
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
/* Add this this library into the cache */
|
||||||
|
GetLibraryInfo(handle);
|
||||||
return GetProcAddress((HMODULE)handle, symbol);
|
return GetProcAddress((HMODULE)handle, symbol);
|
||||||
|
|
||||||
#elif defined PLATFORM_LINUX
|
#elif defined PLATFORM_LINUX
|
||||||
@ -162,6 +165,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add this this library into the cache */
|
||||||
|
GetLibraryInfo((void *)dlmap->l_addr);
|
||||||
|
|
||||||
/* If we don't have a symbol table for this library, then create one */
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
if (table == NULL)
|
if (table == NULL)
|
||||||
{
|
{
|
||||||
@ -325,6 +331,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
/* Uh oh, we couldn't find a matching handle */
|
/* Uh oh, we couldn't find a matching handle */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add this this library into the cache */
|
||||||
|
GetLibraryInfo((void *)dlbase);
|
||||||
|
|
||||||
/* See if we already have a symbol table for this library */
|
/* See if we already have a symbol table for this library */
|
||||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
@ -429,21 +438,25 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr)
|
||||||
{
|
{
|
||||||
uintptr_t baseAddr;
|
uintptr_t baseAddr;
|
||||||
|
|
||||||
if (libPtr == NULL)
|
if (libPtr == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynLibInfo lib;
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
|
||||||
#ifdef PLATFORM_X86
|
#ifdef PLATFORM_X86
|
||||||
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386;
|
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386;
|
||||||
|
const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
|
||||||
#else
|
#else
|
||||||
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64;
|
const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64;
|
||||||
|
const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MEMORY_BASIC_INFORMATION info;
|
MEMORY_BASIC_INFORMATION info;
|
||||||
@ -454,7 +467,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
||||||
@ -466,21 +479,21 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
opt = &pe->OptionalHeader;
|
opt = &pe->OptionalHeader;
|
||||||
|
|
||||||
/* Check PE magic and signature */
|
/* Check PE magic and signature */
|
||||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check architecture */
|
/* Check architecture */
|
||||||
if (file->Machine != PE_FILE_MACHINE)
|
if (file->Machine != PE_FILE_MACHINE)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For our purposes, this must be a dynamic library */
|
/* For our purposes, this must be a dynamic library */
|
||||||
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, we can do this */
|
/* Finally, we can do this */
|
||||||
@ -507,12 +520,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
if (!dladdr(libPtr, &info))
|
if (!dladdr(libPtr, &info))
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.dli_fbase || !info.dli_fname)
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is for our insane sanity checks :o */
|
/* This is for our insane sanity checks :o */
|
||||||
@ -522,31 +535,31 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
/* Check ELF magic */
|
/* Check ELF magic */
|
||||||
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check ELF version */
|
/* Check ELF version */
|
||||||
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check ELF endianness */
|
/* Check ELF endianness */
|
||||||
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
|
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check ELF architecture */
|
/* Check ELF architecture */
|
||||||
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
|
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For our purposes, this must be a dynamic library/shared object */
|
/* For our purposes, this must be a dynamic library/shared object */
|
||||||
if (file->e_type != ET_DYN)
|
if (file->e_type != ET_DYN)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
phdrCount = file->e_phnum;
|
phdrCount = file->e_phnum;
|
||||||
@ -596,12 +609,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
if (!dladdr(libPtr, &info))
|
if (!dladdr(libPtr, &info))
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.dli_fbase || !info.dli_fname)
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is for our insane sanity checks :o */
|
/* This is for our insane sanity checks :o */
|
||||||
@ -611,19 +624,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
/* Check Mach-O magic */
|
/* Check Mach-O magic */
|
||||||
if (file->magic != MACH_MAGIC)
|
if (file->magic != MACH_MAGIC)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check architecture */
|
/* Check architecture */
|
||||||
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
|
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For our purposes, this must be a dynamic library */
|
/* For our purposes, this must be a dynamic library */
|
||||||
if (file->filetype != MH_DYLIB)
|
if (file->filetype != MH_DYLIB)
|
||||||
{
|
{
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_count = file->ncmds;
|
cmd_count = file->ncmds;
|
||||||
@ -644,5 +657,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
|
|
||||||
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||||
|
|
||||||
return true;
|
LibraryInfoMap::Insert i = m_InfoMap.findForAdd(lib.baseAddress);
|
||||||
|
if (i.found())
|
||||||
|
{
|
||||||
|
// We already loaded this binary before.
|
||||||
|
return &i->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a copy of the binary in its initial unpatched state for lookup.
|
||||||
|
lib.originalCopy = std::make_unique<char[]>(lib.memorySize);
|
||||||
|
memcpy(lib.originalCopy.get(), lib.baseAddress, lib.memorySize);
|
||||||
|
m_InfoMap.add(i, lib.baseAddress, std::move(lib));
|
||||||
|
|
||||||
|
return &i->value;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include <IMemoryUtils.h>
|
#include <IMemoryUtils.h>
|
||||||
|
#include <am-hashmap.h>
|
||||||
|
#include <memory>
|
||||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include "sm_symtable.h"
|
#include "sm_symtable.h"
|
||||||
@ -49,6 +51,7 @@ struct DynLibInfo
|
|||||||
{
|
{
|
||||||
void *baseAddress;
|
void *baseAddress;
|
||||||
size_t memorySize;
|
size_t memorySize;
|
||||||
|
std::unique_ptr<char[]> originalCopy;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
@ -73,7 +76,7 @@ public: // IMemoryUtils
|
|||||||
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
|
||||||
void *ResolveSymbol(void *handle, const char *symbol);
|
void *ResolveSymbol(void *handle, const char *symbol);
|
||||||
public:
|
public:
|
||||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
const DynLibInfo *GetLibraryInfo(const void *libPtr);
|
||||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
private:
|
private:
|
||||||
CVector<LibSymbolTable *> m_SymTables;
|
CVector<LibSymbolTable *> m_SymTables;
|
||||||
@ -83,6 +86,8 @@ private:
|
|||||||
SInt32 m_OSXMinor;
|
SInt32 m_OSXMinor;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
|
||||||
|
LibraryInfoMap m_InfoMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MemoryUtils g_MemUtils;
|
extern MemoryUtils g_MemUtils;
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <IShareSys.h>
|
#include <IShareSys.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <am-autoptr.h>
|
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
#include <am-utility.h>
|
#include <am-utility.h>
|
||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
@ -47,16 +46,14 @@ struct FakeNative
|
|||||||
FakeNative(const char *name, IPluginFunction *fun)
|
FakeNative(const char *name, IPluginFunction *fun)
|
||||||
: name(name),
|
: name(name),
|
||||||
ctx(fun->GetParentContext()),
|
ctx(fun->GetParentContext()),
|
||||||
call(fun),
|
call(fun)
|
||||||
gate(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~FakeNative();
|
|
||||||
|
|
||||||
ke::AString name;
|
std::string name;
|
||||||
IPluginContext *ctx;
|
IPluginContext *ctx;
|
||||||
IPluginFunction *call;
|
IPluginFunction *call;
|
||||||
SPVM_NATIVE_FUNC gate;
|
ke::RefPtr<INativeCallback> wrapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native : public ke::Refcounted<Native>
|
struct Native : public ke::Refcounted<Native>
|
||||||
@ -64,31 +61,25 @@ struct Native : public ke::Refcounted<Native>
|
|||||||
Native(CNativeOwner *owner, const sp_nativeinfo_t *native)
|
Native(CNativeOwner *owner, const sp_nativeinfo_t *native)
|
||||||
: owner(owner),
|
: owner(owner),
|
||||||
native(native),
|
native(native),
|
||||||
fake(NULL)
|
fake(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Native(CNativeOwner *owner, FakeNative *fake)
|
Native(CNativeOwner *owner, std::unique_ptr<FakeNative>&& fake)
|
||||||
: owner(owner),
|
: owner(owner),
|
||||||
native(NULL),
|
native(nullptr),
|
||||||
fake(fake)
|
fake(std::move(fake))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CNativeOwner *owner;
|
CNativeOwner *owner;
|
||||||
const sp_nativeinfo_t *native;
|
const sp_nativeinfo_t *native;
|
||||||
ke::AutoPtr<FakeNative> fake;
|
std::unique_ptr<FakeNative> fake;
|
||||||
|
|
||||||
SPVM_NATIVE_FUNC func() const
|
|
||||||
{
|
|
||||||
if (native)
|
|
||||||
return native->func;
|
|
||||||
return fake->gate;
|
|
||||||
}
|
|
||||||
const char *name() const
|
const char *name() const
|
||||||
{
|
{
|
||||||
if (native)
|
if (native)
|
||||||
return native->name;
|
return native->name;
|
||||||
return fake->name.chars();
|
return fake->name.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool matches(const char *name, const ke::RefPtr<Native> &entry)
|
static inline bool matches(const char *name, const ke::RefPtr<Native> &entry)
|
||||||
|
|||||||
@ -62,7 +62,7 @@ void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives)
|
|||||||
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
||||||
g_ShareSys.AddNativeToCache(this, native);
|
g_ShareSys.AddNativeToCache(this, native);
|
||||||
|
|
||||||
m_natives.append(natives);
|
m_natives.push_back(natives);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
|
void CNativeOwner::UnbindWeakRef(const WeakNative &ref)
|
||||||
@ -90,14 +90,14 @@ void CNativeOwner::DropEverything()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Strip all of our natives from the cache */
|
/* Strip all of our natives from the cache */
|
||||||
for (size_t i = 0; i < m_natives.length(); i++) {
|
for (size_t i = 0; i < m_natives.size(); i++) {
|
||||||
const sp_nativeinfo_t *natives = m_natives[i];
|
const sp_nativeinfo_t *natives = m_natives[i];
|
||||||
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++)
|
||||||
g_ShareSys.ClearNativeFromCache(this, native->name);
|
g_ShareSys.ClearNativeFromCache(this, native->name);
|
||||||
}
|
}
|
||||||
m_natives.clear();
|
m_natives.clear();
|
||||||
|
|
||||||
for (size_t i = 0; i < m_fakes.length(); i++)
|
for (size_t i = 0; i < m_fakes.size(); i++)
|
||||||
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
|
g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name());
|
||||||
m_fakes.clear();
|
m_fakes.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <sp_vm_types.h>
|
#include <sp_vm_types.h>
|
||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <am-linkedlist.h>
|
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include "Native.h"
|
#include "Native.h"
|
||||||
@ -80,8 +79,8 @@ protected:
|
|||||||
List<CPlugin *> m_Dependents;
|
List<CPlugin *> m_Dependents;
|
||||||
unsigned int m_nMarkSerial;
|
unsigned int m_nMarkSerial;
|
||||||
List<WeakNative> m_WeakRefs;
|
List<WeakNative> m_WeakRefs;
|
||||||
ke::Vector<const sp_nativeinfo_t *> m_natives;
|
std::vector<const sp_nativeinfo_t *> m_natives;
|
||||||
ke::Vector<ke::RefPtr<Native> > m_fakes;
|
std::vector<ke::RefPtr<Native> > m_fakes;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CNativeOwner g_CoreNatives;
|
extern CNativeOwner g_CoreNatives;
|
||||||
|
|||||||
@ -45,10 +45,11 @@
|
|||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "frame_tasks.h"
|
#include "frame_tasks.h"
|
||||||
#include <amtl/am-string.h>
|
#include <amtl/am-string.h>
|
||||||
#include <amtl/am-linkedlist.h>
|
|
||||||
#include <bridge/include/IVEngineServerBridge.h>
|
#include <bridge/include/IVEngineServerBridge.h>
|
||||||
#include <bridge/include/CoreProvider.h>
|
#include <bridge/include/CoreProvider.h>
|
||||||
|
|
||||||
|
#define SOURCEMOD_PLUGINAPI_VERSION 7
|
||||||
|
|
||||||
CPluginManager g_PluginSys;
|
CPluginManager g_PluginSys;
|
||||||
HandleType_t g_PluginType = 0;
|
HandleType_t g_PluginType = 0;
|
||||||
IdentityType_t g_PluginIdent = 0;
|
IdentityType_t g_PluginIdent = 0;
|
||||||
@ -79,7 +80,7 @@ CPlugin::CPlugin(const char *file)
|
|||||||
|
|
||||||
memset(&m_info, 0, sizeof(m_info));
|
memset(&m_info, 0, sizeof(m_info));
|
||||||
|
|
||||||
m_pPhrases = g_Translator.CreatePhraseCollection();
|
m_pPhrases.reset(g_Translator.CreatePhraseCollection());
|
||||||
}
|
}
|
||||||
|
|
||||||
CPlugin::~CPlugin()
|
CPlugin::~CPlugin()
|
||||||
@ -227,7 +228,7 @@ bool CPlugin::SetProperty(const char *prop, void *ptr)
|
|||||||
|
|
||||||
IPluginRuntime *CPlugin::GetRuntime()
|
IPluginRuntime *CPlugin::GetRuntime()
|
||||||
{
|
{
|
||||||
return m_pRuntime;
|
return m_pRuntime.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::EvictWithError(PluginStatus status, const char *error_fmt, ...)
|
void CPlugin::EvictWithError(PluginStatus status, const char *error_fmt, ...)
|
||||||
@ -276,7 +277,7 @@ bool CPlugin::ReadInfo()
|
|||||||
sm_plugininfo_c_t *cinfo;
|
sm_plugininfo_c_t *cinfo;
|
||||||
cell_t local_addr;
|
cell_t local_addr;
|
||||||
|
|
||||||
auto update_field = [base](cell_t addr, ke::AString *dest) {
|
auto update_field = [base](cell_t addr, std::string *dest) {
|
||||||
const char* ptr;
|
const char* ptr;
|
||||||
if (base->LocalToString(addr, (char **)&ptr) == SP_ERROR_NONE)
|
if (base->LocalToString(addr, (char **)&ptr) == SP_ERROR_NONE)
|
||||||
*dest = ptr;
|
*dest = ptr;
|
||||||
@ -310,12 +311,12 @@ bool CPlugin::ReadInfo()
|
|||||||
|
|
||||||
base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
|
base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
|
||||||
m_FileVersion = info->version;
|
m_FileVersion = info->version;
|
||||||
if (m_FileVersion >= 4) {
|
if (m_FileVersion >= 5) {
|
||||||
base->LocalToString(info->date, (char **)&pDate);
|
base->LocalToString(info->date, (char **)&pDate);
|
||||||
base->LocalToString(info->time, (char **)&pTime);
|
base->LocalToString(info->time, (char **)&pTime);
|
||||||
ke::SafeSprintf(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
|
ke::SafeSprintf(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
|
||||||
}
|
}
|
||||||
if (m_FileVersion > 5) {
|
if (m_FileVersion > SOURCEMOD_PLUGINAPI_VERSION) {
|
||||||
base->LocalToString(info->filevers, (char **)&pFileVers);
|
base->LocalToString(info->filevers, (char **)&pFileVers);
|
||||||
EvictWithError(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
|
EvictWithError(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
|
||||||
return false;
|
return false;
|
||||||
@ -483,7 +484,7 @@ bool CPlugin::TryCompile()
|
|||||||
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", m_filename);
|
g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", m_filename);
|
||||||
|
|
||||||
char loadmsg[255];
|
char loadmsg[255];
|
||||||
m_pRuntime = g_pSourcePawn2->LoadBinaryFromFile(fullpath, loadmsg, sizeof(loadmsg));
|
m_pRuntime.reset(g_pSourcePawn2->LoadBinaryFromFile(fullpath, loadmsg, sizeof(loadmsg)));
|
||||||
if (!m_pRuntime) {
|
if (!m_pRuntime) {
|
||||||
EvictWithError(Plugin_BadLoad, "Unable to load plugin (%s)", loadmsg);
|
EvictWithError(Plugin_BadLoad, "Unable to load plugin (%s)", loadmsg);
|
||||||
return false;
|
return false;
|
||||||
@ -524,11 +525,11 @@ PluginType CPlugin::GetType()
|
|||||||
|
|
||||||
const sm_plugininfo_t *CPlugin::GetPublicInfo()
|
const sm_plugininfo_t *CPlugin::GetPublicInfo()
|
||||||
{
|
{
|
||||||
m_info.author = info_author_.chars();
|
m_info.author = info_author_.c_str();
|
||||||
m_info.description = info_description_.chars();
|
m_info.description = info_description_.c_str();
|
||||||
m_info.name = info_name_.chars();
|
m_info.name = info_name_.c_str();
|
||||||
m_info.url = info_url_.chars();
|
m_info.url = info_url_.c_str();
|
||||||
m_info.version = info_version_.chars();
|
m_info.version = info_version_.c_str();
|
||||||
return &m_info;
|
return &m_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,7 +659,7 @@ time_t CPlugin::GetFileTimeStamp()
|
|||||||
|
|
||||||
IPhraseCollection *CPlugin::GetPhrases()
|
IPhraseCollection *CPlugin::GetPhrases()
|
||||||
{
|
{
|
||||||
return m_pPhrases;
|
return m_pPhrases.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::DependencyDropped(CPlugin *pOwner)
|
void CPlugin::DependencyDropped(CPlugin *pOwner)
|
||||||
@ -674,7 +675,7 @@ void CPlugin::DependencyDropped(CPlugin *pOwner)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int unbound = 0;
|
unsigned int unbound = 0;
|
||||||
for (size_t i = 0; i < pOwner->m_fakes.length(); i++)
|
for (size_t i = 0; i < pOwner->m_fakes.size(); i++)
|
||||||
{
|
{
|
||||||
ke::RefPtr<Native> entry(pOwner->m_fakes[i]);
|
ke::RefPtr<Native> entry(pOwner->m_fakes[i]);
|
||||||
|
|
||||||
@ -773,13 +774,13 @@ bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKEN
|
|||||||
if (!entry)
|
if (!entry)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_fakes.append(entry);
|
m_fakes.push_back(entry);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::BindFakeNativesTo(CPlugin *other)
|
void CPlugin::BindFakeNativesTo(CPlugin *other)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_fakes.length(); i++)
|
for (size_t i = 0; i < m_fakes.size(); i++)
|
||||||
g_ShareSys.BindNativeToPlugin(other, m_fakes[i]);
|
g_ShareSys.BindNativeToPlugin(other, m_fakes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,7 +791,7 @@ void CPlugin::BindFakeNativesTo(CPlugin *other)
|
|||||||
CPluginManager::CPluginIterator::CPluginIterator(ReentrantList<CPlugin *>& in)
|
CPluginManager::CPluginIterator::CPluginIterator(ReentrantList<CPlugin *>& in)
|
||||||
{
|
{
|
||||||
for (PluginIter iter(in); !iter.done(); iter.next())
|
for (PluginIter iter(in); !iter.done(); iter.next())
|
||||||
mylist.append(*iter);
|
mylist.push_back(*iter);
|
||||||
current = mylist.begin();
|
current = mylist.begin();
|
||||||
g_PluginSys.AddPluginsListener(this);
|
g_PluginSys.AddPluginsListener(this);
|
||||||
}
|
}
|
||||||
@ -847,11 +848,7 @@ CPluginManager::~CPluginManager()
|
|||||||
|
|
||||||
void CPluginManager::Shutdown()
|
void CPluginManager::Shutdown()
|
||||||
{
|
{
|
||||||
List<CPlugin *>::iterator iter;
|
UnloadAll();
|
||||||
|
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
|
|
||||||
UnloadPlugin(*iter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::LoadAll(const char *config_path, const char *plugins_path)
|
void CPluginManager::LoadAll(const char *config_path, const char *plugins_path)
|
||||||
@ -979,6 +976,20 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ
|
|||||||
LoadRes res;
|
LoadRes res;
|
||||||
|
|
||||||
*wasloaded = false;
|
*wasloaded = false;
|
||||||
|
|
||||||
|
if (strstr(path, "..") != NULL)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(error, maxlength, "Cannot load plugins outside the \"plugins\" folder");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ext = libsys->GetFileExtension(path);
|
||||||
|
if (!ext || strcmp(ext, "smx") != 0)
|
||||||
|
{
|
||||||
|
ke::SafeStrcpy(error, maxlength, "Plugin files must have the \".smx\" file extension");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((res=LoadPlugin(&pl, path, true, PluginType_MapUpdated)) == LoadRes_Failure)
|
if ((res=LoadPlugin(&pl, path, true, PluginType_MapUpdated)) == LoadRes_Failure)
|
||||||
{
|
{
|
||||||
ke::SafeStrcpy(error, maxlength, pl->GetErrorMsg());
|
ke::SafeStrcpy(error, maxlength, pl->GetErrorMsg());
|
||||||
@ -1033,7 +1044,7 @@ void CPluginManager::LoadAutoPlugin(const char *plugin)
|
|||||||
|
|
||||||
void CPluginManager::AddPlugin(CPlugin *pPlugin)
|
void CPluginManager::AddPlugin(CPlugin *pPlugin)
|
||||||
{
|
{
|
||||||
m_plugins.append(pPlugin);
|
m_plugins.push_back(pPlugin);
|
||||||
m_LoadLookup.insert(pPlugin->GetFilename(), pPlugin);
|
m_LoadLookup.insert(pPlugin->GetFilename(), pPlugin);
|
||||||
|
|
||||||
pPlugin->SetRegistered();
|
pPlugin->SetRegistered();
|
||||||
@ -1165,7 +1176,7 @@ bool CPlugin::ForEachExtVar(const ExtVarCallback& callback)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlugin::ForEachLibrary(ke::Lambda<void(const char *)> callback)
|
void CPlugin::ForEachLibrary(ke::Function<void(const char *)> callback)
|
||||||
{
|
{
|
||||||
for (auto iter = m_Libraries.begin(); iter != m_Libraries.end(); iter++)
|
for (auto iter = m_Libraries.begin(); iter != m_Libraries.end(); iter++)
|
||||||
callback((*iter).c_str());
|
callback((*iter).c_str());
|
||||||
@ -1177,7 +1188,7 @@ void CPlugin::AddRequiredLib(const char *name)
|
|||||||
m_RequiredLibs.push_back(name);
|
m_RequiredLibs.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPlugin::ForEachRequiredLib(ke::Lambda<bool(const char *)> callback)
|
bool CPlugin::ForEachRequiredLib(ke::Function<bool(const char *)> callback)
|
||||||
{
|
{
|
||||||
for (auto iter = m_RequiredLibs.begin(); iter != m_RequiredLibs.end(); iter++) {
|
for (auto iter = m_RequiredLibs.begin(); iter != m_RequiredLibs.end(); iter++) {
|
||||||
if (!callback((*iter).c_str()))
|
if (!callback((*iter).c_str()))
|
||||||
@ -1211,7 +1222,7 @@ void CPluginManager::LoadExtensions(CPlugin *pPlugin)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
pPlugin->ForEachExtVar(ke::Move(callback));
|
pPlugin->ForEachExtVar(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPluginManager::RequireExtensions(CPlugin *pPlugin)
|
bool CPluginManager::RequireExtensions(CPlugin *pPlugin)
|
||||||
@ -1247,7 +1258,7 @@ bool CPluginManager::RequireExtensions(CPlugin *pPlugin)
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
return pPlugin->ForEachExtVar(ke::Move(callback));
|
return pPlugin->ForEachExtVar(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
CPlugin *CPluginManager::CompileAndPrep(const char *path)
|
CPlugin *CPluginManager::CompileAndPrep(const char *path)
|
||||||
@ -1490,6 +1501,9 @@ void CPluginManager::Purge(CPlugin *plugin)
|
|||||||
if (plugin->GetStatus() == Plugin_Running)
|
if (plugin->GetStatus() == Plugin_Running)
|
||||||
plugin->Call_OnPluginEnd();
|
plugin->Call_OnPluginEnd();
|
||||||
|
|
||||||
|
m_pOnNotifyPluginUnloaded->PushCell(plugin->GetMyHandle());
|
||||||
|
m_pOnNotifyPluginUnloaded->Execute(NULL);
|
||||||
|
|
||||||
// Notify listeners of unloading.
|
// Notify listeners of unloading.
|
||||||
if (plugin->EnteredSecondPass()) {
|
if (plugin->EnteredSecondPass()) {
|
||||||
for (ListenerIter iter(m_listeners); !iter.done(); iter.next())
|
for (ListenerIter iter(m_listeners); !iter.done(); iter.next())
|
||||||
@ -1536,12 +1550,12 @@ CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx)
|
|||||||
|
|
||||||
unsigned int CPluginManager::GetPluginCount()
|
unsigned int CPluginManager::GetPluginCount()
|
||||||
{
|
{
|
||||||
return m_plugins.length();
|
return m_plugins.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
|
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
|
||||||
{
|
{
|
||||||
m_listeners.append(listener);
|
m_listeners.push_back(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
|
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
|
||||||
@ -1578,6 +1592,7 @@ void CPluginManager::OnSourceModAllInitialized()
|
|||||||
|
|
||||||
m_pOnLibraryAdded = forwardsys->CreateForward("OnLibraryAdded", ET_Ignore, 1, NULL, Param_String);
|
m_pOnLibraryAdded = forwardsys->CreateForward("OnLibraryAdded", ET_Ignore, 1, NULL, Param_String);
|
||||||
m_pOnLibraryRemoved = forwardsys->CreateForward("OnLibraryRemoved", ET_Ignore, 1, NULL, Param_String);
|
m_pOnLibraryRemoved = forwardsys->CreateForward("OnLibraryRemoved", ET_Ignore, 1, NULL, Param_String);
|
||||||
|
m_pOnNotifyPluginUnloaded = forwardsys->CreateForward("OnNotifyPluginUnloaded", ET_Ignore, 1, NULL, Param_Cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::OnSourceModShutdown()
|
void CPluginManager::OnSourceModShutdown()
|
||||||
@ -1592,6 +1607,7 @@ void CPluginManager::OnSourceModShutdown()
|
|||||||
|
|
||||||
forwardsys->ReleaseForward(m_pOnLibraryAdded);
|
forwardsys->ReleaseForward(m_pOnLibraryAdded);
|
||||||
forwardsys->ReleaseForward(m_pOnLibraryRemoved);
|
forwardsys->ReleaseForward(m_pOnLibraryRemoved);
|
||||||
|
forwardsys->ReleaseForward(m_pOnNotifyPluginUnloaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
|
ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
|
||||||
@ -1715,7 +1731,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
|
|||||||
rootmenu->ConsolePrint("[SM] Listing %d plugin%s:", plnum, (plnum > 1) ? "s" : "");
|
rootmenu->ConsolePrint("[SM] Listing %d plugin%s:", plnum, (plnum > 1) ? "s" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
ke::LinkedList<CPlugin *> fail_list;
|
std::list<CPlugin *> fail_list;
|
||||||
|
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) {
|
for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) {
|
||||||
CPlugin *pl = (*iter);
|
CPlugin *pl = (*iter);
|
||||||
@ -1727,7 +1743,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
|
|||||||
len += ke::SafeSprintf(buffer, sizeof(buffer), " %0*d <%s>", plpadding, id, GetStatusText(pl->GetDisplayStatus()));
|
len += ke::SafeSprintf(buffer, sizeof(buffer), " %0*d <%s>", plpadding, id, GetStatusText(pl->GetDisplayStatus()));
|
||||||
|
|
||||||
/* Plugin has failed to load. */
|
/* Plugin has failed to load. */
|
||||||
fail_list.append(pl);
|
fail_list.push_back(pl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2033,7 +2049,8 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
|
|||||||
//the unload/reload attempt next frame will print a message
|
//the unload/reload attempt next frame will print a message
|
||||||
case PluginState::WaitingToUnload:
|
case PluginState::WaitingToUnload:
|
||||||
case PluginState::WaitingToUnloadAndReload:
|
case PluginState::WaitingToUnloadAndReload:
|
||||||
return;
|
rootmenu->ConsolePrint("[SM] Plugin %s will be reloaded on the next frame.", name);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
|
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
|
||||||
@ -2063,7 +2080,7 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print)
|
|||||||
if (state == PluginState::WaitingToUnloadAndReload)
|
if (state == PluginState::WaitingToUnloadAndReload)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ke::AString filename(pl->GetFilename());
|
std::string filename(pl->GetFilename());
|
||||||
PluginType ptype = pl->GetType();
|
PluginType ptype = pl->GetType();
|
||||||
|
|
||||||
int id = 1;
|
int id = 1;
|
||||||
@ -2078,13 +2095,13 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print)
|
|||||||
{
|
{
|
||||||
pl->SetWaitingToUnload(true);
|
pl->SetWaitingToUnload(true);
|
||||||
ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void {
|
ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void {
|
||||||
ReloadPluginImpl(id, filename.chars(), ptype, print);
|
ReloadPluginImpl(id, filename.c_str(), ptype, print);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadPluginImpl(id, filename.chars(), ptype, false);
|
ReloadPluginImpl(id, filename.c_str(), ptype, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2208,7 +2225,6 @@ void CPluginManager::UnloadAll()
|
|||||||
int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
|
int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
|
||||||
{
|
{
|
||||||
int id = 1;
|
int id = 1;
|
||||||
List<CPlugin *>::iterator iter;
|
|
||||||
|
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
|
for (PluginIter iter(m_plugins); !iter.done(); iter.next()) {
|
||||||
if ((*iter) == pl)
|
if ((*iter) == pl)
|
||||||
@ -2273,7 +2289,7 @@ void CPluginManager::FreePluginList(const CVector<SMPlugin *> *list)
|
|||||||
delete const_cast<CVector<SMPlugin *> *>(list);
|
delete const_cast<CVector<SMPlugin *> *>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginManager::ForEachPlugin(ke::Lambda<void(CPlugin *)> callback)
|
void CPluginManager::ForEachPlugin(ke::Function<void(CPlugin *)> callback)
|
||||||
{
|
{
|
||||||
for (PluginIter iter(m_plugins); !iter.done(); iter.next())
|
for (PluginIter iter(m_plugins); !iter.done(); iter.next())
|
||||||
callback(*iter);
|
callback(*iter);
|
||||||
@ -2351,7 +2367,7 @@ public:
|
|||||||
{
|
{
|
||||||
ke::RefPtr<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener);
|
ke::RefPtr<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener);
|
||||||
|
|
||||||
v1_wrappers_.append(wrapper);
|
v1_wrappers_.push_back(wrapper);
|
||||||
g_PluginSys.AddPluginsListener(wrapper);
|
g_PluginSys.AddPluginsListener(wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2394,4 +2410,4 @@ static OldPluginAPI sOldPluginAPI;
|
|||||||
IPluginManager *CPluginManager::GetOldAPI()
|
IPluginManager *CPluginManager::GetOldAPI()
|
||||||
{
|
{
|
||||||
return &sOldPluginAPI;
|
return &sOldPluginAPI;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,9 +32,12 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <IPluginSys.h>
|
#include <IPluginSys.h>
|
||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
@ -129,10 +132,10 @@ public:
|
|||||||
bool required;
|
bool required;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ke::Lambda<bool(const sp_pubvar_t *, const ExtVar& ext)> ExtVarCallback;
|
typedef ke::Function<bool(const sp_pubvar_t *, const ExtVar& ext)> ExtVarCallback;
|
||||||
bool ForEachExtVar(const ExtVarCallback& callback);
|
bool ForEachExtVar(const ExtVarCallback& callback);
|
||||||
|
|
||||||
void ForEachLibrary(ke::Lambda<void(const char *)> callback);
|
void ForEachLibrary(ke::Function<void(const char *)> callback);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a plugin object with default values.
|
* Creates a plugin object with default values.
|
||||||
@ -215,7 +218,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddRequiredLib(const char *name);
|
void AddRequiredLib(const char *name);
|
||||||
bool ForEachRequiredLib(ke::Lambda<bool(const char *)> callback);
|
bool ForEachRequiredLib(ke::Function<bool(const char *)> callback);
|
||||||
|
|
||||||
bool HasMissingFakeNatives() const {
|
bool HasMissingFakeNatives() const {
|
||||||
return m_FakeNativesMissing;
|
return m_FakeNativesMissing;
|
||||||
@ -224,7 +227,7 @@ public:
|
|||||||
return m_LibraryMissing;
|
return m_LibraryMissing;
|
||||||
}
|
}
|
||||||
bool HasFakeNatives() const {
|
bool HasFakeNatives() const {
|
||||||
return m_fakes.length() > 0;
|
return m_fakes.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// True if we got far enough into the second pass to call OnPluginLoaded
|
// True if we got far enough into the second pass to call OnPluginLoaded
|
||||||
@ -267,8 +270,8 @@ private:
|
|||||||
char m_errormsg[256];
|
char m_errormsg[256];
|
||||||
|
|
||||||
// Internal properties that must by reset if the runtime is evicted.
|
// Internal properties that must by reset if the runtime is evicted.
|
||||||
ke::AutoPtr<IPluginRuntime> m_pRuntime;
|
std::unique_ptr<IPluginRuntime> m_pRuntime;
|
||||||
ke::AutoPtr<CPhraseCollection> m_pPhrases;
|
std::unique_ptr<CPhraseCollection> m_pPhrases;
|
||||||
IPluginContext *m_pContext;
|
IPluginContext *m_pContext;
|
||||||
sp_pubvar_t *m_MaxClientsVar;
|
sp_pubvar_t *m_MaxClientsVar;
|
||||||
StringHashMap<void *> m_Props;
|
StringHashMap<void *> m_Props;
|
||||||
@ -286,11 +289,11 @@ private:
|
|||||||
|
|
||||||
// Cached.
|
// Cached.
|
||||||
sm_plugininfo_t m_info;
|
sm_plugininfo_t m_info;
|
||||||
ke::AString info_name_;
|
std::string info_name_;
|
||||||
ke::AString info_author_;
|
std::string info_author_;
|
||||||
ke::AString info_description_;
|
std::string info_description_;
|
||||||
ke::AString info_version_;
|
std::string info_version_;
|
||||||
ke::AString info_url_;
|
std::string info_url_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPluginManager :
|
class CPluginManager :
|
||||||
@ -317,8 +320,8 @@ public:
|
|||||||
void Release();
|
void Release();
|
||||||
void OnPluginDestroyed(IPlugin *plugin) override;
|
void OnPluginDestroyed(IPlugin *plugin) override;
|
||||||
private:
|
private:
|
||||||
ke::LinkedList<CPlugin *> mylist;
|
std::list<CPlugin *> mylist;
|
||||||
ke::LinkedList<CPlugin *>::iterator current;
|
std::list<CPlugin *>::iterator current;
|
||||||
};
|
};
|
||||||
friend class CPluginManager::CPluginIterator;
|
friend class CPluginManager::CPluginIterator;
|
||||||
public: //IScriptManager
|
public: //IScriptManager
|
||||||
@ -432,7 +435,7 @@ public:
|
|||||||
|
|
||||||
void _SetPauseState(CPlugin *pPlugin, bool pause);
|
void _SetPauseState(CPlugin *pPlugin, bool pause);
|
||||||
|
|
||||||
void ForEachPlugin(ke::Lambda<void(CPlugin *)> callback);
|
void ForEachPlugin(ke::Function<void(CPlugin *)> callback);
|
||||||
private:
|
private:
|
||||||
LoadRes LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type);
|
LoadRes LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type);
|
||||||
|
|
||||||
@ -473,7 +476,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
ReentrantList<IPluginsListener *> m_listeners;
|
ReentrantList<IPluginsListener *> m_listeners;
|
||||||
ReentrantList<CPlugin *> m_plugins;
|
ReentrantList<CPlugin *> m_plugins;
|
||||||
ke::LinkedList<CPluginIterator *> m_iterators;
|
std::list<CPluginIterator *> m_iterators;
|
||||||
|
|
||||||
typedef decltype(m_listeners)::iterator ListenerIter;
|
typedef decltype(m_listeners)::iterator ListenerIter;
|
||||||
typedef decltype(m_plugins)::iterator PluginIter;
|
typedef decltype(m_plugins)::iterator PluginIter;
|
||||||
@ -484,10 +487,8 @@ private:
|
|||||||
{
|
{
|
||||||
/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */
|
/* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */
|
||||||
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
||||||
ke::AString original(key.chars());
|
std::string lower = ke::Lowercase(key.c_str());
|
||||||
ke::AString lower = original.lowercase();
|
return detail::CharsAndLength(lower.c_str()).hash();
|
||||||
|
|
||||||
return detail::CharsAndLength(lower.chars()).hash();
|
|
||||||
#else
|
#else
|
||||||
return key.hash();
|
return key.hash();
|
||||||
#endif
|
#endif
|
||||||
@ -497,8 +498,8 @@ private:
|
|||||||
{
|
{
|
||||||
const char *pluginFileChars = const_cast<CPlugin*>(plugin)->GetFilename();
|
const char *pluginFileChars = const_cast<CPlugin*>(plugin)->GetFilename();
|
||||||
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
#if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE
|
||||||
ke::AString pluginFile = ke::AString(pluginFileChars).lowercase();
|
std::string pluginFile = ke::Lowercase(pluginFileChars);
|
||||||
ke::AString input = ke::AString(file).lowercase();
|
std::string input = ke::Lowercase(file);
|
||||||
|
|
||||||
return pluginFile == input;
|
return pluginFile == input;
|
||||||
#else
|
#else
|
||||||
@ -522,6 +523,7 @@ private:
|
|||||||
// Forwards
|
// Forwards
|
||||||
IForward *m_pOnLibraryAdded;
|
IForward *m_pOnLibraryAdded;
|
||||||
IForward *m_pOnLibraryRemoved;
|
IForward *m_pOnLibraryRemoved;
|
||||||
|
IForward *m_pOnNotifyPluginUnloaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPluginManager g_PluginSys;
|
extern CPluginManager g_PluginSys;
|
||||||
|
|||||||
@ -52,7 +52,7 @@ ProfileToolManager::OnSourceModShutdown()
|
|||||||
IProfilingTool *
|
IProfilingTool *
|
||||||
ProfileToolManager::FindToolByName(const char *name)
|
ProfileToolManager::FindToolByName(const char *name)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < tools_.length(); i++) {
|
for (size_t i = 0; i < tools_.size(); i++) {
|
||||||
if (strcmp(tools_[i]->Name(), name) == 0)
|
if (strcmp(tools_[i]->Name(), name) == 0)
|
||||||
return tools_[i];
|
return tools_[i];
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ ProfileToolManager::StartFromConsole(IProfilingTool *tool)
|
|||||||
void
|
void
|
||||||
ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args)
|
ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args)
|
||||||
{
|
{
|
||||||
if (tools_.length() == 0) {
|
if (tools_.size() == 0) {
|
||||||
rootmenu->ConsolePrint("No profiling tools are enabled.");
|
rootmenu->ConsolePrint("No profiling tools are enabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
|||||||
|
|
||||||
if (strcmp(cmdname, "list") == 0) {
|
if (strcmp(cmdname, "list") == 0) {
|
||||||
rootmenu->ConsolePrint("Profiling tools:");
|
rootmenu->ConsolePrint("Profiling tools:");
|
||||||
for (size_t i = 0; i < tools_.length(); i++) {
|
for (size_t i = 0; i < tools_.size(); i++) {
|
||||||
rootmenu->DrawGenericOption(tools_[i]->Name(), tools_[i]->Description());
|
rootmenu->DrawGenericOption(tools_[i]->Name(), tools_[i]->Description());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -135,7 +135,7 @@ ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs
|
|||||||
if (strcmp(cmdname, "start") == 0) {
|
if (strcmp(cmdname, "start") == 0) {
|
||||||
if (!default_) {
|
if (!default_) {
|
||||||
default_ = FindToolByName("vprof");
|
default_ = FindToolByName("vprof");
|
||||||
if (!default_ && tools_.length() > 0)
|
if (!default_ && tools_.size() > 0)
|
||||||
default_ = tools_[0];
|
default_ = tools_[0];
|
||||||
if (!default_) {
|
if (!default_) {
|
||||||
rootmenu->ConsolePrint("Could not find any profiler to use.");
|
rootmenu->ConsolePrint("Could not find any profiler to use.");
|
||||||
|
|||||||
@ -51,7 +51,7 @@ public:
|
|||||||
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args) override;
|
void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args) override;
|
||||||
|
|
||||||
void RegisterTool(IProfilingTool *tool) {
|
void RegisterTool(IProfilingTool *tool) {
|
||||||
tools_.append(tool);
|
tools_.push_back(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsActive() const {
|
bool IsActive() const {
|
||||||
@ -76,7 +76,7 @@ private:
|
|||||||
void StartFromConsole(IProfilingTool *tool);
|
void StartFromConsole(IProfilingTool *tool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ke::Vector<IProfilingTool *> tools_;
|
std::vector<IProfilingTool *> tools_;
|
||||||
IProfilingTool *active_;
|
IProfilingTool *active_;
|
||||||
IProfilingTool *default_;
|
IProfilingTool *default_;
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
|
|||||||
@ -221,11 +221,15 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const ICommandAr
|
|||||||
ConsolePrint(" Fyren");
|
ConsolePrint(" Fyren");
|
||||||
ConsolePrint(" Nicholas \"psychonic\" Hastings");
|
ConsolePrint(" Nicholas \"psychonic\" Hastings");
|
||||||
ConsolePrint(" Asher \"asherkin\" Baker");
|
ConsolePrint(" Asher \"asherkin\" Baker");
|
||||||
|
ConsolePrint(" Ruben \"Dr!fter\" Gonzalez");
|
||||||
|
ConsolePrint(" Josh \"KyleS\" Allard");
|
||||||
|
ConsolePrint(" Michael \"Headline\" Flaherty");
|
||||||
|
ConsolePrint(" Jannik \"Peace-Maker\" Hartung");
|
||||||
ConsolePrint(" Borja \"faluco\" Ferrer");
|
ConsolePrint(" Borja \"faluco\" Ferrer");
|
||||||
ConsolePrint(" Pavol \"PM OnoTo\" Marko");
|
ConsolePrint(" Pavol \"PM OnoTo\" Marko");
|
||||||
ConsolePrint(" Special thanks to Liam, ferret, and Mani");
|
ConsolePrint(" Special thanks to Liam, ferret, and Mani");
|
||||||
ConsolePrint(" Special thanks to Viper and SteamFriends");
|
ConsolePrint(" Special thanks to Viper and SteamFriends");
|
||||||
ConsolePrint(" http://www.sourcemod.net/");
|
ConsolePrint(" https://www.sourcemod.net/");
|
||||||
}
|
}
|
||||||
else if (strcmp(cmdname, "version") == 0)
|
else if (strcmp(cmdname, "version") == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -29,13 +29,16 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
#include <ILibrarySys.h>
|
#include <ILibrarySys.h>
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include "HandleSys.h"
|
#include "HandleSys.h"
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
using namespace ke;
|
using namespace ke;
|
||||||
|
|
||||||
@ -361,11 +364,11 @@ void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *native
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pPlugin->GetRuntime()->UpdateNativeBinding(
|
auto rt = pPlugin->GetRuntime();
|
||||||
index,
|
if (pEntry->fake)
|
||||||
pEntry->func(),
|
rt->UpdateNativeBindingObject(index, pEntry->fake->wrapper, flags, nullptr);
|
||||||
flags,
|
else
|
||||||
nullptr);
|
rt->UpdateNativeBinding(index, pEntry->native->func, flags, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
|
AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
|
||||||
@ -379,11 +382,6 @@ AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const s
|
|||||||
return entry.forget();
|
return entry.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeNative::~FakeNative()
|
|
||||||
{
|
|
||||||
g_pSourcePawn2->DestroyFakeNative(gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
||||||
{
|
{
|
||||||
NativeCache::Result r = m_NtvCache.find(name);
|
NativeCache::Result r = m_NtvCache.find(name);
|
||||||
@ -400,21 +398,44 @@ void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
|||||||
m_NtvCache.remove(r);
|
m_NtvCache.remove(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DynamicNative final : public INativeCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DynamicNative(SPVM_FAKENATIVE_FUNC callback, void* data)
|
||||||
|
: callback_(callback),
|
||||||
|
data_(data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void AddRef() override {
|
||||||
|
refcount_++;
|
||||||
|
}
|
||||||
|
void Release() override {
|
||||||
|
assert(refcount_ > 0);
|
||||||
|
if (--refcount_ == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
int Invoke(IPluginContext* ctx, const cell_t* params) override {
|
||||||
|
return callback_(ctx, params, data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t refcount_ = 0;
|
||||||
|
SPVM_FAKENATIVE_FUNC callback_;
|
||||||
|
void* data_;
|
||||||
|
};
|
||||||
|
|
||||||
AlreadyRefed<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
|
AlreadyRefed<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
|
||||||
{
|
{
|
||||||
RefPtr<Native> entry(FindNative(name));
|
RefPtr<Native> entry(FindNative(name));
|
||||||
if (entry)
|
if (entry)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
AutoPtr<FakeNative> fake(new FakeNative(name, pFunc));
|
std::unique_ptr<FakeNative> fake(new FakeNative(name, pFunc));
|
||||||
|
fake->wrapper = new DynamicNative(func, fake.get());
|
||||||
fake->gate = g_pSourcePawn2->CreateFakeNative(func, fake);
|
|
||||||
if (!fake->gate)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
|
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
|
||||||
|
|
||||||
entry = new Native(owner, fake.take());
|
entry = new Native(owner, std::move(fake));
|
||||||
m_NtvCache.insert(name, entry);
|
m_NtvCache.insert(name, entry);
|
||||||
|
|
||||||
return entry.forget();
|
return entry.forget();
|
||||||
|
|||||||
@ -49,15 +49,17 @@ namespace SourceMod
|
|||||||
{
|
{
|
||||||
struct IdentityToken_t
|
struct IdentityToken_t
|
||||||
{
|
{
|
||||||
Handle_t ident;
|
Handle_t ident = 0;
|
||||||
void *ptr;
|
void *ptr = nullptr;
|
||||||
IdentityType_t type;
|
IdentityType_t type = 0;
|
||||||
|
size_t num_handles = 0;
|
||||||
|
bool warned_handle_usage = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IfaceInfo
|
struct IfaceInfo
|
||||||
{
|
{
|
||||||
bool operator ==(const IfaceInfo &info)
|
bool operator ==(const IfaceInfo &info) const
|
||||||
{
|
{
|
||||||
return (info.iface == iface && info.owner == owner);
|
return (info.iface == iface && info.owner == owner);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 sw=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
@ -29,17 +29,518 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
#include <sm_platform.h>
|
#include <sm_platform.h>
|
||||||
|
#include <amtl/am-deque.h>
|
||||||
|
#include <amtl/am-maybe.h>
|
||||||
|
#include <amtl/am-thread.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include "BaseWorker.h"
|
||||||
#include "ThreadSupport.h"
|
#include "ThreadSupport.h"
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
|
|
||||||
#if defined PLATFORM_POSIX
|
static constexpr unsigned int DEFAULT_THINK_TIME_MS = 20;
|
||||||
#include "thread/PosixThreads.h"
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
#include "thread/WinThreads.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MainThreader g_MainThreader;
|
class CompatWorker final : public IThreadWorker
|
||||||
IThreader *g_pThreader = &g_MainThreader;
|
{
|
||||||
|
public:
|
||||||
|
explicit CompatWorker(IThreadWorkerCallbacks* callbacks);
|
||||||
|
~CompatWorker();
|
||||||
|
|
||||||
|
void MakeThread(IThread *pThread) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override;
|
||||||
|
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override;
|
||||||
|
unsigned int RunFrame() override;
|
||||||
|
bool Pause() override;
|
||||||
|
bool Unpause() override;
|
||||||
|
bool Start() override;
|
||||||
|
bool Stop(bool flush) override;
|
||||||
|
WorkerState GetStatus(unsigned int *numThreads) override;
|
||||||
|
void SetMaxThreadsPerFrame(unsigned int threads) override;
|
||||||
|
void SetThinkTimePerFrame(unsigned int thinktime) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Flush();
|
||||||
|
void Worker();
|
||||||
|
void RunWork(SWThreadHandle* handle);
|
||||||
|
void RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IThreadWorkerCallbacks* callbacks_;
|
||||||
|
WorkerState state_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable work_cv_;
|
||||||
|
std::deque<SWThreadHandle*> work_;
|
||||||
|
std::unique_ptr<std::thread> thread_;
|
||||||
|
std::atomic<unsigned int> jobs_per_wakeup_;
|
||||||
|
std::atomic<unsigned int> wait_between_jobs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompatWorker::CompatWorker(IThreadWorkerCallbacks* callbacks)
|
||||||
|
: callbacks_(callbacks),
|
||||||
|
state_(Worker_Stopped),
|
||||||
|
jobs_per_wakeup_(SM_DEFAULT_THREADS_PER_FRAME),
|
||||||
|
wait_between_jobs_(DEFAULT_THINK_TIME_MS)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CompatWorker::~CompatWorker()
|
||||||
|
{
|
||||||
|
Stop(false /* ignored */);
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Start()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (state_ != Worker_Stopped)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
thread_ = ke::NewThread("SM CompatWorker Thread", [this]() -> void {
|
||||||
|
Worker();
|
||||||
|
});
|
||||||
|
|
||||||
|
state_ = Worker_Running;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Stop(bool)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
if (state_ <= Worker_Stopped)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state_ = Worker_Stopped;
|
||||||
|
work_cv_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_->join();
|
||||||
|
thread_ = nullptr;
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Pause()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (state_ != Worker_Running)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state_ = Worker_Paused;
|
||||||
|
work_cv_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatWorker::Unpause()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (state_ != Worker_Paused)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state_ = Worker_Running;
|
||||||
|
work_cv_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::Flush()
|
||||||
|
{
|
||||||
|
while (!work_.empty()) {
|
||||||
|
auto handle = ke::PopFront(&work_);
|
||||||
|
handle->GetThread()->OnTerminate(handle, true);
|
||||||
|
if (handle->m_params.flags & Thread_AutoRelease)
|
||||||
|
delete handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::Worker()
|
||||||
|
{
|
||||||
|
// Note: this must be first to ensure an ordering between Worker() and
|
||||||
|
// Start(). It must also be outside of the loop to ensure the lock is
|
||||||
|
// held across wakeup and retesting the predicates.
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
if (callbacks_) {
|
||||||
|
lock.unlock();
|
||||||
|
callbacks_->OnWorkerStart(this);
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::chrono::system_clock Clock;
|
||||||
|
typedef std::chrono::time_point<Clock> TimePoint;
|
||||||
|
|
||||||
|
auto can_work = [this]() -> bool {
|
||||||
|
return state_ == Worker_Running && !work_.empty();
|
||||||
|
};
|
||||||
|
|
||||||
|
ke::Maybe<TimePoint> wait;
|
||||||
|
unsigned int work_in_frame = 0;
|
||||||
|
for (;;) {
|
||||||
|
if (state_ == Worker_Stopped)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!can_work()) {
|
||||||
|
// Wait for work or a Stop.
|
||||||
|
work_cv_.wait(lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait.isValid()) {
|
||||||
|
// Wait until the specified time has passed. If we wake up with a
|
||||||
|
// timeout, then the wait has elapsed, so reset the holder.
|
||||||
|
if (work_cv_.wait_until(lock, wait.get()) == std::cv_status::timeout)
|
||||||
|
wait = ke::Nothing();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(state_ == Worker_Running);
|
||||||
|
assert(!work_.empty());
|
||||||
|
|
||||||
|
SWThreadHandle* handle = ke::PopFront(&work_);
|
||||||
|
RunWorkLocked(&lock, handle);
|
||||||
|
work_in_frame++;
|
||||||
|
|
||||||
|
// If we've reached our max jobs per "frame", signal that the next
|
||||||
|
// immediate job must be delayed. We retain the old ThreadWorker
|
||||||
|
// behavior by checking if the queue has more work. Thus, a delay
|
||||||
|
// only occurs if two jobs would be processed in the same wakeup.
|
||||||
|
if (work_in_frame >= jobs_per_wakeup_ && wait_between_jobs_ && can_work())
|
||||||
|
wait = ke::Some(Clock::now() + std::chrono::milliseconds(wait_between_jobs_));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(lock.owns_lock());
|
||||||
|
|
||||||
|
while (!work_.empty()) {
|
||||||
|
SWThreadHandle* handle = ke::PopFront(&work_);
|
||||||
|
RunWorkLocked(&lock, handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CompatWorker::RunFrame()
|
||||||
|
{
|
||||||
|
unsigned int nprocessed = 0;
|
||||||
|
for (unsigned int i = 1; i <= jobs_per_wakeup_; i++) {
|
||||||
|
SWThreadHandle* handle;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (work_.empty())
|
||||||
|
break;
|
||||||
|
handle = ke::PopFront(&work_);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunWork(handle);
|
||||||
|
nprocessed++;
|
||||||
|
}
|
||||||
|
return nprocessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle)
|
||||||
|
{
|
||||||
|
lock->unlock();
|
||||||
|
RunWork(handle);
|
||||||
|
lock->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::RunWork(SWThreadHandle* handle)
|
||||||
|
{
|
||||||
|
bool autorelease = !!(handle->m_params.flags & Thread_AutoRelease);
|
||||||
|
handle->m_state = Thread_Running;
|
||||||
|
handle->GetThread()->RunThread(handle);
|
||||||
|
handle->m_state = Thread_Done;
|
||||||
|
handle->GetThread()->OnTerminate(handle, false);
|
||||||
|
if (autorelease)
|
||||||
|
delete handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::MakeThread(IThread *pThread)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = Thread_AutoRelease;
|
||||||
|
MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatWorker::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = flags;
|
||||||
|
return MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatWorker::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
ThreadParams def_params;
|
||||||
|
if (!params)
|
||||||
|
params = &def_params;
|
||||||
|
|
||||||
|
if (state_ <= Worker_Stopped)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
SWThreadHandle* handle = new SWThreadHandle(this, params, pThread);
|
||||||
|
work_.push_back(handle);
|
||||||
|
work_cv_.notify_one();
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||||
|
{
|
||||||
|
min = ThreadPrio_Normal;
|
||||||
|
max = ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::SetMaxThreadsPerFrame(unsigned int threads)
|
||||||
|
{
|
||||||
|
jobs_per_wakeup_ = threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatWorker::SetThinkTimePerFrame(unsigned int thinktime)
|
||||||
|
{
|
||||||
|
wait_between_jobs_ = thinktime;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerState CompatWorker::GetStatus(unsigned int *numThreads)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
// This number is meaningless and the status is racy.
|
||||||
|
if (numThreads)
|
||||||
|
*numThreads = jobs_per_wakeup_;
|
||||||
|
return state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompatThread final : public IThreadHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CompatThread(IThread* callbacks, const ThreadParams* params);
|
||||||
|
|
||||||
|
bool WaitForThread() override;
|
||||||
|
void DestroyThis() override;
|
||||||
|
IThreadCreator *Parent() override;
|
||||||
|
void GetParams(ThreadParams *ptparams) override;
|
||||||
|
ThreadPriority GetPriority() override;
|
||||||
|
bool SetPriority(ThreadPriority prio) override;
|
||||||
|
ThreadState GetState() override;
|
||||||
|
bool Unpause() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
IThread* callbacks_;
|
||||||
|
ThreadParams params_;
|
||||||
|
std::unique_ptr<std::thread> thread_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable check_cv_;
|
||||||
|
std::atomic<bool> finished_;
|
||||||
|
};
|
||||||
|
|
||||||
|
CompatThread::CompatThread(IThread* callbacks, const ThreadParams* params)
|
||||||
|
: callbacks_(callbacks),
|
||||||
|
params_(*params)
|
||||||
|
{
|
||||||
|
if (!(params_.flags & Thread_CreateSuspended))
|
||||||
|
Unpause();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatThread::Unpause()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
if (thread_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
thread_ = ke::NewThread("SM CompatThread", [this]() -> void {
|
||||||
|
Run();
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThread::Run()
|
||||||
|
{
|
||||||
|
// Create an ordering between when the thread runs and when thread_ is assigned.
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
callbacks_->RunThread(this);
|
||||||
|
finished_ = true;
|
||||||
|
callbacks_->OnTerminate(this, false);
|
||||||
|
|
||||||
|
if (params_.flags & Thread_AutoRelease) {
|
||||||
|
// There should be no handles outstanding, so it's safe to self-destruct.
|
||||||
|
thread_->detach();
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
|
callbacks_ = nullptr;
|
||||||
|
check_cv_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatThread::WaitForThread()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
for (;;) {
|
||||||
|
// When done, callbacks are unset. If paused, this will deadlock.
|
||||||
|
if (!callbacks_)
|
||||||
|
break;
|
||||||
|
check_cv_.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_->join();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadState CompatThread::GetState()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
if (!thread_)
|
||||||
|
return Thread_Paused;
|
||||||
|
return finished_ ? Thread_Done : Thread_Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThread::DestroyThis()
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPriority CompatThread::GetPriority()
|
||||||
|
{
|
||||||
|
return ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompatThread::SetPriority(ThreadPriority prio)
|
||||||
|
{
|
||||||
|
return prio == ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadCreator *CompatThread::Parent()
|
||||||
|
{
|
||||||
|
return g_pThreader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThread::GetParams(ThreadParams *ptparams)
|
||||||
|
{
|
||||||
|
*ptparams = params_;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompatMutex : public IMutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool TryLock() {
|
||||||
|
return mutex_.try_lock();
|
||||||
|
}
|
||||||
|
void Lock() {
|
||||||
|
mutex_.lock();
|
||||||
|
}
|
||||||
|
void Unlock() {
|
||||||
|
mutex_.unlock();
|
||||||
|
}
|
||||||
|
void DestroyThis() {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::mutex mutex_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompatThreader final : public IThreader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void MakeThread(IThread *pThread) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override;
|
||||||
|
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override;
|
||||||
|
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override;
|
||||||
|
IMutex *MakeMutex() override;
|
||||||
|
void ThreadSleep(unsigned int ms) override;
|
||||||
|
IEventSignal *MakeEventSignal() override;
|
||||||
|
IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) override;
|
||||||
|
void DestroyWorker(IThreadWorker *pWorker) override;
|
||||||
|
} sCompatThreader;
|
||||||
|
|
||||||
|
void CompatThreader::MakeThread(IThread *pThread)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = Thread_AutoRelease;
|
||||||
|
MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||||
|
{
|
||||||
|
ThreadParams params;
|
||||||
|
params.flags = flags;
|
||||||
|
return MakeThread(pThread, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadHandle *CompatThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||||
|
{
|
||||||
|
ThreadParams def_params;
|
||||||
|
if (!params)
|
||||||
|
params = &def_params;
|
||||||
|
|
||||||
|
return new CompatThread(pThread, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||||
|
{
|
||||||
|
min = ThreadPrio_Normal;
|
||||||
|
max = ThreadPrio_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMutex *CompatThreader::MakeMutex()
|
||||||
|
{
|
||||||
|
return new CompatMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThreader::ThreadSleep(unsigned int ms)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompatEventSignal final : public IEventSignal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Wait() override {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
cv_.wait(lock);
|
||||||
|
}
|
||||||
|
void Signal() override {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
cv_.notify_all();
|
||||||
|
}
|
||||||
|
void DestroyThis() override {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable cv_;
|
||||||
|
};
|
||||||
|
|
||||||
|
IEventSignal *CompatThreader::MakeEventSignal()
|
||||||
|
{
|
||||||
|
return new CompatEventSignal();
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreadWorker *CompatThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
|
||||||
|
{
|
||||||
|
if (!threaded)
|
||||||
|
return new BaseWorker(hooks);
|
||||||
|
return new CompatWorker(hooks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompatThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||||
|
{
|
||||||
|
delete pWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
IThreader *g_pThreader = &sCompatThreader;
|
||||||
|
|
||||||
class RegThreadStuff : public SMGlobalClass
|
class RegThreadStuff : public SMGlobalClass
|
||||||
{
|
{
|
||||||
|
|||||||
@ -32,49 +32,13 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <am-thread-utils.h>
|
|
||||||
#include <am-utility.h>
|
#include <am-utility.h>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
class CompatMutex : public IMutex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool TryLock() {
|
|
||||||
return mutex_.TryLock();
|
|
||||||
}
|
|
||||||
void Lock() {
|
|
||||||
mutex_.Lock();
|
|
||||||
}
|
|
||||||
void Unlock() {
|
|
||||||
mutex_.Unlock();
|
|
||||||
}
|
|
||||||
void DestroyThis() {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
ke::Mutex mutex_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CompatCondVar : public IEventSignal
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Wait() {
|
|
||||||
ke::AutoLock lock(&cv_);
|
|
||||||
cv_.Wait();
|
|
||||||
}
|
|
||||||
void Signal() {
|
|
||||||
ke::AutoLock lock(&cv_);
|
|
||||||
cv_.Notify();
|
|
||||||
}
|
|
||||||
void DestroyThis() {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
ke::ConditionVariable cv_;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern IThreader *g_pThreader;
|
extern IThreader *g_pThreader;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
#include "LibrarySys.h"
|
#include "LibrarySys.h"
|
||||||
#include "RootConsoleMenu.h"
|
#include "RootConsoleMenu.h"
|
||||||
#include "CellArray.h"
|
#include "CellArray.h"
|
||||||
|
#include "smn_entitylump.h"
|
||||||
#include <bridge/include/BridgeAPI.h>
|
#include <bridge/include/BridgeAPI.h>
|
||||||
#include <bridge/include/IProviderCallbacks.h>
|
#include <bridge/include/IProviderCallbacks.h>
|
||||||
|
|
||||||
@ -89,6 +90,8 @@ CNativeOwner g_CoreNatives;
|
|||||||
PseudoAddressManager pseudoAddr;
|
PseudoAddressManager pseudoAddr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
EntityLumpParseResult lastParseResult;
|
||||||
|
|
||||||
static void AddCorePhraseFile(const char *filename)
|
static void AddCorePhraseFile(const char *filename)
|
||||||
{
|
{
|
||||||
g_pCorePhrases->AddPhraseFile(filename);
|
g_pCorePhrases->AddPhraseFile(filename);
|
||||||
@ -135,6 +138,35 @@ static uint32_t ToPseudoAddress(void *addr)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetEntityLumpWritable(bool writable)
|
||||||
|
{
|
||||||
|
g_bLumpAvailableForWriting = writable;
|
||||||
|
|
||||||
|
// write-lock causes the map entities to be serialized out to string
|
||||||
|
if (!writable)
|
||||||
|
{
|
||||||
|
g_strMapEntities = lumpmanager->Dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseEntityLumpString(const char *pMapEntities, int &status, size_t &position)
|
||||||
|
{
|
||||||
|
lastParseResult = lumpmanager->Parse(pMapEntities);
|
||||||
|
status = static_cast<int>(lastParseResult.m_Status);
|
||||||
|
position = static_cast<size_t>(lastParseResult.m_Position);
|
||||||
|
return lastParseResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns nullptr if the original lump failed to parse
|
||||||
|
static const char* GetEntityLumpString()
|
||||||
|
{
|
||||||
|
if (!lastParseResult)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return g_strMapEntities.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
// Defined in smn_filesystem.cpp.
|
// Defined in smn_filesystem.cpp.
|
||||||
extern bool OnLogPrint(const char *msg);
|
extern bool OnLogPrint(const char *msg);
|
||||||
|
|
||||||
@ -170,6 +202,9 @@ static sm_logic_t logic =
|
|||||||
CellArray::Free,
|
CellArray::Free,
|
||||||
FromPseudoAddress,
|
FromPseudoAddress,
|
||||||
ToPseudoAddress,
|
ToPseudoAddress,
|
||||||
|
SetEntityLumpWritable,
|
||||||
|
ParseEntityLumpString,
|
||||||
|
GetEntityLumpString,
|
||||||
&g_PluginSys,
|
&g_PluginSys,
|
||||||
&g_ShareSys,
|
&g_ShareSys,
|
||||||
&g_Extensions,
|
&g_Extensions,
|
||||||
|
|||||||
@ -26,16 +26,17 @@
|
|||||||
// or <http://www.sourcemod.net/license.php>.
|
// or <http://www.sourcemod.net/license.php>.
|
||||||
#include "frame_tasks.h"
|
#include "frame_tasks.h"
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
|
|
||||||
ke::Vector<ke::Lambda<void()>> sNextTasks;
|
std::vector<ke::Function<void()>> sNextTasks;
|
||||||
ke::Vector<ke::Lambda<void()>> sWorkTasks;
|
std::vector<ke::Function<void()>> sWorkTasks;
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceMod::ScheduleTaskForNextFrame(ke::Lambda<void()>&& task)
|
SourceMod::ScheduleTaskForNextFrame(ke::Function<void()>&& task)
|
||||||
{
|
{
|
||||||
sNextTasks.append(ke::Forward<decltype(task)>(task));
|
sNextTasks.push_back(std::forward<decltype(task)>(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -45,11 +46,11 @@ SourceMod::RunScheduledFrameTasks(bool simulating)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Swap.
|
// Swap.
|
||||||
ke::Vector<ke::Lambda<void()>> temp(ke::Move(sNextTasks));
|
std::vector<ke::Function<void()>> temp(std::move(sNextTasks));
|
||||||
sNextTasks = ke::Move(sWorkTasks);
|
sNextTasks = std::move(sWorkTasks);
|
||||||
sWorkTasks = ke::Move(temp);
|
sWorkTasks = std::move(temp);
|
||||||
|
|
||||||
for (size_t i = 0; i < sWorkTasks.length(); i++)
|
for (size_t i = 0; i < sWorkTasks.size(); i++)
|
||||||
sWorkTasks[i]();
|
sWorkTasks[i]();
|
||||||
sWorkTasks.clear();
|
sWorkTasks.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,10 +31,10 @@
|
|||||||
|
|
||||||
namespace SourceMod {
|
namespace SourceMod {
|
||||||
|
|
||||||
void ScheduleTaskForNextFrame(ke::Lambda<void()>&& task);
|
void ScheduleTaskForNextFrame(ke::Function<void()>&& task);
|
||||||
|
|
||||||
void RunScheduledFrameTasks(bool simulating);
|
void RunScheduledFrameTasks(bool simulating);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _include_sourcemod_logic_frame_tasks_h_
|
#endif // _include_sourcemod_logic_frame_tasks_h_
|
||||||
|
|||||||
@ -89,6 +89,6 @@ unsigned int UTIL_CRC32(const void *pdata, size_t data_length)
|
|||||||
crc = CRCTable[c] ^ (crc >> 8);
|
crc = CRCTable[c] ^ (crc >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return crc;
|
return ~crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,11 @@ static cell_t CreateArray(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
if (params[2])
|
if (params[2])
|
||||||
{
|
{
|
||||||
array->resize(params[2]);
|
if (!array->resize(params[2]))
|
||||||
|
{
|
||||||
|
delete array;
|
||||||
|
return pContext->ThrowNativeError("Failed to resize array to startsize \"%u\".", params[2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
@ -277,7 +281,19 @@ static cell_t GetArrayString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *blk = array->at(idx);
|
// the blocknumber is not guaranteed to always be passed
|
||||||
|
size_t blocknumber = 0;
|
||||||
|
if (params[0] >= 5)
|
||||||
|
{
|
||||||
|
blocknumber = (size_t)params[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocknumber >= array->blocksize())
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||||
size_t numWritten = 0;
|
size_t numWritten = 0;
|
||||||
|
|
||||||
pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
|
pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
|
||||||
@ -303,7 +319,19 @@ static cell_t GetArrayArray(IPluginContext *pContext, const cell_t *params)
|
|||||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *blk = array->at(idx);
|
// the blocknumber is not guaranteed to always be passed
|
||||||
|
size_t blocknumber = 0;
|
||||||
|
if (params[0] >= 5)
|
||||||
|
{
|
||||||
|
blocknumber = (size_t)params[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocknumber >= array->blocksize())
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||||
size_t indexes = array->blocksize();
|
size_t indexes = array->blocksize();
|
||||||
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
||||||
{
|
{
|
||||||
@ -375,12 +403,30 @@ static cell_t SetArrayString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *blk = array->at(idx);
|
// the blocknumber is not guaranteed to always be passed
|
||||||
|
size_t blocknumber = 0;
|
||||||
|
if (params[0] >= 5)
|
||||||
|
{
|
||||||
|
blocknumber = (size_t)params[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocknumber >= array->blocksize())
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||||
|
|
||||||
char *str;
|
char *str;
|
||||||
pContext->LocalToString(params[3], &str);
|
pContext->LocalToString(params[3], &str);
|
||||||
|
|
||||||
return strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
|
size_t maxlength = array->blocksize() * sizeof(cell_t);
|
||||||
|
if (params[0] >= 4 && params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
||||||
|
{
|
||||||
|
maxlength = (size_t)params[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
return strncopy((char*)blk, str, maxlength);
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
|
static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
|
||||||
@ -401,7 +447,19 @@ static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
|
|||||||
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *blk = array->at(idx);
|
// the blocknumber is not guaranteed to always be passed
|
||||||
|
size_t blocknumber = 0;
|
||||||
|
if (params[0] >= 5)
|
||||||
|
{
|
||||||
|
blocknumber = (size_t)params[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocknumber >= array->blocksize())
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
|
||||||
size_t indexes = array->blocksize();
|
size_t indexes = array->blocksize();
|
||||||
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
|
||||||
{
|
{
|
||||||
@ -529,12 +587,24 @@ static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
|
|||||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the blocknumber is not guaranteed to always be passed
|
||||||
|
size_t blocknumber = 0;
|
||||||
|
if (params[0] >= 3)
|
||||||
|
{
|
||||||
|
blocknumber = (size_t)params[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocknumber >= array->blocksize())
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
|
||||||
|
}
|
||||||
|
|
||||||
char *str;
|
char *str;
|
||||||
pContext->LocalToString(params[2], &str);
|
pContext->LocalToString(params[2], &str);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < array->size(); i++)
|
for (unsigned int i = 0; i < array->size(); i++)
|
||||||
{
|
{
|
||||||
const char *array_str = (const char *)array->at(i);
|
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
|
||||||
if (strcmp(str, array_str) == 0)
|
if (strcmp(str, array_str) == 0)
|
||||||
{
|
{
|
||||||
return (cell_t) i;
|
return (cell_t) i;
|
||||||
|
|||||||
@ -83,6 +83,48 @@ static cell_t CreateStack(IPluginContext *pContext, const cell_t *params)
|
|||||||
return hndl;
|
return hndl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t ClearStack(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
CellArray *array;
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
array->clear();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t CloneStack(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
CellArray *oldArray;
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&oldArray)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ICellArray *array = oldArray->clone();
|
||||||
|
if (!array)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Failed to clone stack. Out of memory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle_t hndl = handlesys->CreateHandle(htCellStack, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
if (!hndl)
|
||||||
|
{
|
||||||
|
delete array;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t PushStackCell(IPluginContext *pContext, const cell_t *params)
|
static cell_t PushStackCell(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
CellArray *array;
|
CellArray *array;
|
||||||
@ -198,9 +240,9 @@ static cell_t PopStackCell(IPluginContext *pContext, const cell_t *params)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (idx >= array->blocksize() * 4)
|
if (idx >= array->blocksize() * sizeof(cell_t))
|
||||||
{
|
{
|
||||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
|
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
|
||||||
}
|
}
|
||||||
*buffer = (cell_t)*((char *)blk + idx);
|
*buffer = (cell_t)*((char *)blk + idx);
|
||||||
}
|
}
|
||||||
@ -314,8 +356,8 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
|
|||||||
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
|
||||||
rval = blk[idx];
|
rval = blk[idx];
|
||||||
} else {
|
} else {
|
||||||
if (idx >= array->blocksize() * 4)
|
if (idx >= array->blocksize() * sizeof(cell_t))
|
||||||
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
|
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
|
||||||
rval = (cell_t)*((char *)blk + idx);
|
rval = (cell_t)*((char *)blk + idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,6 +365,32 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t ArrayStack_Top(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||||
|
if (!array.Ok())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (array->size() == 0)
|
||||||
|
return pContext->ThrowNativeError("stack is empty");
|
||||||
|
|
||||||
|
cell_t *blk = array->at(array->size() - 1);
|
||||||
|
size_t idx = (size_t)params[2];
|
||||||
|
|
||||||
|
cell_t rval;
|
||||||
|
if (params[3] == 0) {
|
||||||
|
if (idx >= array->blocksize())
|
||||||
|
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
|
||||||
|
rval = blk[idx];
|
||||||
|
} else {
|
||||||
|
if (idx >= array->blocksize() * sizeof(cell_t))
|
||||||
|
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
|
||||||
|
rval = (cell_t)*((char *)blk + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params)
|
static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||||
@ -345,6 +413,27 @@ static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *param
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t ArrayStack_TopString(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||||
|
if (!array.Ok())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (array->size() == 0)
|
||||||
|
return pContext->ThrowNativeError("stack is empty");
|
||||||
|
|
||||||
|
size_t idx = array->size() - 1;
|
||||||
|
cell_t *blk = array->at(idx);
|
||||||
|
|
||||||
|
cell_t *pWritten;
|
||||||
|
pContext->LocalToPhysAddr(params[4], &pWritten);
|
||||||
|
|
||||||
|
size_t numWritten;
|
||||||
|
pContext->StringToLocalUTF8(params[2], params[3], (char *)blk, &numWritten);
|
||||||
|
*pWritten = (cell_t)numWritten;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params)
|
static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||||
@ -369,6 +458,29 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t ArrayStack_TopArray(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
|
||||||
|
if (!array.Ok())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (array->size() == 0)
|
||||||
|
return pContext->ThrowNativeError("stack is empty");
|
||||||
|
|
||||||
|
cell_t *addr;
|
||||||
|
pContext->LocalToPhysAddr(params[2], &addr);
|
||||||
|
|
||||||
|
size_t idx = array->size() - 1;
|
||||||
|
cell_t *blk = array->at(idx);
|
||||||
|
size_t indexes = array->blocksize();
|
||||||
|
|
||||||
|
if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
|
||||||
|
indexes = params[3];
|
||||||
|
|
||||||
|
memcpy(addr, blk, sizeof(cell_t) * indexes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
|
static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
HandleError err;
|
HandleError err;
|
||||||
@ -384,9 +496,25 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
|
|||||||
return array->blocksize();
|
return array->blocksize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t GetStackSize(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError err;
|
||||||
|
CellArray *array;
|
||||||
|
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array->size();
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(cellStackNatives)
|
REGISTER_NATIVES(cellStackNatives)
|
||||||
{
|
{
|
||||||
{"CreateStack", CreateStack},
|
{"CreateStack", CreateStack},
|
||||||
|
{"CloneStack", CloneStack},
|
||||||
{"IsStackEmpty", IsStackEmpty},
|
{"IsStackEmpty", IsStackEmpty},
|
||||||
{"PopStackArray", PopStackArray},
|
{"PopStackArray", PopStackArray},
|
||||||
{"PopStackCell", PopStackCell},
|
{"PopStackCell", PopStackCell},
|
||||||
@ -398,14 +526,20 @@ REGISTER_NATIVES(cellStackNatives)
|
|||||||
|
|
||||||
// Transitional syntax support.
|
// Transitional syntax support.
|
||||||
{"ArrayStack.ArrayStack", CreateStack},
|
{"ArrayStack.ArrayStack", CreateStack},
|
||||||
|
{"ArrayStack.Clear", ClearStack},
|
||||||
|
{"ArrayStack.Clone", CloneStack},
|
||||||
{"ArrayStack.Pop", ArrayStack_Pop},
|
{"ArrayStack.Pop", ArrayStack_Pop},
|
||||||
|
{"ArrayStack.Top", ArrayStack_Top},
|
||||||
{"ArrayStack.PopString", ArrayStack_PopString},
|
{"ArrayStack.PopString", ArrayStack_PopString},
|
||||||
|
{"ArrayStack.TopString", ArrayStack_TopString},
|
||||||
{"ArrayStack.PopArray", ArrayStack_PopArray},
|
{"ArrayStack.PopArray", ArrayStack_PopArray},
|
||||||
|
{"ArrayStack.TopArray", ArrayStack_TopArray},
|
||||||
{"ArrayStack.Push", PushStackCell},
|
{"ArrayStack.Push", PushStackCell},
|
||||||
{"ArrayStack.PushString", PushStackString},
|
{"ArrayStack.PushString", PushStackString},
|
||||||
{"ArrayStack.PushArray", PushStackArray},
|
{"ArrayStack.PushArray", PushStackArray},
|
||||||
{"ArrayStack.Empty.get", IsStackEmpty},
|
{"ArrayStack.Empty.get", IsStackEmpty},
|
||||||
{"ArrayStack.BlockSize.get", GetStackBlockSize},
|
{"ArrayStack.BlockSize.get", GetStackBlockSize},
|
||||||
|
{"ArrayStack.Length.get", GetStackSize},
|
||||||
|
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,9 +30,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
#include <am-autoptr.h>
|
|
||||||
#include <am-moveable.h>
|
|
||||||
#include <am-refcounting.h>
|
#include <am-refcounting.h>
|
||||||
#include <sm_stringhashmap.h>
|
#include <sm_stringhashmap.h>
|
||||||
#include "sm_memtable.h"
|
#include "sm_memtable.h"
|
||||||
@ -103,7 +104,7 @@ public:
|
|||||||
assert(isArray());
|
assert(isArray());
|
||||||
return reinterpret_cast<cell_t *>(raw()->base());
|
return reinterpret_cast<cell_t *>(raw()->base());
|
||||||
}
|
}
|
||||||
char *chars() const {
|
char *c_str() const {
|
||||||
assert(isString());
|
assert(isString());
|
||||||
return reinterpret_cast<char *>(raw()->base());
|
return reinterpret_cast<char *>(raw()->base());
|
||||||
}
|
}
|
||||||
@ -182,7 +183,7 @@ struct TrieSnapshot
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t length;
|
size_t length;
|
||||||
ke::AutoPtr<int[]> keys;
|
std::unique_ptr<int[]> keys;
|
||||||
BaseStringTable strings;
|
BaseStringTable strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -349,6 +350,27 @@ static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
CellTrie *pTrie;
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
Handle_t hndl = params[1];
|
||||||
|
|
||||||
|
if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key;
|
||||||
|
pContext->LocalToString(params[2], &key);
|
||||||
|
|
||||||
|
StringHashMap<Entry>::Result r = pTrie->map.find(key);
|
||||||
|
|
||||||
|
return r.found() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
CellTrie *pTrie;
|
CellTrie *pTrie;
|
||||||
@ -517,7 +539,7 @@ static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
size_t written;
|
size_t written;
|
||||||
pContext->StringToLocalUTF8(params[3], params[4], r->value.chars(), &written);
|
pContext->StringToLocalUTF8(params[3], params[4], r->value.c_str(), &written);
|
||||||
|
|
||||||
*pSize = (cell_t)written;
|
*pSize = (cell_t)written;
|
||||||
return 1;
|
return 1;
|
||||||
@ -557,10 +579,10 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
TrieSnapshot *snapshot = new TrieSnapshot;
|
TrieSnapshot *snapshot = new TrieSnapshot;
|
||||||
snapshot->length = pTrie->map.elements();
|
snapshot->length = pTrie->map.elements();
|
||||||
snapshot->keys = ke::MakeUnique<int[]>(snapshot->length);
|
snapshot->keys = std::make_unique<int[]>(snapshot->length);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
|
for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
|
||||||
snapshot->keys[i] = snapshot->strings.AddString(iter->key.chars(), iter->key.length());
|
snapshot->keys[i] = snapshot->strings.AddString(iter->key.c_str(), iter->key.length());
|
||||||
assert(i == snapshot->length);
|
assert(i == snapshot->length);
|
||||||
|
|
||||||
if ((hndl = handlesys->CreateHandle(htSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
|
if ((hndl = handlesys->CreateHandle(htSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
|
||||||
@ -635,6 +657,56 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
|
|||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
HandleError err;
|
||||||
|
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
|
||||||
|
|
||||||
|
CellTrie *pOldTrie;
|
||||||
|
if ((err = handlesys->ReadHandle(params[1], htCellTrie, &sec, (void **)&pOldTrie))
|
||||||
|
!= HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
CellTrie *pNewTrie = new CellTrie;
|
||||||
|
Handle_t hndl = handlesys->CreateHandle(htCellTrie, pNewTrie, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
if (!hndl)
|
||||||
|
{
|
||||||
|
delete pNewTrie;
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (StringHashMap<Entry>::iterator it = pOldTrie->map.iter(); !it.empty(); it.next())
|
||||||
|
{
|
||||||
|
const char *key = it->key.c_str();
|
||||||
|
StringHashMap<Entry>::Insert insert = pNewTrie->map.findForAdd(key);
|
||||||
|
if (pNewTrie->map.add(insert, key))
|
||||||
|
{
|
||||||
|
StringHashMap<Entry>::Result result = pOldTrie->map.find(key);
|
||||||
|
if (result->value.isCell())
|
||||||
|
{
|
||||||
|
insert->value.setCell(result->value.cell());
|
||||||
|
}
|
||||||
|
else if (result->value.isString())
|
||||||
|
{
|
||||||
|
insert->value.setString(result->value.c_str());
|
||||||
|
}
|
||||||
|
else if (result->value.isArray())
|
||||||
|
{
|
||||||
|
insert->value.setArray(result->value.array(), result->value.arrayLength());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlesys->FreeHandle(hndl, NULL);
|
||||||
|
return pContext->ThrowNativeError("Unhandled data type encountered, file a bug and reference pr #852");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hndl;
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(trieNatives)
|
REGISTER_NATIVES(trieNatives)
|
||||||
{
|
{
|
||||||
{"ClearTrie", ClearTrie},
|
{"ClearTrie", ClearTrie},
|
||||||
@ -659,12 +731,14 @@ REGISTER_NATIVES(trieNatives)
|
|||||||
{"StringMap.GetArray", GetTrieArray},
|
{"StringMap.GetArray", GetTrieArray},
|
||||||
{"StringMap.GetString", GetTrieString},
|
{"StringMap.GetString", GetTrieString},
|
||||||
{"StringMap.GetValue", GetTrieValue},
|
{"StringMap.GetValue", GetTrieValue},
|
||||||
|
{"StringMap.ContainsKey", ContainsKeyInTrie},
|
||||||
{"StringMap.Remove", RemoveFromTrie},
|
{"StringMap.Remove", RemoveFromTrie},
|
||||||
{"StringMap.SetArray", SetTrieArray},
|
{"StringMap.SetArray", SetTrieArray},
|
||||||
{"StringMap.SetString", SetTrieString},
|
{"StringMap.SetString", SetTrieString},
|
||||||
{"StringMap.SetValue", SetTrieValue},
|
{"StringMap.SetValue", SetTrieValue},
|
||||||
{"StringMap.Size.get", GetTrieSize},
|
{"StringMap.Size.get", GetTrieSize},
|
||||||
{"StringMap.Snapshot", CreateTrieSnapshot},
|
{"StringMap.Snapshot", CreateTrieSnapshot},
|
||||||
|
{"StringMap.Clone", CloneTrie},
|
||||||
|
|
||||||
{"StringMapSnapshot.Length.get", TrieSnapshotLength},
|
{"StringMapSnapshot.Length.get", TrieSnapshotLength},
|
||||||
{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize},
|
{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize},
|
||||||
|
|||||||
@ -127,6 +127,8 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_pSM->SetGlobalTarget(index);
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
char *fmt;
|
char *fmt;
|
||||||
int arg = 3;
|
int arg = 3;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user