mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-19 03:36:56 -06:00
Compare commits
856 Commits
v1.0
...
visual-deb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4adba09b4 | ||
|
|
fc0961ed76 | ||
|
|
b28b93b3f0 | ||
|
|
f3ace4e7ed | ||
| 14d4bf3cc5 | |||
| 26f2eb409f | |||
| 1af3e59348 | |||
|
|
e3077aa410 | ||
| 3b75ecc0b4 | |||
| b70e7334e8 | |||
| 500b7885e2 | |||
|
|
bc132487e9 | ||
| 47f0830483 | |||
| e707207ffa | |||
|
|
ceb374591f | ||
|
|
c05562a227 | ||
| f8c1e2fb52 | |||
| e4a15a0f2e | |||
|
|
dd8091f60e | ||
|
|
50b3946548 | ||
| 976bd3c41b | |||
|
|
3b7f1dad54 | ||
|
|
54021458bd | ||
|
|
1e1b6aaa0b | ||
|
|
008f953003 | ||
|
|
dc960cb99c | ||
| 2d0faae759 | |||
| 932d8030f0 | |||
|
|
7f5ab8b9fa | ||
|
|
6c97ea8208 | ||
| 72477e01e2 | |||
|
|
ea86988521 | ||
| d626ac1ed4 | |||
| 168f837b94 | |||
| 9e4ce24fd2 | |||
|
|
4112a85906 | ||
|
|
408163ed35 | ||
|
|
4556f13474 | ||
|
|
88f316bf93 | ||
|
|
e6c7f744b5 | ||
|
|
d2b05a1ac5 | ||
|
|
a429489846 | ||
|
|
9ee219ea42 | ||
| a0aa8b2854 | |||
|
|
c11a4a67d1 | ||
|
|
c69d01d77b | ||
|
|
50cb9346b8 | ||
|
|
17d77db1c6 | ||
|
|
e97dc6fbff | ||
|
|
7ec458421f | ||
| 0b9e97625e | |||
|
|
d64fa1680d | ||
|
|
f80a26a944 | ||
|
|
26ddeaa429 | ||
| 8b386ae6c5 | |||
| f284e5a6e1 | |||
| 1b01abd7d9 | |||
| 0e46b875a5 | |||
| 19e77a38d8 | |||
|
|
adb6a2c609 | ||
| 4f7aa11067 | |||
|
|
ffd4477081 | ||
| a632ef8ccd | |||
|
|
9e08bb20d2 | ||
|
|
9813c3ed2c | ||
| e97ae92624 | |||
| a7fb6eb3f3 | |||
| 9ed4a4f47f | |||
| b57cacc676 | |||
| f2d1c5d26d | |||
|
|
ef0a3c6d0b | ||
|
|
6a38b67ed5 | ||
| 5523b6aafc | |||
|
|
40a9aefb5b | ||
|
|
91f2cebcc7 | ||
|
|
45a7dbdadd | ||
|
|
74bca38253 | ||
|
|
082a2a418f | ||
|
|
835cf2b794 | ||
|
|
74343be871 | ||
|
|
ed5ced0bed | ||
| 3dfe363a6b | |||
|
|
8e5da2cf1f | ||
|
|
ec4ed8fa7e | ||
|
|
b55606d41e | ||
|
|
69a0d5a50b | ||
|
|
945e572493 | ||
| ef8c2a40f3 | |||
|
|
fab8a1e982 | ||
|
|
0d4f86b20b | ||
|
|
c689b3d3d1 | ||
|
|
77d35019cc | ||
| 9287e5bc4b | |||
|
|
f5ae5aa13e | ||
|
|
df0f11c95b | ||
|
|
9c0819de4f | ||
|
|
3d46d703b2 | ||
|
|
9ba297dd2e | ||
|
|
ccb9f7c499 | ||
|
|
24dbd3944d | ||
|
|
5888c9f468 | ||
|
|
c9cd7a200a | ||
|
|
b7497a47e4 | ||
|
|
bfa1f57158 | ||
|
|
d642de9462 | ||
|
|
06217ad5e3 | ||
|
|
325dc5a571 | ||
|
|
66edf57b02 | ||
|
|
485de6173a | ||
| dddc33607b | |||
| 3865a186a7 | |||
|
|
22b2516107 | ||
|
|
0734760d42 | ||
|
|
138fffda2c | ||
|
|
de5d9182eb | ||
|
|
3cf243b1d7 | ||
|
|
8cdb388915 | ||
|
|
cc25ec0151 | ||
|
|
8a54e7ccd2 | ||
|
|
6e2936504c | ||
|
|
eaa962f265 | ||
| 1497d9b35a | |||
|
|
a55162775e | ||
|
|
670a2de95b | ||
| 94e161df55 | |||
|
|
06dc18fb49 | ||
|
|
00f7a5c4d6 | ||
| 5dd4086bd5 | |||
| 1b222a64c3 | |||
|
|
6a7c6da01a | ||
|
|
9bfff533c3 | ||
|
|
8e9c48cce0 | ||
|
|
fb81c0c9a2 | ||
|
|
c0d05b00df | ||
|
|
ef0873075f | ||
|
|
c89f420204 | ||
|
|
ea94de16cd | ||
|
|
c5f2f4b708 | ||
|
|
cb6d91cfb2 | ||
|
|
e24ad43dc5 | ||
|
|
09d50faf79 | ||
|
|
6b30292efd | ||
|
|
5f34b7150a | ||
|
|
43377caa3b | ||
| 29199f4755 | |||
|
|
f4b89a8925 | ||
|
|
968114199b | ||
|
|
c871aeef56 | ||
|
|
9cf534dc0a | ||
|
|
de47210f15 | ||
|
|
ba5037300f | ||
|
|
2e224cb151 | ||
|
|
2a0616d0e9 | ||
|
|
0774ab930d | ||
|
|
e415d96a9d | ||
|
|
35ea3d35ae | ||
|
|
e28b084395 | ||
|
|
136937184e | ||
|
|
2403a7fe45 | ||
|
|
531c4a594c | ||
|
|
1fe6c32933 | ||
|
|
4a39221dd0 | ||
|
|
09c459a083 | ||
|
|
7dfcd22a2e | ||
|
|
8bdd5b6e2c | ||
|
|
4556faf833 | ||
|
|
1179f5a2fe | ||
|
|
a61c6e5e41 | ||
|
|
1f62f169c8 | ||
|
|
842cb80137 | ||
|
|
2868465e89 | ||
|
|
ef8ea13d99 | ||
|
|
df9f9f08b6 | ||
|
|
50fd27b973 | ||
|
|
81431cfcbd | ||
|
|
7af248feeb | ||
|
|
fbf0b59ff1 | ||
|
|
c5dff54e01 | ||
|
|
30c8326c3e | ||
|
|
d8cde40b49 | ||
|
|
db773e9778 | ||
|
|
33cc3a3dd9 | ||
| 66215da37a | |||
|
|
73bbe641c6 | ||
| c6f871d42b | |||
|
|
445c01d485 | ||
|
|
915b779f03 | ||
|
|
731c25741c | ||
|
|
f8d73ccbc5 | ||
|
|
f5caa1f00d | ||
|
|
769f789a43 | ||
| e3422ac0c5 | |||
|
|
cdb2cf0344 | ||
|
|
44e17eabca | ||
| 06df15717c | |||
| 813aca9d20 | |||
|
|
a363d0734c | ||
|
|
667677dcdd | ||
| 9169d844e2 | |||
| 03a5aa4da0 | |||
| 729e79eadb | |||
| ca55fccb27 | |||
| 81af1f382e | |||
|
|
cc23538244 | ||
| 20b45bc27f | |||
|
|
85cd8c8833 | ||
|
|
d6aece44aa | ||
| aba349301f | |||
| 875827d688 | |||
| d7eb8783a8 | |||
|
|
d39df2e5a1 | ||
| 4c7034648b | |||
| ec207838d4 | |||
|
|
24745c2e7a | ||
|
|
8601976498 | ||
|
|
ca042bd415 | ||
| 06a1949eaa | |||
| b11b516641 | |||
| ad5c679d2d | |||
| e81acb4c67 | |||
| aa212ae6d8 | |||
| bd3e8aee51 | |||
|
|
a1a345326a | ||
|
|
6b409303af | ||
|
|
427c4a8c33 | ||
| 763a1f4a61 | |||
|
|
12ae6a5525 | ||
|
|
2435870ec5 | ||
|
|
59be7d8635 | ||
|
|
bbedf5d174 | ||
|
|
2f598dad09 | ||
|
|
16b108f69c | ||
|
|
94c00417ff | ||
|
|
b713b94841 | ||
|
|
843a5b39c0 | ||
|
|
fa7c4d9c27 | ||
|
|
cacf4fcd97 | ||
|
|
5afeb265cd | ||
|
|
aca2bb1090 | ||
|
|
2bd90ce353 | ||
|
|
27edf5da1d | ||
|
|
7d233a04c0 | ||
|
|
c2c8cf9767 | ||
|
|
4117ceb6c1 | ||
|
|
58d2cee984 | ||
|
|
4fd1467cbf | ||
|
|
7b32d2f609 | ||
|
|
2e29dce77c | ||
|
|
e56732184f | ||
|
|
dc770299d1 | ||
|
|
18fc01cd49 | ||
|
|
c6480192f8 | ||
|
|
7a051afd97 | ||
|
|
ceab229a63 | ||
|
|
8e10f090fd | ||
|
|
a4d934913c | ||
|
|
0eece14b68 | ||
|
|
d0233a2cd0 | ||
|
|
834b53b4ec | ||
|
|
2e61839d93 | ||
|
|
e85cf466d4 | ||
| d42cbb2473 | |||
| d4adb0e6e5 | |||
| 4cf9865431 | |||
|
|
6f9caaa8c1 | ||
|
|
c489132f59 | ||
| c845055e6b | |||
|
|
a3331d009d | ||
|
|
80a09881c0 | ||
| 263b019262 | |||
| 6933b2c301 | |||
| 8db7dfef75 | |||
| f3dd71ccb1 | |||
| 8fe5c00984 | |||
| d05601ce64 | |||
|
|
1defc22caf | ||
|
|
5691df9009 | ||
| 2122448284 | |||
| 263eaf03b0 | |||
| 6cef7a437a | |||
| 0778b4f81c | |||
| 235934714f | |||
| a343ed9493 | |||
| cc68b0768b | |||
| e696d26941 | |||
| a8fcb4c153 | |||
| 1e85ae2035 | |||
| 67615d5688 | |||
| 23677b4bd3 | |||
| 5b0f917485 | |||
| b3695c42b2 | |||
| 0e5a1c9721 | |||
| b4acf329b4 | |||
|
|
8f50e4ff56 | ||
|
|
a3e2aa2a97 | ||
| 3d6d5e58a7 | |||
| cdbb42badf | |||
| 1d1f479387 | |||
|
|
a32c5a2f3c | ||
| 59ec28a5a4 | |||
| 959c90985c | |||
| 4a98c46fb9 | |||
| 40d396c7e2 | |||
| 6b44936c68 | |||
|
|
e92cdc4f14 | ||
|
|
0f738c8d9c | ||
|
|
7a354b3545 | ||
|
|
f45cb380e0 | ||
|
|
f01c2e1bd3 | ||
|
|
30c7b65150 | ||
|
|
1e514a8b61 | ||
|
|
c08557f37d | ||
|
|
6927bc614e | ||
|
|
ae61b23896 | ||
|
|
aee3290248 | ||
|
|
1efbe2d2c0 | ||
|
|
d085c0cf10 | ||
|
|
3e60b9db4a | ||
|
|
fd13770e87 | ||
|
|
5ef1848474 | ||
|
|
77c6350f03 | ||
|
|
f17e6d6a4a | ||
|
|
53823a0be5 | ||
|
|
3900267fed | ||
|
|
0a494422b7 | ||
|
|
96f1c0a709 | ||
|
|
39089284ff | ||
|
|
5a76cb3b44 | ||
|
|
92d36496df | ||
|
|
9b6caef6b5 | ||
|
|
7030d937b1 | ||
|
|
e73793c1a3 | ||
|
|
5eb801eb12 | ||
|
|
4b0ab2380c | ||
|
|
bd0926e0a5 | ||
|
|
9d79fc3d2e | ||
|
|
a0a9936e47 | ||
|
|
5e5fefb501 | ||
|
|
395d607632 | ||
|
|
db0f363967 | ||
|
|
ec463dd4c8 | ||
|
|
acbd46afcb | ||
|
|
8379fba079 | ||
|
|
4bc5c8194f | ||
|
|
ba33c15b2d | ||
|
|
0bf2d398ea | ||
|
|
ece83db6ed | ||
|
|
8ae7bc0f92 | ||
|
|
ccff6746ce | ||
|
|
450bebc8a2 | ||
|
|
cf70881370 | ||
|
|
4724e0ebc1 | ||
|
|
95010e791f | ||
|
|
33b16a56e3 | ||
|
|
cc9b6c05f6 | ||
|
|
9169acad47 | ||
|
|
aed0ecc9fc | ||
|
|
0561f60031 | ||
|
|
e66421d34f | ||
|
|
8462068a05 | ||
|
|
8a8b5b4f44 | ||
|
|
bc7c543530 | ||
|
|
f22dab0f72 | ||
|
|
002025231e | ||
|
|
061d2b394c | ||
|
|
d3f954bdac | ||
|
|
c80a90e81e | ||
|
|
b903c81a0a | ||
|
|
f72c2dcaa5 | ||
|
|
6b759ff54e | ||
|
|
041dc8256f | ||
|
|
b79ebf1d40 | ||
|
|
0bf2f0e92a | ||
|
|
04852ac1d9 | ||
|
|
5fa0a16302 | ||
|
|
4edb428954 | ||
|
|
ff9d736073 | ||
|
|
b2890262fb | ||
|
|
0a6b8f139e | ||
|
|
529b40b66c | ||
|
|
2a2fa94b03 | ||
|
|
58c6429209 | ||
|
|
5c16dd11f4 | ||
|
|
bd6bdddcde | ||
|
|
fe334d8739 | ||
|
|
69cc265fea | ||
|
|
17e9fb0d3c | ||
|
|
b676343b02 | ||
|
|
c838f4f422 | ||
|
|
e244fbccc2 | ||
|
|
36edbf393b | ||
|
|
258174d4e1 | ||
|
|
fdd3e15b2f | ||
|
|
94e0ef77a9 | ||
|
|
06671b8d66 | ||
|
|
1783904cb6 | ||
|
|
9f16284595 | ||
|
|
af15cc60eb | ||
|
|
e79d4e66f3 | ||
|
|
82ebdccdb2 | ||
| 75fd425ef6 | |||
|
|
ec9749ab85 | ||
|
|
9385c33729 | ||
|
|
7b536ee079 | ||
|
|
0c41026df0 | ||
|
|
b0d4993344 | ||
|
|
35e576a839 | ||
|
|
69ec1216dc | ||
|
|
19e82a5150 | ||
|
|
965d4c7af0 | ||
|
|
17b0de8062 | ||
|
|
895bbec277 | ||
|
|
17f773c6cb | ||
|
|
dc74b46e11 | ||
|
|
148c177d27 | ||
|
|
c94f0918c9 | ||
|
|
54de6c6878 | ||
|
|
acb7ad78e8 | ||
|
|
0a453e9dca | ||
|
|
0a7fd6f79a | ||
|
|
a7cd2f4d9b | ||
|
|
e43517efe6 | ||
|
|
b459790b2f | ||
|
|
66b7c6522e | ||
|
|
3a959778fe | ||
|
|
db3cd33bca | ||
|
|
6499139a49 | ||
|
|
f83ad8bbe4 | ||
|
|
819c58df7c | ||
|
|
4e2c352ab9 | ||
|
|
b2c88bb6a7 | ||
|
|
e2bfdcd174 | ||
|
|
22a00de8cd | ||
|
|
68c600facc | ||
|
|
a49f9dc586 | ||
|
|
6be274b259 | ||
|
|
24d443537a | ||
|
|
3d1283675f | ||
|
|
ad52facef7 | ||
|
|
55def02c8f | ||
|
|
6905120ac6 | ||
|
|
5ffb57d92c | ||
|
|
87d3ac15bd | ||
|
|
1c116fb0c4 | ||
|
|
1c43d7f38c | ||
|
|
78fbe3c7fe | ||
|
|
4ef5508347 | ||
|
|
afa38ae890 | ||
|
|
352f654ede | ||
|
|
2bc9f8f66d | ||
|
|
5fbb1e9cc2 | ||
|
|
7c80c12b90 | ||
|
|
9021c5209f | ||
|
|
6c5c6b7b8e | ||
|
|
a60738f78f | ||
|
|
b077bd937d | ||
|
|
1607b506c8 | ||
|
|
42f6f2f10b | ||
|
|
788cd3f807 | ||
|
|
d5a18af0e8 | ||
|
|
cabd220a66 | ||
|
|
e397ed310e | ||
|
|
1122f50c7c | ||
|
|
d9874b452e | ||
|
|
0253a1fcb4 | ||
|
|
a22e1bd53d | ||
|
|
56765d355b | ||
|
|
417a1a7485 | ||
|
|
204f03fd2a | ||
|
|
b297d21a8d | ||
|
|
f41e8292e8 | ||
|
|
3de2c3bfc6 | ||
|
|
a6ed435038 | ||
|
|
679f077772 | ||
|
|
9cfb9a0de6 | ||
|
|
56521d35d0 | ||
|
|
72b3812716 | ||
|
|
b7d7146821 | ||
|
|
6ac90f98d1 | ||
|
|
42e20d6db5 | ||
|
|
b8c1f7629e | ||
|
|
448e888d69 | ||
|
|
ae6980966d | ||
|
|
579cf590b4 | ||
|
|
f7009b499b | ||
|
|
84cf79906b | ||
|
|
933cdee414 | ||
|
|
77459af1d3 | ||
|
|
828c457614 | ||
|
|
6ba9eea993 | ||
|
|
fe178bf745 | ||
|
|
c6f220ee31 | ||
|
|
dc2bd76aba | ||
|
|
f0a4324bd4 | ||
|
|
0d0949f5f0 | ||
|
|
13980c4133 | ||
|
|
dac8ec621c | ||
| 026654b0d0 | |||
|
|
59afc63a2f | ||
|
|
344af924fe | ||
|
|
676611ed6f | ||
|
|
4cd38f1174 | ||
|
|
910448b0e7 | ||
|
|
477b629faf | ||
| f6558aa31e | |||
|
|
4f1df372a2 | ||
|
|
1e01423a93 | ||
|
|
20037d12f7 | ||
|
|
f605451693 | ||
|
|
fa747a27db | ||
|
|
02bf5937dc | ||
|
|
ef194f8796 | ||
|
|
20789bab7f | ||
|
|
e248b74ee6 | ||
|
|
e11260a2fe | ||
|
|
24f8ea21db | ||
|
|
6fc0683ce9 | ||
|
|
15831e8d6c | ||
|
|
2a5f3b8072 | ||
|
|
850ae40f05 | ||
|
|
3bb1491f09 | ||
|
|
a9389fcabf | ||
|
|
7cf458cff2 | ||
|
|
2bfff2933a | ||
|
|
46f375a58e | ||
|
|
097af41392 | ||
|
|
67d5061416 | ||
|
|
d69a4ffaf0 | ||
|
|
84a376b425 | ||
|
|
179d44fdd3 | ||
|
|
2f2e670ef3 | ||
|
|
01ed5106b9 | ||
|
|
60ba78d639 | ||
|
|
3ede7006f9 | ||
|
|
df77997b0b | ||
|
|
7dd7fdaf71 | ||
|
|
789c0890ca | ||
|
|
d883536ebd | ||
|
|
fa714aa843 | ||
|
|
9dfa401b27 | ||
|
|
4ff84e0730 | ||
|
|
70af1f9314 | ||
|
|
24aaa04954 | ||
|
|
ae06188871 | ||
|
|
3eb319af5b | ||
|
|
3de3932503 | ||
|
|
470bc65239 | ||
|
|
304b03b1d1 | ||
|
|
d9d27a88fc | ||
|
|
3fb61f068b | ||
|
|
2221945dc8 | ||
|
|
03fd073e76 | ||
|
|
0415ada289 | ||
|
|
b7b182c57c | ||
|
|
150dec1cc2 | ||
|
|
01230e2575 | ||
|
|
03e2a855b1 | ||
|
|
77826c8691 | ||
|
|
b529b7d3a0 | ||
|
|
e5f7d164cb | ||
|
|
c1903ca12d | ||
|
|
4796b551ad | ||
|
|
590ccc78aa | ||
|
|
eef2ed0b4c | ||
|
|
9a7654806f | ||
|
|
72e2d24c67 | ||
|
|
dc39acaa75 | ||
|
|
f914799b62 | ||
|
|
0f3fafde4b | ||
|
|
852ec4d990 | ||
|
|
30fa4c2aa9 | ||
|
|
b21a88d1b0 | ||
|
|
5e7566c89a | ||
|
|
adab6cf96f | ||
|
|
f7b3a1ef10 | ||
|
|
a19454f7ae | ||
|
|
8ed7690b96 | ||
|
|
4d19459015 | ||
|
|
a9c0cfd9c8 | ||
|
|
227b82c446 | ||
|
|
cca5b79e91 | ||
|
|
329d3d66b3 | ||
|
|
cb9ce85bda | ||
|
|
7aed5f0500 | ||
|
|
a92e05c640 | ||
|
|
f1525028da | ||
|
|
f2b3b0bf66 | ||
|
|
64a78532ed | ||
|
|
a9da275673 | ||
|
|
f74cc9cb10 | ||
|
|
975654f8e2 | ||
|
|
73718fe9af | ||
|
|
a06fa39a5d | ||
|
|
03d4d84eeb | ||
|
|
eb18115c99 | ||
|
|
1100c57e2d | ||
|
|
a591dbfe9c | ||
|
|
74013e07a8 | ||
|
|
d78b2404e2 | ||
|
|
9f895205d4 | ||
|
|
1ddf7d1f94 | ||
|
|
4d6991ea4b | ||
|
|
15e8343e75 | ||
|
|
4198379aa8 | ||
|
|
df369612be | ||
|
|
f02165b912 | ||
|
|
203e75ef3d | ||
|
|
14fc049ea0 | ||
|
|
83107d413d | ||
|
|
a15f9f38d8 | ||
|
|
00e841587d | ||
|
|
2d5d5b273a | ||
|
|
84b3386eab | ||
|
|
824ab7c0c2 | ||
|
|
d501a85c51 | ||
|
|
f53a43631c | ||
|
|
9c10a7adef | ||
|
|
bb1c7095d7 | ||
|
|
0bf03cb66e | ||
|
|
f15b716ea7 | ||
|
|
7c1f392fdf | ||
|
|
0a737eaa0d | ||
|
|
64edb88d36 | ||
|
|
1e7a2febea | ||
|
|
da0be9f226 | ||
|
|
8af1c92eff | ||
|
|
be008ca439 | ||
|
|
6e6eee71b3 | ||
|
|
2ac2dbd650 | ||
|
|
ff8d68f45c | ||
|
|
0a7d9c46eb | ||
|
|
b6fc49f057 | ||
|
|
57e28d4619 | ||
|
|
8ba3fe33f3 | ||
|
|
76c9d057cf | ||
|
|
5e605b30de | ||
|
|
e95af79c8a | ||
|
|
e84811bdce | ||
|
|
6aad799f95 | ||
|
|
6ff5ae78aa | ||
|
|
7d40585211 | ||
|
|
9440af0d67 | ||
|
|
0afba0d1d3 | ||
|
|
271e14e2f1 | ||
|
|
ac01edd440 | ||
|
|
f772fedf19 | ||
|
|
29cf7f8998 | ||
|
|
97f8e9e9fc | ||
|
|
c575294587 | ||
|
|
23e269940b | ||
|
|
7b18c81608 | ||
|
|
eae1a38705 | ||
|
|
3cb16ddb5f | ||
|
|
dcbca46e75 | ||
|
|
65b7f49c9b | ||
|
|
1006bd17e3 | ||
|
|
0700b9647b | ||
|
|
aad4ed6a83 | ||
|
|
185bed2048 | ||
|
|
9d52ee7120 | ||
|
|
0531365cb5 | ||
| f7858ab183 | |||
|
|
dfb41c7c40 | ||
|
|
c8177563e9 | ||
|
|
6f6be5ec47 | ||
|
|
54501bce2a | ||
|
|
46149b19f1 | ||
|
|
35e8a374df | ||
|
|
88af3c7681 | ||
|
|
93ddd50f76 | ||
|
|
3793b1f00b | ||
|
|
8dd376ae1e | ||
|
|
f816ce4beb | ||
|
|
6f932fe2cb | ||
|
|
49aba62dbb | ||
|
|
630d34f51c | ||
|
|
8846524541 | ||
|
|
279fa076d6 | ||
|
|
3cad0214d1 | ||
|
|
9c570b8121 | ||
|
|
2a00d50672 | ||
|
|
b05c41fe8f | ||
|
|
52fa7aaeae | ||
|
|
9f761a9ea5 | ||
|
|
337383b6fd | ||
|
|
c4dd85be53 | ||
|
|
de202ac6cc | ||
|
|
34050f641d | ||
|
|
fb18225f46 | ||
|
|
a5d527d0cf | ||
| 58229a922e | |||
| a2ed772417 | |||
|
|
e58af90c8b | ||
|
|
0d88357c85 | ||
|
|
ff2f5cb2ce | ||
|
|
0f7986ff36 | ||
|
|
f96a5e2b1a | ||
|
|
2b92bbc45f | ||
|
|
5ab326142f | ||
|
|
023b7f85fb | ||
|
|
79bcf811d6 | ||
|
|
543b231a80 | ||
|
|
c060b01037 | ||
|
|
f6a401ac6b | ||
|
|
ca8f0059a3 | ||
|
|
995042f130 | ||
|
|
259c236b72 | ||
|
|
81d25dd574 | ||
|
|
ff3e10d076 | ||
|
|
9b1fbe6c2c | ||
|
|
ed151e6d45 | ||
|
|
932128a084 | ||
|
|
8c6ef98b22 | ||
|
|
9e032223eb | ||
|
|
830cf22beb | ||
|
|
d7294bda55 | ||
|
|
49c1cb3aff | ||
|
|
834b87f4b2 | ||
|
|
180db5dea5 | ||
|
|
95d1c65011 | ||
|
|
bb508e91c1 | ||
|
|
94e32a5773 | ||
|
|
6427b097ab | ||
|
|
22de531ab3 | ||
|
|
b6453376e4 | ||
|
|
74742771c4 | ||
|
|
833ed8a40d | ||
|
|
c8991666d2 | ||
|
|
e31dc35733 | ||
|
|
5767ebea38 | ||
|
|
6500b62c52 | ||
|
|
4a1928ba92 | ||
|
|
6350d8e135 | ||
|
|
1dd5ac0ecb | ||
|
|
b42c4db400 | ||
|
|
dca1361bac | ||
|
|
f7cf0010db | ||
|
|
1073a2e2d1 | ||
|
|
b6648ff596 | ||
|
|
3a7db82004 | ||
|
|
cd3540b085 | ||
|
|
c7c1500c5e | ||
|
|
0316b2189d | ||
|
|
67ca452993 | ||
|
|
0bad9d7186 | ||
|
|
960b090702 | ||
|
|
ecbf886e52 | ||
|
|
da5b290809 | ||
|
|
d1e0a73f36 | ||
|
|
a9dc0e0dac | ||
|
|
22e6caa0e6 | ||
|
|
11ade05510 | ||
|
|
ef7dd0f069 | ||
|
|
417ff818d3 | ||
|
|
82a1c8a765 | ||
|
|
1f083cb168 | ||
|
|
51600a5329 | ||
|
|
140c736bef | ||
|
|
9b085faf07 | ||
|
|
619eec8335 | ||
|
|
e4de42659e | ||
|
|
bd609dfc90 | ||
|
|
50512cdef8 | ||
|
|
56f860676d | ||
|
|
3b90669d03 | ||
|
|
ecd717702d | ||
|
|
18d797150e | ||
|
|
8c16127115 | ||
|
|
f22bf24663 | ||
|
|
fdd4e3cc80 | ||
|
|
e91222b504 | ||
|
|
72ffe50ca6 | ||
|
|
7f1e392be2 | ||
|
|
51a9f61e88 | ||
|
|
293aaff2a5 | ||
|
|
f185c8b5db | ||
|
|
a38765d02d | ||
|
|
59f053433c | ||
| a923a2baa7 | |||
| f68f683e22 | |||
|
|
0dfc962df5 | ||
|
|
cf6f69ba93 | ||
|
|
4a3d341c9a | ||
|
|
78a04c90e6 | ||
|
|
9b0ba22ef9 | ||
|
|
0d910e3307 | ||
|
|
b1e700e2a2 | ||
|
|
a6190fe29d | ||
|
|
cf79175500 | ||
|
|
a1f003edd9 | ||
|
|
0780824e31 | ||
|
|
4cf2f4e7c7 | ||
|
|
53c9467bec | ||
|
|
157977e267 | ||
|
|
e714cacc58 | ||
|
|
ac20be8744 | ||
|
|
2681ab3828 | ||
|
|
7a55db3f21 | ||
|
|
5281253f66 | ||
|
|
7bead89e39 | ||
|
|
002f3b6c0e | ||
|
|
a873de5e9e | ||
|
|
73ef2e6c59 | ||
|
|
b46f833e23 | ||
|
|
e01a7be08e | ||
|
|
b35a367ed1 | ||
|
|
e967bf2398 | ||
|
|
9387e88dc0 | ||
|
|
eede772b53 | ||
|
|
bcb0454916 | ||
|
|
d2fe15679c | ||
|
|
c48f4b08a2 | ||
|
|
bfcce19649 | ||
| 0db954fa72 | |||
|
|
6e33f5e545 | ||
|
|
eab32c68f3 | ||
|
|
fe5814d5ba | ||
|
|
50221fbd65 | ||
|
|
6f2e306c7e | ||
|
|
a59ea5e245 | ||
|
|
0add6853bf | ||
|
|
393cce885b | ||
|
|
b580f19825 | ||
| 17e4f2536b | |||
| 595afc4a93 | |||
|
|
ca287db536 | ||
|
|
994382b801 | ||
|
|
d9348054f1 | ||
|
|
713cb6c6e5 | ||
|
|
d7b443d51b | ||
|
|
af05371c09 | ||
|
|
9dc38e87cd | ||
|
|
932bf7ca60 | ||
|
|
2dd96198af | ||
|
|
7dadc4ce77 | ||
|
|
34f1d4002b | ||
|
|
3845dc77f9 | ||
|
|
3163c91a4a | ||
| 7e4be6fdb6 | |||
| 4b8712b0f5 | |||
| 2f064f0145 | |||
| 0a9d4d0d66 | |||
| bcfa1fb906 | |||
| 3c3a3dba8f | |||
|
|
f760ef456c | ||
|
|
1ba48ecd64 | ||
|
|
57ba0cde37 | ||
|
|
a409132f69 | ||
|
|
0c006b4007 | ||
|
|
498a9c0be4 | ||
|
|
26dd78fff7 | ||
|
|
54810fd5ef | ||
|
|
27dace206b | ||
|
|
a54687671a | ||
|
|
e0ef02bfdb | ||
|
|
18d33933d4 |
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.git
|
||||
Dockerfile
|
||||
*.md
|
||||
logo.png
|
||||
versions.txt
|
||||
build.sh
|
||||
docker-compose.yml
|
||||
.env
|
||||
docker/__pycache__
|
||||
.env.example
|
||||
76
.editorconfig
Normal file
76
.editorconfig
Normal file
@@ -0,0 +1,76 @@
|
||||
# top-most EditorConfig file
|
||||
root=true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
indent_style=tab
|
||||
tab_width=4
|
||||
charset=utf-8
|
||||
trim_trailing_whitespace=true
|
||||
end_of_line=lf
|
||||
insert_final_newline=true
|
||||
|
||||
[*.{c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,inl,ipp,tlh,tli}]
|
||||
|
||||
vc_generate_documentation_comments=doxygen_slash_star
|
||||
|
||||
cpp_indent_braces=false
|
||||
cpp_alignment_tab_fill_style=use_spaces
|
||||
cpp_indent_multi_line_relative_to=innermost_parenthesis
|
||||
cpp_indent_within_parentheses=indent
|
||||
cpp_indent_preserve_within_parentheses=false
|
||||
cpp_indent_case_labels=false
|
||||
cpp_indent_case_contents=true
|
||||
cpp_indent_case_contents_when_block=false
|
||||
cpp_indent_lambda_braces_when_parameter=true
|
||||
cpp_indent_goto_labels=one_left
|
||||
cpp_indent_preprocessor=leftmost_column
|
||||
cpp_indent_access_specifiers=false
|
||||
cpp_indent_namespace_contents=true
|
||||
cpp_indent_preserve_comments=false
|
||||
cpp_new_line_before_open_brace_namespace=same_line
|
||||
cpp_new_line_before_open_brace_type=same_line
|
||||
cpp_new_line_before_open_brace_function=same_line
|
||||
cpp_new_line_before_open_brace_block=same_line
|
||||
cpp_new_line_before_open_brace_lambda=same_line
|
||||
cpp_new_line_scope_braces_on_separate_lines=false
|
||||
cpp_new_line_close_brace_same_line_empty_type=false
|
||||
cpp_new_line_close_brace_same_line_empty_function=false
|
||||
cpp_new_line_before_catch=false
|
||||
cpp_new_line_before_else=false
|
||||
cpp_new_line_before_while_in_do_while=false
|
||||
cpp_space_before_function_open_parenthesis=remove
|
||||
cpp_space_within_parameter_list_parentheses=false
|
||||
cpp_space_between_empty_parameter_list_parentheses=false
|
||||
cpp_space_after_keywords_in_control_flow_statements=true
|
||||
cpp_space_within_control_flow_statement_parentheses=false
|
||||
cpp_space_before_lambda_open_parenthesis=false
|
||||
cpp_space_within_cast_parentheses=false
|
||||
cpp_space_after_cast_close_parenthesis=false
|
||||
cpp_space_within_expression_parentheses=false
|
||||
cpp_space_before_block_open_brace=true
|
||||
cpp_space_between_empty_braces=false
|
||||
cpp_space_before_initializer_list_open_brace=false
|
||||
cpp_space_within_initializer_list_braces=true
|
||||
cpp_space_preserve_in_initializer_list=true
|
||||
cpp_space_before_open_square_bracket=false
|
||||
cpp_space_within_square_brackets=false
|
||||
cpp_space_before_empty_square_brackets=false
|
||||
cpp_space_between_empty_square_brackets=false
|
||||
cpp_space_group_square_brackets=true
|
||||
cpp_space_within_lambda_brackets=false
|
||||
cpp_space_between_empty_lambda_brackets=false
|
||||
cpp_space_before_comma=false
|
||||
cpp_space_after_comma=true
|
||||
cpp_space_remove_around_member_operators=true
|
||||
cpp_space_before_inheritance_colon=true
|
||||
cpp_space_before_constructor_colon=true
|
||||
cpp_space_remove_before_semicolon=true
|
||||
cpp_space_after_semicolon=false
|
||||
cpp_space_remove_around_unary_operator=true
|
||||
cpp_space_around_binary_operator=insert
|
||||
cpp_space_around_assignment_operator=insert
|
||||
cpp_space_pointer_reference_alignment=left
|
||||
cpp_space_around_ternary_operator=insert
|
||||
cpp_wrap_preserve_blocks=one_liners
|
||||
cpp_indent_comment=fasle
|
||||
17
.env.example
Normal file
17
.env.example
Normal file
@@ -0,0 +1,17 @@
|
||||
# Full path to the LEGO Universe client
|
||||
CLIENT_PATH=/Users/someuser/LEGO Universe
|
||||
# Can improve build time
|
||||
BUILD_THREADS=1
|
||||
# Updates NET_VERSION in CMakeVariables.txt
|
||||
BUILD_VERSION=171022
|
||||
# make sure this is a long random string
|
||||
# grab a "SHA 256-bit Key" from here: https://keygen.io/
|
||||
ACCOUNT_MANAGER_SECRET=
|
||||
# Should be the externally facing IP of your server host
|
||||
EXTERNAL_IP=localhost
|
||||
# Database values
|
||||
# Be careful with special characters here. It is more safe to use normal characters and/or numbers.
|
||||
MARIADB_USER=darkflame
|
||||
MARIADB_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||
MARIADB_DATABASE=darkflame
|
||||
8
.git-blame-ignore-revs
Normal file
8
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,8 @@
|
||||
# format codebase
|
||||
19e77a38d837ce781ba0ca6ea8e78b67a6e3b5a5
|
||||
|
||||
# add semi-colons to macros consistently
|
||||
9e4ce24fd2851e65df776dd9c57bcb0d45f4453a
|
||||
|
||||
# convert to unix line endings
|
||||
72477e01e2711e0f61cdb192ee266e5e21b8846f
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Bug Report
|
||||
description: Report incorrect behavior in DarkflameServer
|
||||
title: "BUG: "
|
||||
labels: ["bug", "triage"]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: "Make sure you've done the following:"
|
||||
options:
|
||||
- label: >
|
||||
I have checked that this issue has not already been reported.
|
||||
required: true
|
||||
- label: >
|
||||
I have validated that this issue is not a syntax error of either MySQL or SQLite.
|
||||
required: true
|
||||
- label: >
|
||||
I have pulled the latest version of the main branch of DarkflameServer and have confirmed that the issue exists there.
|
||||
required: true
|
||||
- type: input
|
||||
id: server-version
|
||||
attributes:
|
||||
label: DarkflameServer Version
|
||||
description: >
|
||||
DarkflameServer version or commit SHA (can be obtained with `git rev-parse --short HEAD`)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Issue Description
|
||||
description: >
|
||||
Please provide a description of the issue. If this is an in-game bug, please also include pictures that showcase the issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: >
|
||||
Please provide a concise list of steps needed to reproduce this issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: >
|
||||
Please describe what you expected to happen instead of the issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: >
|
||||
Please include the environment you're running DarkflameServer on (for example: Windows, macOS, Ubuntu, WSL, etc).
|
||||
validations:
|
||||
required: true
|
||||
44
.github/ISSUE_TEMPLATE/documentation_improvement.yaml
vendored
Normal file
44
.github/ISSUE_TEMPLATE/documentation_improvement.yaml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Documentation Improvement
|
||||
description: Report wrong or missing documentation
|
||||
title: "DOC: "
|
||||
labels: ["docs", "triage"]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: "Make sure you've done the following:"
|
||||
options:
|
||||
- label: >
|
||||
I have checked that this issue has not already been reported.
|
||||
required: true
|
||||
- label: >
|
||||
I have validated that the documentation is wrong or missing on the latest version of the main branch of DarkflameServer
|
||||
required: true
|
||||
- type: textarea
|
||||
id: location
|
||||
attributes:
|
||||
label: Location of the documentation
|
||||
description: >
|
||||
Please provide the location of the documentation, e.g. "Entity.cpp" or the
|
||||
URL of the documentation, e.g.
|
||||
"https://github.com/DarkflameUniverse/DarkflameServer/blob/main/README.md"
|
||||
placeholder: https://github.com/DarkflameUniverse/DarkflameServer/blob/main/README.md
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Documentation problem
|
||||
description: >
|
||||
Please provide a description of what documentation you believe needs to be fixed/improved
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: suggested-fix
|
||||
attributes:
|
||||
label: Suggested fix for documentation
|
||||
description: >
|
||||
Please explain the suggested fix and **why** it's better than the existing documentation
|
||||
validations:
|
||||
required: true
|
||||
40
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
40
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for DarkflameServer
|
||||
title: "ENH: "
|
||||
labels: ["enhancement", "triage"]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
description: >
|
||||
Please provide a description of what the problem is, e.g. "I wish I could use DarkflameServer to do [...]"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: >
|
||||
Please provide a description of the feature request, e.g. "`SlashCommandHandler.cpp` should get a new command `/unlimited-coins` that [...]", try to write a docstring for the desired feature
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: implications
|
||||
attributes:
|
||||
label: Repository breaking implications
|
||||
description: >
|
||||
Please provide a description of how this feature will affect the DarkflameServer repository
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: >
|
||||
Please provide a description of any alternative solutions or features you've considered
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: >
|
||||
Please add any other context, code examples, or references to existing implementations about the feature request here
|
||||
62
.github/ISSUE_TEMPLATE/installation_issue.yaml
vendored
Normal file
62
.github/ISSUE_TEMPLATE/installation_issue.yaml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Installation Issue
|
||||
description: Report issues installing the DarkflameServer on your system
|
||||
title: "BUILD: "
|
||||
labels: ["build", "triage"]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: "Make sure you've done the following:"
|
||||
options:
|
||||
- label: >
|
||||
I have read the [installation guide](https://github.com/DarkflameUniverse/DarkflameServer/blob/main/README.md).
|
||||
required: true
|
||||
- type: input
|
||||
id: server-version
|
||||
attributes:
|
||||
label: DarkflameServer Version
|
||||
description: >
|
||||
DarkflameServer version or commit SHA (can be obtained with `git rev-parse --short HEAD`)
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: Platform
|
||||
description: >
|
||||
Please provide on which platform you've tried to install DarkflameServer
|
||||
options:
|
||||
- Windows
|
||||
- WSL1
|
||||
- WSL2
|
||||
- macOS
|
||||
- Ubuntu
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: architecture
|
||||
attributes:
|
||||
label: Architecture
|
||||
description: >
|
||||
Please provide on which architecture you've tried to install DarkflameServer
|
||||
options:
|
||||
- x86
|
||||
- ARM
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Error Logs
|
||||
description: >
|
||||
If possible, please copy and paste the error logs when attempting to install DarkflameServer.
|
||||
value: >
|
||||
<details>
|
||||
|
||||
|
||||
Replace this line with the error logs.
|
||||
|
||||
|
||||
</details>
|
||||
50
.github/ISSUE_TEMPLATE/performance_issue.yaml
vendored
Normal file
50
.github/ISSUE_TEMPLATE/performance_issue.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Performance Issue
|
||||
description: Report slow performance or memory issues when running DarkflameServer
|
||||
title: "PERF: "
|
||||
labels: ["performance", "triage"]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: "Make sure you've done the following:"
|
||||
options:
|
||||
- label: >
|
||||
I have checked that this issue has not already been reported.
|
||||
required: true
|
||||
- label: >
|
||||
I have pulled the latest version of the main branch of DarkflameServer and have confirmed that the issue exists there.
|
||||
required: true
|
||||
- type: input
|
||||
id: server-version
|
||||
attributes:
|
||||
label: DarkflameServer Version
|
||||
description: >
|
||||
DarkflameServer version or commit SHA (can be obtained with `git rev-parse --short HEAD`)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: >
|
||||
Please include the environment you're running DarkflameServer on (for example: Windows, macOS, Ubuntu, WSL, etc), available memory, number of CPU cores.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Reproducible Example
|
||||
description: >
|
||||
Please provide a minimal, example that quantifies slow runtime or memory issues.
|
||||
Ideally include screenshots of CPU usage or memory usage. And if possible point
|
||||
to the code that you may suspect to cause the issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: prior-performance
|
||||
attributes:
|
||||
label: Prior Performance
|
||||
description: >
|
||||
If applicable, please provide the prior version of DarkflameServer and output
|
||||
of the same reproducible example where the performance issue did not exist.
|
||||
56
.github/workflows/build-and-test.yml
vendored
Normal file
56
.github/workflows/build-and-test.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
name: Build & Test (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-2022, ubuntu-20.04, macos-11 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Add msbuild to PATH (Windows only)
|
||||
if: ${{ matrix.os == 'windows-2022' }}
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
with:
|
||||
vs-version: '[17,18)'
|
||||
msbuild-architecture: x64
|
||||
- name: Install libssl (Mac Only)
|
||||
if: ${{ matrix.os == 'macos-11' }}
|
||||
run: brew install openssl@3
|
||||
- name: cmake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
configurePreset: "ci-${{matrix.os}}"
|
||||
buildPreset: "ci-${{matrix.os}}"
|
||||
testPreset: "ci-${{matrix.os}}"
|
||||
- name: artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ github.ref == 'ref/head/main' }}
|
||||
with:
|
||||
name: build-${{matrix.os}}
|
||||
path: |
|
||||
build
|
||||
!build/tests
|
||||
!build/Testing
|
||||
!build/CMakeFiles
|
||||
!build/DartConfiguration.tcl
|
||||
!build/CTestTestfile.cmake
|
||||
!build/CMakeCache.txt
|
||||
!build/build.ninja
|
||||
!build/_deps
|
||||
!build/cmake_install.cmake
|
||||
!build/*.a
|
||||
!build/*.lib
|
||||
!build/*.dir
|
||||
!build/*.vcxproj
|
||||
!build/*.vcxproj.filters
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
temp/
|
||||
cmake-build-debug/
|
||||
RelWithDebInfo/
|
||||
docker/configs
|
||||
|
||||
# Third party libraries
|
||||
thirdparty/mysql/
|
||||
@@ -114,3 +115,10 @@ CMakeFiles/TargetDirectories.txt
|
||||
# clangd
|
||||
.cache
|
||||
thirdparty/zlib-1.2.11/
|
||||
|
||||
.env
|
||||
docker/__pycache__
|
||||
|
||||
docker-compose.override.yml
|
||||
|
||||
!/tests/TestBitStreams/*.bin
|
||||
|
||||
16
.gitmodules
vendored
16
.gitmodules
vendored
@@ -10,3 +10,19 @@
|
||||
[submodule "thirdparty/libbcrypt"]
|
||||
path = thirdparty/libbcrypt
|
||||
url = https://github.com/trusch/libbcrypt.git
|
||||
[submodule "thirdparty/mariadb-connector-cpp"]
|
||||
path = thirdparty/mariadb-connector-cpp
|
||||
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
||||
ignore = dirty
|
||||
[submodule "thirdparty/docker-utils"]
|
||||
path = thirdparty/docker-utils
|
||||
url = https://github.com/lcdr/utils.git
|
||||
[submodule "thirdparty/LUnpack"]
|
||||
path = thirdparty/LUnpack
|
||||
url = https://github.com/Xiphoseer/LUnpack.git
|
||||
[submodule "thirdparty/AccountManager"]
|
||||
path = thirdparty/AccountManager
|
||||
url = https://github.com/DarkflameUniverse/AccountManager
|
||||
[submodule "thirdparty/raylib"]
|
||||
path = thirdparty/raylib
|
||||
url = https://github.com/raysan5/raylib
|
||||
|
||||
590
CMakeLists.txt
590
CMakeLists.txt
@@ -1,5 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(Darkflame)
|
||||
include(CTest)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Read variables from file
|
||||
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
|
||||
@@ -10,18 +13,14 @@ string(REPLACE "\n" ";" variables ${variables})
|
||||
# Set the cmake variables, formatted as "VARIABLE #" in variables
|
||||
foreach(variable ${variables})
|
||||
# If the string contains a #, skip it
|
||||
if("${variable}" MATCHES "#")
|
||||
continue()
|
||||
endif()
|
||||
if(NOT "${variable}" MATCHES "#")
|
||||
|
||||
# Split the variable into name and value
|
||||
string(REPLACE "=" ";" variable ${variable})
|
||||
|
||||
# Check that the length of the variable is 2 (name and value)
|
||||
list(LENGTH variable length)
|
||||
if(NOT ${length} EQUAL 2)
|
||||
continue()
|
||||
endif()
|
||||
if(${length} EQUAL 2)
|
||||
|
||||
list(GET variable 0 variable_name)
|
||||
list(GET variable 1 variable_value)
|
||||
@@ -33,89 +32,56 @@ foreach(variable ${variables})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
||||
|
||||
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
||||
endforeach()
|
||||
|
||||
# On windows it's better to build this from source, as there's no way FindZLIB is gonna find it
|
||||
if(NOT WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
# Fetch External (Non-Submodule) Libraries
|
||||
if(WIN32)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
mysql
|
||||
URL https://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-8.0.27-winx64.zip
|
||||
URL_HASH MD5=e3c53f6e4d0a72fde2713f7597bf9468
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
zlib
|
||||
URL http://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip
|
||||
URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(zlib)
|
||||
FetchContent_MakeAvailable(mysql)
|
||||
|
||||
set(ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR})
|
||||
set_target_properties(zlib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}") # Why?
|
||||
add_library(ZLIB::ZLIB ALIAS zlib) # You're welcome
|
||||
|
||||
endif(WIN32)
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
else()
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
mysql
|
||||
URL https://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-8.0.27-linux-glibc2.12-x86-64bit.tar.gz
|
||||
URL_HASH MD5=12f086b76c11022cc7139b41a36cdf9e
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(mysql)
|
||||
|
||||
if (__include_backtrace__ AND __compile_backtrace__)
|
||||
FetchContent_Declare(
|
||||
backtrace
|
||||
GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(backtrace)
|
||||
|
||||
if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs)
|
||||
set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind")
|
||||
|
||||
execute_process(
|
||||
COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
link_directories(${backtrace_SOURCE_DIR}/.libs/)
|
||||
include_directories(${backtrace_SOURCE_DIR})
|
||||
endif(__include_backtrace__)
|
||||
|
||||
endif()
|
||||
endif(UNIX)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Set the version
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
||||
# Set our compile options
|
||||
option(BUILD_VISUAL_DEBUGGER "Toggle for building visual debugger (default off)" OFF)
|
||||
|
||||
# Echo the version
|
||||
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
# Disable demo, tests and examples for recastNavigation. Turn these to ON if you want to use them
|
||||
# This has to be done here to prevent a rare build error due to missing dependencies on the initial generations.
|
||||
set(RECASTNAVIGATION_DEMO OFF CACHE BOOL "" FORCE)
|
||||
set(RECASTNAVIGATION_TESTS OFF CACHE BOOL "" FORCE)
|
||||
set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
|
||||
if(WIN32)
|
||||
# Compiler flags:
|
||||
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
|
||||
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
||||
# Disabled no-register
|
||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC")
|
||||
endif()
|
||||
if (__dynamic AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
||||
endif()
|
||||
if (__ggdb)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||
elseif(MSVC)
|
||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
||||
add_compile_options("/wd4267" "/utf-8")
|
||||
elseif(WIN32)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
endif(WIN32)
|
||||
endif()
|
||||
|
||||
# Our output dir
|
||||
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Create a /res directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/res)
|
||||
@@ -123,364 +89,184 @@ make_directory(${CMAKE_BINARY_DIR}/res)
|
||||
# Create a /locale directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/locale)
|
||||
|
||||
# Copy ini files on first build
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/authconfig.ini)
|
||||
# Create a /logs directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
||||
|
||||
# Copy resource files on first build
|
||||
set(RESOURCE_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
|
||||
foreach(resource_file ${RESOURCE_FILES})
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/authconfig.ini ${PROJECT_BINARY_DIR}/authconfig.ini
|
||||
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/chatconfig.ini)
|
||||
message("Moved ${resource_file} to project binary directory")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Copy vanity files on first build
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||
foreach(file ${VANITY_FILES})
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||
endforeach()
|
||||
|
||||
# Move our migrations for MasterServer to run
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/)
|
||||
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
|
||||
foreach(file ${SQL_FILES})
|
||||
get_filename_component(file ${file} NAME)
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/${file})
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/chatconfig.ini ${PROJECT_BINARY_DIR}/chatconfig.ini
|
||||
${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/${file}
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/worldconfig.ini)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/worldconfig.ini ${PROJECT_BINARY_DIR}/worldconfig.ini
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/masterconfig.ini)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/masterconfig.ini ${PROJECT_BINARY_DIR}/masterconfig.ini
|
||||
COPYONLY
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Create our list of include directories
|
||||
set(INCLUDED_DIRECTORIES
|
||||
"dCommon"
|
||||
"dChatFilter"
|
||||
"dGame"
|
||||
"dGame/dBehaviors"
|
||||
"dGame/dComponents"
|
||||
"dGame/dGameMessages"
|
||||
"dGame/dInventory"
|
||||
"dGame/dMission"
|
||||
"dGame/dEntity"
|
||||
"dGame/dUtilities"
|
||||
"dPhysics"
|
||||
"dNavigation"
|
||||
"dNavigation/dTerrain"
|
||||
"dZoneManager"
|
||||
"dDatabase"
|
||||
"dDatabase/Tables"
|
||||
"dNet"
|
||||
"dScripts"
|
||||
"dWorldServer"
|
||||
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
"thirdparty/SQLite"
|
||||
"thirdparty/cpplinq"
|
||||
)
|
||||
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
if (APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
# Copy files to output
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/CREDITS.md" "${CMAKE_BINARY_DIR}/vanity/CREDITS.md" COPYONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/INFO.md" "${CMAKE_BINARY_DIR}/vanity/INFO.md" COPYONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/TESTAMENT.md" "${CMAKE_BINARY_DIR}/vanity/TESTAMENT.md" COPYONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/NPC.xml" "${CMAKE_BINARY_DIR}/vanity/NPC.xml" COPYONLY)
|
||||
if (WIN32)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include")
|
||||
elseif (UNIX)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt")
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
|
||||
endif()
|
||||
|
||||
# 3rdparty includes
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/)
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
include_directories(/usr/local/include/)
|
||||
include_directories(/usr/local/mysql-connector-c++/include/jdbc/)
|
||||
include_directories(/usr/local/mysql-connector-c++/include/jdbc/cppconn/)
|
||||
else()
|
||||
include_directories(${mysql_SOURCE_DIR}/include/jdbc/)
|
||||
include_directories(${mysql_SOURCE_DIR}/include/jdbc/cppconn/)
|
||||
endif(APPLE)
|
||||
endif(UNIX)
|
||||
if(WIN32)
|
||||
include_directories(${mysql_SOURCE_DIR}/include/jdbc)
|
||||
include_directories(${mysql_SOURCE_DIR}/include/jdbc/cppconn)
|
||||
endif(WIN32)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
# Bcrypt
|
||||
if (NOT WIN32)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt)
|
||||
else ()
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include)
|
||||
endif ()
|
||||
|
||||
# Our includes
|
||||
# Add binary directory as an include directory
|
||||
include_directories(${PROJECT_BINARY_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dChatFilter/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dBehaviors)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dComponents)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dGameMessages)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dInventory)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dMission)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dEntity)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dUtilities)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dPhysics/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dZoneManager/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dDatabase/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dDatabase/Tables/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/SQLite/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/cpplinq/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dNet/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dScripts/)
|
||||
|
||||
# Default to linking to libmysql
|
||||
set(MYSQL_LIB mysql)
|
||||
if(WIN32)
|
||||
set(MYSQL_LIB mysqlcppconn)
|
||||
endif(WIN32)
|
||||
# Actually include the directories from our list
|
||||
foreach (dir ${INCLUDED_DIRECTORIES})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||
endforeach()
|
||||
|
||||
# Lib folders:
|
||||
# Add linking directories:
|
||||
link_directories(${PROJECT_BINARY_DIR})
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
link_directories(/usr/local/mysql-connector-c++/lib64/)
|
||||
else()
|
||||
link_directories(${mysql_SOURCE_DIR}/lib64/)
|
||||
|
||||
# Link to libmysqlcppconn on Linux
|
||||
set(MYSQL_LIB mysqlcppconn)
|
||||
endif(APPLE)
|
||||
endif(UNIX)
|
||||
if(WIN32)
|
||||
link_directories(${mysql_SOURCE_DIR}/lib64/vs14)
|
||||
endif(WIN32)
|
||||
# Load all of our third party directories
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
# Source Code
|
||||
# Glob together all headers that need to be precompiled
|
||||
file(
|
||||
GLOB SOURCES
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dWorldServer/*.cpp
|
||||
GLOB HEADERS_DDATABASE
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||
)
|
||||
|
||||
# Source Code for AuthServer
|
||||
file(
|
||||
GLOB SOURCES_AUTH
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dAuthServer/*.cpp
|
||||
GLOB HEADERS_DZONEMANAGER
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.h
|
||||
)
|
||||
|
||||
# Source Code for MasterServer
|
||||
file(
|
||||
GLOB SOURCES_MASTER
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dMasterServer/*.cpp
|
||||
GLOB HEADERS_DCOMMON
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dCommon/*.h
|
||||
)
|
||||
|
||||
# Source Code for ChatServer
|
||||
file(
|
||||
GLOB SOURCES_CHAT
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dChatServer/*.cpp
|
||||
GLOB HEADERS_DGAME
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dGame/Entity.h
|
||||
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
|
||||
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
|
||||
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h
|
||||
)
|
||||
|
||||
# Source Code for raknet
|
||||
file(
|
||||
GLOB SOURCES_RAKNET
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/*.cpp
|
||||
)
|
||||
# Add our library subdirectories for creation of the library object
|
||||
add_subdirectory(dCommon)
|
||||
add_subdirectory(dDatabase)
|
||||
add_subdirectory(dChatFilter)
|
||||
add_subdirectory(dNet)
|
||||
add_subdirectory(dScripts) # Add for dGame to use
|
||||
add_subdirectory(dGame)
|
||||
add_subdirectory(dZoneManager)
|
||||
add_subdirectory(dNavigation)
|
||||
add_subdirectory(dPhysics)
|
||||
|
||||
# Source Code for recast
|
||||
file(
|
||||
GLOB SOURCES_RECAST
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Source/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for detour
|
||||
file(
|
||||
GLOB SOURCES_DETOUR
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Source/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for tinyxml2
|
||||
file(
|
||||
GLOB SOURCES_TINYXML2
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.cpp
|
||||
)
|
||||
|
||||
# Source Code for libbcrypt
|
||||
file(
|
||||
GLOB SOURCES_LIBBCRYPT
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/*.c
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/src/*.c
|
||||
)
|
||||
|
||||
# Source Code for dCommon
|
||||
file(
|
||||
GLOB SOURCES_DCOMMON
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dCommon/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for dChatFilter
|
||||
file(
|
||||
GLOB SOURCES_DCHATFILTER
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dChatFilter/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for dDatabase
|
||||
file(
|
||||
GLOB SOURCES_DDATABASE
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.c
|
||||
)
|
||||
|
||||
# Source Code for dNet
|
||||
file(
|
||||
GLOB SOURCES_DNET
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dNet/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for dGame
|
||||
file(
|
||||
GLOB SOURCES_DGAME
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dGame/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dBehaviors/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dComponents/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dInventory/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dMission/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dEntity/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dGame/dUtilities/*.cpp
|
||||
${PROJECT_SOURCE_DIR}/dScripts/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for dZoneManager
|
||||
file(
|
||||
GLOB SOURCES_DZM
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for dPhysics
|
||||
file(
|
||||
GLOB SOURCES_DPHYSICS
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dPhysics/*.cpp
|
||||
)
|
||||
|
||||
# 3rdparty static libraries:
|
||||
#add_library(zlib ${SOURCES_ZLIB})
|
||||
add_library(raknet ${SOURCES_RAKNET})
|
||||
add_library(tinyxml2 ${SOURCES_TINYXML2})
|
||||
add_library(detour ${SOURCES_DETOUR})
|
||||
add_library(recast ${SOURCES_RECAST})
|
||||
add_library(libbcrypt ${SOURCES_LIBBCRYPT})
|
||||
|
||||
# Our static libraries:
|
||||
add_library(dCommon ${SOURCES_DCOMMON})
|
||||
add_library(dChatFilter ${SOURCES_DCHATFILTER})
|
||||
add_library(dDatabase ${SOURCES_DDATABASE})
|
||||
add_library(dNet ${SOURCES_DNET})
|
||||
add_library(dGame ${SOURCES_DGAME})
|
||||
add_library(dZoneManager ${SOURCES_DZM})
|
||||
add_library(dPhysics ${SOURCES_DPHYSICS})
|
||||
target_link_libraries(dNet dCommon) #Needed because otherwise linker errors occur.
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
target_link_libraries(dCommon libbcrypt)
|
||||
|
||||
# Our executables:
|
||||
add_executable(WorldServer ${SOURCES})
|
||||
add_executable(AuthServer ${SOURCES_AUTH})
|
||||
add_executable(MasterServer ${SOURCES_MASTER})
|
||||
add_executable(ChatServer ${SOURCES_CHAT})
|
||||
|
||||
# Target libraries to link to:
|
||||
target_link_libraries(WorldServer dCommon)
|
||||
target_link_libraries(WorldServer dChatFilter)
|
||||
target_link_libraries(WorldServer dDatabase)
|
||||
target_link_libraries(WorldServer dNet)
|
||||
target_link_libraries(WorldServer dGame)
|
||||
target_link_libraries(WorldServer dZoneManager)
|
||||
target_link_libraries(WorldServer dPhysics)
|
||||
target_link_libraries(WorldServer detour)
|
||||
target_link_libraries(WorldServer recast)
|
||||
target_link_libraries(WorldServer raknet)
|
||||
target_link_libraries(WorldServer ${MYSQL_LIB})
|
||||
if(UNIX)
|
||||
target_link_libraries(WorldServer pthread)
|
||||
target_link_libraries(WorldServer dl)
|
||||
|
||||
if(NOT APPLE AND __include_backtrace__)
|
||||
target_link_libraries(WorldServer backtrace)
|
||||
target_link_libraries(MasterServer backtrace)
|
||||
target_link_libraries(AuthServer backtrace)
|
||||
target_link_libraries(ChatServer backtrace)
|
||||
if (BUILD_VISUAL_DEBUGGER)
|
||||
add_subdirectory(dVisualDebugger)
|
||||
endif()
|
||||
|
||||
endif(UNIX)
|
||||
if(WIN32)
|
||||
target_link_libraries(WorldServer ws2_32)
|
||||
endif(WIN32)
|
||||
target_link_libraries(WorldServer tinyxml2)
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
|
||||
|
||||
# Target libraries for Auth:
|
||||
target_link_libraries(AuthServer dCommon)
|
||||
target_link_libraries(AuthServer dDatabase)
|
||||
target_link_libraries(AuthServer dNet)
|
||||
target_link_libraries(AuthServer raknet)
|
||||
target_link_libraries(AuthServer ${MYSQL_LIB})
|
||||
if(UNIX)
|
||||
target_link_libraries(AuthServer pthread)
|
||||
target_link_libraries(AuthServer dl)
|
||||
endif(UNIX)
|
||||
if(WIN32)
|
||||
target_link_libraries(AuthServer ws2_32)
|
||||
endif(WIN32)
|
||||
# Add platform specific common libraries
|
||||
if (UNIX)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread")
|
||||
|
||||
# Target libraries for Master:
|
||||
target_link_libraries(MasterServer dCommon)
|
||||
target_link_libraries(MasterServer dDatabase)
|
||||
target_link_libraries(MasterServer dNet)
|
||||
target_link_libraries(MasterServer raknet)
|
||||
target_link_libraries(MasterServer ${MYSQL_LIB})
|
||||
if(UNIX)
|
||||
target_link_libraries(MasterServer pthread)
|
||||
target_link_libraries(MasterServer dl)
|
||||
endif(UNIX)
|
||||
if(WIN32)
|
||||
target_link_libraries(MasterServer ws2_32)
|
||||
endif(WIN32)
|
||||
|
||||
# Target libraries for Chat:
|
||||
target_link_libraries(ChatServer dCommon)
|
||||
target_link_libraries(ChatServer dChatFilter)
|
||||
target_link_libraries(ChatServer dDatabase)
|
||||
target_link_libraries(ChatServer dNet)
|
||||
target_link_libraries(ChatServer raknet)
|
||||
target_link_libraries(ChatServer ${MYSQL_LIB})
|
||||
if(UNIX)
|
||||
target_link_libraries(ChatServer pthread)
|
||||
target_link_libraries(ChatServer dl)
|
||||
endif(UNIX)
|
||||
if(WIN32)
|
||||
target_link_libraries(ChatServer ws2_32)
|
||||
endif(WIN32)
|
||||
|
||||
# Compiler flags:
|
||||
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
|
||||
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
||||
# Disabled no-register
|
||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -Wno-unused-result -Wno-unknown-pragmas -fpermissive -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -Wno-unused-result -Wno-unknown-pragmas -fpermissive -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC")
|
||||
if (NOT APPLE AND __include_backtrace__)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace")
|
||||
endif()
|
||||
if (__dynamic)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
||||
endif()
|
||||
if (__ggdb)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||
endif(UNIX)
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
||||
# Include all of our binary directories
|
||||
add_subdirectory(dWorldServer)
|
||||
add_subdirectory(dAuthServer)
|
||||
add_subdirectory(dChatServer)
|
||||
add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries
|
||||
|
||||
# Add our precompiled headers
|
||||
target_precompile_headers(
|
||||
dGame PRIVATE
|
||||
${HEADERS_DGAME}
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
dZoneManager PRIVATE
|
||||
${HEADERS_DZONEMANAGER}
|
||||
)
|
||||
|
||||
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
|
||||
target_precompile_headers(
|
||||
dDatabase PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
dCommon PRIVATE
|
||||
${HEADERS_DCOMMON}
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
tinyxml2 PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
|
||||
)
|
||||
|
||||
126
CMakePresets.json
Normal file
126
CMakePresets.json
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"version": 3,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 14,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"displayName": "Default configure step",
|
||||
"description": "Use 'build' dir and Unix makefiles",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"generator": "Unix Makefiles"
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"displayName": "CI configure step for Ubuntu",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default"
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"displayName": "CI configure step for MacOS",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default",
|
||||
"cacheVariables": {
|
||||
"OPENSSL_ROOT_DIR": "/usr/local/Cellar/openssl@3/3.0.5/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-windows-2022",
|
||||
"displayName": "CI configure step for Windows",
|
||||
"description": "Set architecture to 64-bit (b/c RakNet)",
|
||||
"inherits": "default",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"architecture": {
|
||||
"value": "x64"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-default",
|
||||
"inherits": "ci-windows-2022",
|
||||
"displayName": "Windows only Configure Settings",
|
||||
"description": "Sets build and install directories",
|
||||
"generator": "Ninja",
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"configurePreset": "default",
|
||||
"displayName": "Default Build",
|
||||
"description": "Default Build",
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-windows-2022",
|
||||
"configurePreset": "ci-windows-2022",
|
||||
"displayName": "Windows CI Build",
|
||||
"description": "This preset is used by the CI build on windows",
|
||||
"configuration": "RelWithDebInfo",
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"displayName": "Linux CI Build",
|
||||
"description": "This preset is used by the CI build on linux",
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "MacOS CI Build",
|
||||
"description": "This preset is used by the CI build on MacOS",
|
||||
"jobs": 2
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"displayName": "CI Tests on Linux",
|
||||
"description": "Runs all tests on a linux configuration",
|
||||
"execution": {
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "CI Tests on MacOS",
|
||||
"description": "Runs all tests on a Mac configuration",
|
||||
"execution": {
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-windows-2022",
|
||||
"configurePreset": "ci-windows-2022",
|
||||
"displayName": "CI Tests on windows",
|
||||
"description": "Runs all tests on a windows configuration",
|
||||
"configuration": "RelWithDebInfo",
|
||||
"execution": {
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
PROJECT_VERSION_MAJOR=1
|
||||
PROJECT_VERSION_MINOR=0
|
||||
PROJECT_VERSION_PATCH=0
|
||||
PROJECT_VERSION_PATCH=4
|
||||
# LICENSE
|
||||
LICENSE=AGPL-3.0
|
||||
# The network version.
|
||||
# 171023 - Darkflame Universe client
|
||||
# 171022 - Unmodded client
|
||||
NET_VERSION=171023
|
||||
NET_VERSION=171022
|
||||
# Debugging
|
||||
# __dynamic=1
|
||||
__dynamic=1
|
||||
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||
# __ggdb=1
|
||||
# Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info.
|
||||
@@ -16,3 +16,5 @@ NET_VERSION=171023
|
||||
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
|
||||
# __compile_backtrace__=1
|
||||
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
||||
__maria_db_connector_compile_jobs__=1
|
||||
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
|
||||
|
||||
@@ -36,23 +36,109 @@ In general, we follow the "fork-and-pull" Git workflow
|
||||
- Open a PR in our repository.
|
||||
|
||||
PRs should include (when applicable):
|
||||
- A descriptive title that covers the **entire** content of the pull request
|
||||
- Description
|
||||
- Motivation and Context
|
||||
- Type of Changes
|
||||
- How Has This Been Tested?
|
||||
- Screenshots
|
||||
|
||||
## Commits
|
||||
|
||||
Commits to this project should be concise, descriptive and to the point. Writing proper commits helps define a clear project history and makes it easier to browse the source and pinpoint issues. Although this might seem trivial, a pull request with improperly formatted commits will not be accepted. An overview of good commit practices can be found in [this](https://cbea.ms/git-commit/) article. In a nutshell, a good commit has:
|
||||
|
||||
#### one conceptual change with a subject line that reflects it
|
||||
|
||||
The subject line of the commit is what you specify when doing `git commit -m "<subject-line>"`. When making commit, make sure that you create it for one conceptual change. E.g. do not use a commit to dump all the changes you have locally, but split your changes into commits that conceptually make sense and use the subject line to refelct that. Some examples:
|
||||
|
||||
**Bad:**
|
||||
Commit message: `Document MovementAIComponent and add Avant Gardens Mech Scripts and fix Entity.cpp bug causing infinite loops`
|
||||
Changed files:
|
||||
- MovementAIComponent.cpp
|
||||
- AgMechScript.cpp
|
||||
- Entity.cpp
|
||||
|
||||
**Good:**
|
||||
|
||||
Commit message: `Document MovementAIComponent`
|
||||
Changed files:
|
||||
- MovementAIComponent.cpp
|
||||
|
||||
Commit message: `Add Avant Gardens Mech Scripts`
|
||||
Changed files:
|
||||
- AgMechScript.cpp
|
||||
|
||||
Commit message: `Fix Entity.cpp bug causing infinite loops`
|
||||
Changed files:
|
||||
- Entity.cpp
|
||||
|
||||
Not only does this logically make more sense, it'll make it easier to revert a conceptual change once something wrong with it. If you commit using the bad example but your bugfix turned out to introduce an even worse bug, all your changes have to be reverted, even though your other changes might not be broken. Splitting your commits into conceptually unique commits makes it easier to find and revert issues.
|
||||
|
||||
#### an imperative subject line
|
||||
|
||||
In the subject line it's also important to have an imperative writing style that covers the contents of your commit so that it easily reflects what it'll do when applied. We pick an imperative writing style so that all commits have equal tonality. An easy check for this is placing `When applied, this commit will ...` in front of your commit message and checking if that makes sense. Some examples:
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
Nice commit :) -> "When applied, this commit will nice commit :)"
|
||||
```
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
fixed bug -> "When applied, this commit will fixed bug"
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
Fix Entity.cpp bug causing infinite loop -> "When applied, this commit will fix Entity.cpp bug causing infinite loop"
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
Add Avant Gardens mech scripts -> "When applied, this commit will add Avant Gardens mech scripts"
|
||||
```
|
||||
|
||||
#### a subject line and a body
|
||||
|
||||
A good commit has a subject line that summarizes the change and a body that further describes the context required to understand the change. In this body you don't have to explain *what* the change was, as the code should reflect that, but *why* a change was made. Some examples:
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
Add Avant Gardens mech scripts
|
||||
|
||||
Added the Avant Gardens mech scripts by creaing a new file called
|
||||
AgMechScripts.cpp and then adding the proper event handlers to that
|
||||
to send events to the client regarding changes of the mech.
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
Add Avant Gardens mech scripts
|
||||
|
||||
Added the Avant Gardens mech scripts as they were previously not
|
||||
added, which produced InvalidScript errors.
|
||||
```
|
||||
|
||||
## Development Resources
|
||||
|
||||
Check out a compiled list of development resources and tools [here](https://lu-dev.net/).
|
||||
|
||||
|
||||
Please use [.editorconfig](https://editorconfig.org/#pre-installed) with your preferred IDE.
|
||||
|
||||
And run:
|
||||
```bash
|
||||
git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
```
|
||||
to ignore the gitblame of mass formatting commits
|
||||
|
||||
## Coding Style
|
||||
|
||||
This project has gone through multiple iterations of coding style. In the code you'll find a number of different coding styles in use. What follows is the preferred style for this project.
|
||||
|
||||
### General
|
||||
|
||||
Use 4 spaces instead of the tab character.
|
||||
**Never** use spaces instead of tabs. 1 Tab = 4 space character's width by default.
|
||||
|
||||
Use typically trailing braces everywhere (if, else, functions, structures, typedefs, class definitions, etc.)
|
||||
|
||||
|
||||
46
Docker.md
Normal file
46
Docker.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Run the Darkflame Server inside Docker
|
||||
|
||||
## What you need
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker)
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop)
|
||||
- LEGO® Universe packed Client. Check the main [README](./README.md) for details on this.
|
||||
|
||||
## Run server inside Docker
|
||||
|
||||
1. Copy `.env.example` and save it as `.env` inside the root directory of this repository
|
||||
2. Edit the `.env` file and add your path to the root directory of your LEGO® Universe Client after `CLIENT_PATH=`
|
||||
3. Update other values in the `.env` file as needed (be sure to update passwords!)
|
||||
4. Run `docker compose up -d --build`
|
||||
5. Run `docker compose exec darkflame /app/MasterServer -a` and setup your admin account
|
||||
6. Follow the directions [here](https://github.com/DarkflameUniverse/AccountManager) to setup regular user accounts. The server will be accessible at: `http://<EXTERNAL_IP>:5000`
|
||||
7. Now you can see the output of the server with `docker compose logs -f --tail 100` or `docker compose logs -f --tail 100`. This can help you understand issues and there you can also see when the server finishes it's startup.
|
||||
8. You're ready to connect your client!
|
||||
|
||||
**NOTE #1**: If you're running an older version of Docker, you may need to use the command `docker-compose` instead of `docker compose`.
|
||||
|
||||
**NOTE #2**: To stop the server simply run `docker compose down` and to restart it just run `docker compose up -d` again. No need to run all the steps above every time.
|
||||
|
||||
**NOTE #3**: Docker buildkit needs to be enabled. https://docs.docker.com/develop/develop-images/build_enhancements/#to-enable-buildkit-builds
|
||||
|
||||
**NOTE #4**: Make sure to run the following in the repo root directory after cloning so submodules are also downloaded.
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
**NOTE #5**: If DarkflameSetup fails due to not having cdclient.fdb, rename CDClient.fdb (in the same folder) to cdclient.fdb
|
||||
|
||||
## Disable brickbuildfix
|
||||
|
||||
If you don't need the http server running on port 80 do this:
|
||||
|
||||
1. Create a file with the name `docker-compose.override.yml` in the root of the repository
|
||||
2. Paste this content:
|
||||
|
||||
```yml
|
||||
services:
|
||||
brickbuildfix:
|
||||
profiles:
|
||||
- donotstart
|
||||
```
|
||||
|
||||
3. Now run `docker compose up -d`
|
||||
58
Docker_Windows.md
Normal file
58
Docker_Windows.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Installation under Windows
|
||||
## First Run
|
||||
1. Navigate to the [Docker download page](https://www.docker.com/products/docker-desktop) and download docker.
|
||||
|
||||

|
||||
|
||||
2. Once the file has finished downloading, run it and proceed through the installation. Make sure, "Install required Windows components for WSL 2" is checked.
|
||||
|
||||

|
||||
|
||||
3. If necessary, restart your computer.
|
||||
4. After the restart, Docker Desktop will automatically open. If it does not, simply start it like any other program.
|
||||
5. If a window "WSL 2 Installation is incomplete." pops up, follow the link and click "WSL2 Linux kernel update package for x64 machines". Run the downloaded file and once that finishes, click "Restart" in the Docker Desktop window.
|
||||
|
||||

|
||||
|
||||
6. Wait until Docker Desktop has started. You may skip the tutorial.
|
||||
7. You may want to disable "Open Docker Dashboard at startup" in _Settings_ -> _General_
|
||||
|
||||

|
||||
|
||||
8. Install [Git for Windows](https://git-scm.com/download/win). During the installation, simply confirming the defaults is sufficient.
|
||||
9. In the folder you wish to save the Server, right click and select "Git Bash Here".
|
||||
10. Type `git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer`
|
||||
11. Once the command has completed (you can see you path again and can enter commands), close the window.
|
||||
12. Inside the downloaded folder, copy `.env.example` and name the copy `.env`
|
||||
13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_.
|
||||
14. Change the text after `CLIENT_PATH=` to the location of your client. The folder you are pointing to must contain a folder called `client` which should contain the client files.
|
||||
> If you need the extra performance, place the client files in `\\wsl$\<your linux OS>\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems).
|
||||
|
||||
15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value.
|
||||
16. After `ACCOUNT_MANAGER_SECRET=` paste a "SHA 256-bit Key" from https://keygen.io/
|
||||
17. If you are not only hosting a local server, change the value after `EXTERNAL_IP=` to the external IP address of your computer.
|
||||
18. Change the two values `SECRET_VALUE_CHANGE_ME` to passwords only you know. Save and close the file.
|
||||
19. In the extracted folder hit Shift+Right Click and select "Open PowerShell window here".
|
||||
|
||||

|
||||
|
||||
17. In the new window, paste (with right click) or type `docker compose up -d --build` and confirm with enter.
|
||||
18. Once you see the blinking cursor and the path again, setup has finished and the server is already running.
|
||||
|
||||

|
||||
|
||||
19. Create an admin account by pasting `docker compose exec darkflame /app/MasterServer -a` and following the prompts.
|
||||
|
||||

|
||||
|
||||
20. You can now login with these credentials at `http://your_ip:5000` (replace your_ip with your external IP). There you can create your account for playing as well as generate keys for other people to join; use these at `http://your_ip:5000/activate`
|
||||
|
||||
## Normal Use
|
||||
1. In Docker Desktop you should now see an entry `darkflameserver-main` and when you click on it all containers but `DarkflameSetup` should eventually be green. That means the server is running.
|
||||
|
||||

|
||||
|
||||
2. For troubleshooting, you can check the logs of the various parts by clicking their entry.
|
||||
3. You can start and stop the server with the corresponding buttons. Once all containers are grey, the server has shut down, and when all containers but `DarkflameSetup` are green, the server is running. Note that starting and stopping takes some time, please be patient.
|
||||
|
||||

|
||||
169
README.md
169
README.md
@@ -27,25 +27,41 @@ Darkflame Universe is a server emulator and does not distribute any LEGO® Unive
|
||||
Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience.
|
||||
|
||||
### Prerequisites
|
||||
**Clone the repository**
|
||||
#### Clone the repository
|
||||
```bash
|
||||
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||
```
|
||||
|
||||
**Python**
|
||||
#### Python
|
||||
|
||||
Some tools utilized to streamline the setup process require Python 3, make sure you have it installed.
|
||||
|
||||
**Choosing the right version for your client**
|
||||
|
||||
### Choosing the right version for your client
|
||||
DLU clients identify themselves using a higher version number than the regular live clients out there.
|
||||
This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client.
|
||||
|
||||
If you're using a DLU client, then you don't need to change anything. But if you're using any other client, you'll have to go into the "CMakeVariables.txt" file and change it to match your client's version. (likely 171022)
|
||||
If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number.
|
||||
|
||||
### Using Docker
|
||||
Refer to [Docker.md](/Docker.md).
|
||||
|
||||
For Windows, refer to [Docker_Windows.md](/Docker_Windows.md).
|
||||
|
||||
### Linux builds
|
||||
Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed.
|
||||
Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`.
|
||||
|
||||
CMake must be version 3.14 or higher!
|
||||
|
||||
#### Build the repository
|
||||
|
||||
You can either run `build.sh` when in the root folder of the repository:
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
|
||||
Or manually run the commands used in `build.sh`:
|
||||
|
||||
**Build the repository**
|
||||
```bash
|
||||
# Create the build directory, preserving it if it already exists
|
||||
mkdir -p build
|
||||
@@ -54,33 +70,30 @@ cd build
|
||||
# Run CMake to generate make files
|
||||
cmake ..
|
||||
|
||||
# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8`
|
||||
make
|
||||
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### MacOS builds
|
||||
Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`).
|
||||
|
||||
**Download precompiled MySQL connector**
|
||||
In the repository root folder run the following. Ensure -DOPENSSL_ROOT_DIR=/path/to/openssl points to your openssl install location
|
||||
```bash
|
||||
# Install required tools
|
||||
brew install boost mysql-connector-c++
|
||||
# Create the build directory, preserving it if it already exists
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
# Symlinks for finding the required modules
|
||||
sudo ln -s /usr/local/mysql-connector-c++/lib64/libmysqlcppconn.dylib /usr/local/mysql-connector-c++/lib64/libmysql.dylib
|
||||
sudo ln -s /usr/local/mysql-connector-c++/lib64/libcrypto.1.1.dylib /usr/local/mysql/lib/libcrypto.1.1.dylib
|
||||
```
|
||||
# Run CMake to generate build files
|
||||
cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl
|
||||
|
||||
Then follow the Linux build steps (gcc is not required), but before running `make`, run the following to make sure all the libs are available in the build folder:
|
||||
|
||||
```bash
|
||||
sudo ln -s /usr/local/mysql-connector-c++/lib64/libssl.1.1.dylib /path/to/build/folder/libssl.1.1.dylib
|
||||
sudo ln -s /usr/local/mysql-connector-c++/lib64/libcrypto.1.1.dylib /path/to/build/folder/libcrypto.1.1.dylib
|
||||
# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8`
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### Windows builds (native)
|
||||
Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/).
|
||||
Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode.
|
||||
|
||||
**Build the repository**
|
||||
#### Build the repository
|
||||
```batch
|
||||
:: Create the build directory
|
||||
mkdir build
|
||||
@@ -90,20 +103,31 @@ cd build
|
||||
cmake ..
|
||||
|
||||
:: Run CMake with build flag to build
|
||||
cmake --build .
|
||||
cmake --build . --config Release
|
||||
```
|
||||
#### Windows for ARM has not been tested but should build by doing the following
|
||||
```batch
|
||||
:: Create the build directory
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
:: Run CMake to generate make files
|
||||
cmake .. -DMARIADB_BUILD_SOURCE=ON
|
||||
|
||||
:: Run CMake with build flag to build
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### Windows builds (WSL)
|
||||
This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11.
|
||||
|
||||
**Open the Command Prompt application with Administrator permissions and run the following:**
|
||||
#### Open the Command Prompt application with Administrator permissions and run the following:
|
||||
```bash
|
||||
# Installing Windows Subsystem for Linux
|
||||
wsl --install
|
||||
```
|
||||
|
||||
**Open the Ubuntu application and run the following:**
|
||||
#### Open the Ubuntu application and run the following:
|
||||
```bash
|
||||
# Make sure the install is up to date
|
||||
apt update && apt upgrade
|
||||
@@ -111,23 +135,31 @@ apt update && apt upgrade
|
||||
# Make sure the gcc, cmake, and build-essentials are installed
|
||||
sudo apt install gcc
|
||||
sudo apt install cmake
|
||||
sudo apt install build-essentials
|
||||
sudo apt install build-essential
|
||||
```
|
||||
|
||||
[**Follow the Linux instructions**](#linux-builds)
|
||||
|
||||
### ARM builds
|
||||
AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested
|
||||
|
||||
### Updating your build
|
||||
To update your server to the latest version navigate to your cloned directory
|
||||
```bash
|
||||
cd /path/to/DarkflameServer
|
||||
```
|
||||
run the following commands to update to the latest changes
|
||||
```bash
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
now follow the build section for your system
|
||||
|
||||
## Setting up the environment
|
||||
|
||||
### Database
|
||||
Darkflame Universe utilizes a MySQL/MariaDB database for account and character information.
|
||||
|
||||
Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running.
|
||||
* Create a database for Darkflame Universe to use
|
||||
* Run each SQL file in the order at which they appear [here](migrations/dlu/) on the database
|
||||
|
||||
### Resources
|
||||
|
||||
**LEGO® Universe 1.10.64**
|
||||
#### LEGO® Universe 1.10.64
|
||||
|
||||
This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe.
|
||||
|
||||
@@ -150,29 +182,39 @@ shasum -a 256 <file>
|
||||
certutil -hashfile <file> SHA256
|
||||
```
|
||||
|
||||
**Unpacking the client**
|
||||
#### Unpacking the client
|
||||
* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils)
|
||||
* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked
|
||||
|
||||
**Setup resource directory**
|
||||
#### Setup resource directory
|
||||
* In the `build` directory create a `res` directory if it does not already exist.
|
||||
* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, and `maps` in your client `res` directory to the server `build/res` directory
|
||||
* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory
|
||||
* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes`
|
||||
|
||||
**Setup locale**
|
||||
#### Setup locale
|
||||
* In the `build` directory create a `locale` directory if it does not already exist
|
||||
* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory
|
||||
|
||||
**Client database**
|
||||
#### Client database
|
||||
* Use `fdb_to_sqlite.py` in lcdr's utilities on `res/cdclient.fdb` in the unpacked client to convert the client database to `cdclient.sqlite`
|
||||
* Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite`
|
||||
* Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database
|
||||
|
||||
**Configuration**
|
||||
### Database
|
||||
Darkflame Universe utilizes a MySQL/MariaDB database for account and character information.
|
||||
|
||||
Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running.
|
||||
* Create a database for Darkflame Universe to use
|
||||
|
||||
#### Configuration
|
||||
|
||||
After the server has been built there should be four `ini` files in the build director: `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary.
|
||||
|
||||
**Verify**
|
||||
#### Setup and Migrations
|
||||
|
||||
Use the command `./MasterServer -m` to setup the tables in the database. The first time this command is run on a database, the tables will be up to date with the most recent version. To update your database tables, run this command again. Multiple invocations will not affect any functionality.
|
||||
|
||||
#### Verify
|
||||
|
||||
Your build directory should now look like this:
|
||||
* AuthServer
|
||||
@@ -223,6 +265,7 @@ To connect to a server follow these steps:
|
||||
* Open it in a text editor and locate where it says `AUTHSERVERIP=0:`
|
||||
* Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers
|
||||
* Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system
|
||||
* Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users.
|
||||
|
||||
### Survival
|
||||
|
||||
@@ -232,6 +275,8 @@ The client script for the survival minigame has a bug in it which can cause the
|
||||
* Change `PlayerReady(self)` to `onPlayerReady(self)`
|
||||
* Save the file, overriding readonly mode if required
|
||||
|
||||
If you still experience the bug, try deleting/renaming `res/pack/scripts.pk`.
|
||||
|
||||
### Brick-By-Brick building
|
||||
|
||||
Brick-By-Brick building requires `PATCHSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be achieved by pointing it to `localhost` while having `sudo python -m http.server 80` running in the background.
|
||||
@@ -283,10 +328,10 @@ Here is a summary of the commands available in-game. All commands are prefixed b
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
instance-info
|
||||
instanceinfo
|
||||
</td>
|
||||
<td>
|
||||
/instance-info
|
||||
/instanceinfo
|
||||
</td>
|
||||
<td>
|
||||
Displays in the chat the current zone, clone, and instance id.
|
||||
@@ -380,30 +425,38 @@ Here is a summary of the commands available in-game. All commands are prefixed b
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Credits
|
||||
### Contributors to DLUv3
|
||||
* DarwinAnim8or
|
||||
* Wincent01
|
||||
* Mick
|
||||
* averysumner
|
||||
* Jon002
|
||||
* Jonny
|
||||
* Xiphoseer
|
||||
# Credits
|
||||
## Active Contributors
|
||||
* [EmosewaMC](https://github.com/EmosewaMC)
|
||||
* [Jettford](https://github.com/Jettford)
|
||||
* [Aaron K.](https://github.com/aronwk-aaron)
|
||||
|
||||
## DLU Team
|
||||
* [DarwinAnim8or](https://github.com/DarwinAnim8or)
|
||||
* [Wincent01](https://github.com/Wincent01)
|
||||
* [Mick](https://github.com/MickVermeulen)
|
||||
* [averysumner](https://github.com/codeshaunted)
|
||||
* [Jon002](https://github.com/jaller200)
|
||||
* [Jonny](https://github.com/cuzitsjonny)
|
||||
|
||||
### Research and tools
|
||||
* lcdr
|
||||
* [lcdr](https://github.com/lcdr)
|
||||
* [Xiphoseer](https://github.com/Xiphoseer)
|
||||
|
||||
### Community management
|
||||
* Neal
|
||||
* [Neal](https://github.com/NealSpellman)
|
||||
|
||||
### Former contributors
|
||||
* TheMachine
|
||||
* Matthew
|
||||
* Raine
|
||||
* [Raine](https://github.com/Rainebannister)
|
||||
* Bricknave
|
||||
|
||||
### Special thanks
|
||||
### Logo
|
||||
* Cole Peterson (BlasterBuilder)
|
||||
|
||||
## Special thanks
|
||||
* humanoid24
|
||||
* pwjones1969
|
||||
* BlasterBuilder for the logo
|
||||
* [Simon](https://github.com/SimonNitzsche)
|
||||
* ALL OF THE NETDEVIL AND LEGO TEAMS!
|
||||
|
||||
51
SECURITY.md
Normal file
51
SECURITY.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
At the moment, only the latest commit on the `main` branch will be supported for security vulnerabilities. Private server operators
|
||||
should keep their instances up to date and forks should regularily rebase on `main`.
|
||||
|
||||
| Branch | Supported |
|
||||
| ------- | ------------------ |
|
||||
| `main` | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you found a security vulnerability in DLU, please send a message to [darkflame-security@googlegroups.com][darkflame-security]. You should get a
|
||||
reply within *72 hours* that we have received your report and a tentative [CVSS score](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator).
|
||||
We will do a preliminary analysis to confirm that the vulnerability is a plausible claim and decline the report otherwise.
|
||||
|
||||
If possible, please include
|
||||
|
||||
1. reproducible steps on how to trigger the vulnerability
|
||||
2. a description on why you are convinced that it exists.
|
||||
3. any information you may have on active exploitation of the vulnerability (zero-day).
|
||||
|
||||
## Security Advisories
|
||||
|
||||
The project will release advisories on resolved vulnerabilities at <https://github.com/DarkflameUniverse/DarkflameServer/security/advisories>
|
||||
|
||||
## Receiving Security Updates
|
||||
|
||||
We set up [darkflame-security-announce@googlegroups.com][darkflame-security-announce] for private server operators to receive updates on vulnerabilities
|
||||
such as the release of [Security Advisories](#security-advisories) or early workarounds and recommendations to mitigate ongoing
|
||||
vulnerabilities.
|
||||
|
||||
Unfortunately, we cannot guarantee that announcements will be sent for every vulnerability.
|
||||
|
||||
## Embargo
|
||||
|
||||
We propose a 90 day (approx. 3 months) embargo on security vulnerabilities. That is, we ask everyone not to disclose the vulnerabilty
|
||||
publicly until either:
|
||||
|
||||
1. 90 days have passed from the time the first related email is sent to `darkflame-security@`
|
||||
2. a security advisory related to the vulnerability has been published by the project.
|
||||
|
||||
If you fail to comply with this embargo, you might be exluded from [receiving security updates](#receiving-security-updates).
|
||||
|
||||
## Bug Bounty
|
||||
|
||||
Unfortunately we cannot provide bug bounties at this time.
|
||||
|
||||
[darkflame-security]: mailto:darkflame-security@googlegroups.com
|
||||
[darkflame-security-announce]: https://groups.google.com/g/darkflame-security-announce
|
||||
7
build.sh
Normal file → Executable file
7
build.sh
Normal file → Executable file
@@ -5,5 +5,8 @@ cd build
|
||||
# Run cmake to generate make files
|
||||
cmake ..
|
||||
|
||||
# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8`
|
||||
make
|
||||
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
|
||||
cmake --build . --config Release
|
||||
|
||||
# Run migrations
|
||||
./MasterServer -m
|
||||
|
||||
@@ -37,14 +37,15 @@ int main(int argc, char** argv) {
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger();
|
||||
if (!Game::logger) return 0;
|
||||
Game::logger->Log("AuthServer", "Starting Auth server...\n");
|
||||
Game::logger->Log("AuthServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
Game::logger->Log("AuthServer", "Compiled on: %s\n", __TIMESTAMP__);
|
||||
Game::logger->Log("AuthServer", "Starting Auth server...");
|
||||
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
//Read our config:
|
||||
dConfig config("authconfig.ini");
|
||||
Game::config = &config;
|
||||
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
|
||||
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
|
||||
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = config.GetValue("mysql_host");
|
||||
@@ -55,8 +56,8 @@ int main(int argc, char** argv) {
|
||||
try {
|
||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
} catch (sql::SQLException& ex) {
|
||||
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s\n", ex.what());
|
||||
Database::Destroy();
|
||||
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s", ex.what());
|
||||
Database::Destroy("AuthServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
return 0;
|
||||
@@ -97,8 +98,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (framesSinceMasterDisconnect >= 30)
|
||||
break; //Exit our loop, shut down.
|
||||
}
|
||||
else framesSinceMasterDisconnect = 0;
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
//In world we'd update our other systems here.
|
||||
|
||||
@@ -133,8 +133,7 @@ int main(int argc, char** argv) {
|
||||
delete stmt;
|
||||
|
||||
framesSinceLastSQLPing = 0;
|
||||
}
|
||||
else framesSinceLastSQLPing++;
|
||||
} else framesSinceLastSQLPing++;
|
||||
|
||||
//Sleep our thread since auth can afford to.
|
||||
t += std::chrono::milliseconds(mediumFramerate); //Auth can run at a lower "fps"
|
||||
@@ -142,21 +141,24 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//Delete our objects here:
|
||||
Database::Destroy();
|
||||
Database::Destroy("AuthServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
|
||||
return 0;
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
dLogger * SetupLogger() {
|
||||
dLogger* SetupLogger() {
|
||||
std::string logPath = "./logs/AuthServer_" + std::to_string(time(nullptr)) + ".log";
|
||||
bool logToConsole = false;
|
||||
bool logDebugStatements = false;
|
||||
#ifdef _DEBUG
|
||||
logToConsole = true;
|
||||
logDebugStatements = true;
|
||||
#endif
|
||||
|
||||
return new dLogger(logPath, logToConsole);
|
||||
return new dLogger(logPath, logToConsole, logDebugStatements);
|
||||
}
|
||||
|
||||
void HandlePacket(Packet* packet) {
|
||||
|
||||
4
dAuthServer/CMakeLists.txt
Normal file
4
dAuthServer/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(DAUTHSERVER_SOURCES "AuthServer.cpp")
|
||||
|
||||
add_executable(AuthServer ${DAUTHSERVER_SOURCES})
|
||||
target_link_libraries(AuthServer ${COMMON_LIBRARIES})
|
||||
4
dChatFilter/CMakeLists.txt
Normal file
4
dChatFilter/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(DCHATFILTER_SOURCES "dChatFilter.cpp")
|
||||
|
||||
add_library(dChatFilter STATIC ${DCHATFILTER_SOURCES})
|
||||
target_link_libraries(dChatFilter dDatabase)
|
||||
@@ -8,8 +8,9 @@
|
||||
#include <regex>
|
||||
|
||||
#include "dCommonVars.h"
|
||||
#include "Database.h"
|
||||
#include "dLogger.h"
|
||||
#include "dConfig.h"
|
||||
#include "Database.h"
|
||||
#include "Game.h"
|
||||
|
||||
using namespace dChatFilterDCF;
|
||||
@@ -18,11 +19,15 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
||||
m_DontGenerateDCF = dontGenerateDCF;
|
||||
|
||||
if (!BinaryIO::DoesFileExist(filepath + ".dcf") || m_DontGenerateDCF) {
|
||||
ReadWordlistPlaintext(filepath + ".txt");
|
||||
if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf");
|
||||
ReadWordlistPlaintext(filepath + ".txt", true);
|
||||
if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf", true);
|
||||
} else if (!ReadWordlistDCF(filepath + ".dcf", true)) {
|
||||
ReadWordlistPlaintext(filepath + ".txt", true);
|
||||
ExportWordlistToDCF(filepath + ".dcf", true);
|
||||
}
|
||||
else {
|
||||
ReadWordlistDCF(filepath + ".dcf");
|
||||
|
||||
if (BinaryIO::DoesFileExist("blacklist.dcf")) {
|
||||
ReadWordlistDCF("blacklist.dcf", false);
|
||||
}
|
||||
|
||||
//Read player names that are ok as well:
|
||||
@@ -31,65 +36,71 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
||||
while (res->next()) {
|
||||
std::string line = res->getString(1).c_str();
|
||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||
m_Words.push_back(CalculateHash(line));
|
||||
m_ApprovedWords.push_back(CalculateHash(line));
|
||||
}
|
||||
delete res;
|
||||
delete stmt;
|
||||
}
|
||||
|
||||
dChatFilter::~dChatFilter() {
|
||||
m_Words.clear();
|
||||
m_ApprovedWords.clear();
|
||||
m_DeniedWords.clear();
|
||||
}
|
||||
|
||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath) {
|
||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) {
|
||||
std::ifstream file(filepath);
|
||||
if (file) {
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||
m_Words.push_back(CalculateHash(line));
|
||||
if (whiteList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||
else m_DeniedWords.push_back(CalculateHash(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dChatFilter::ReadWordlistDCF(const std::string& filepath) {
|
||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
std::ifstream file(filepath, std::ios::binary);
|
||||
if (file) {
|
||||
fileHeader hdr;
|
||||
BinaryIO::BinaryRead(file, hdr);
|
||||
if (hdr.header != header) {
|
||||
std::cout << "Wrong file header!" << std::endl;
|
||||
file.close();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hdr.formatVersion <= formatVersion) {
|
||||
if (hdr.formatVersion == formatVersion) {
|
||||
size_t wordsToRead = 0;
|
||||
BinaryIO::BinaryRead(file, wordsToRead);
|
||||
m_Words.reserve(wordsToRead);
|
||||
if (whiteList) m_ApprovedWords.reserve(wordsToRead);
|
||||
else m_DeniedWords.reserve(wordsToRead);
|
||||
|
||||
size_t word = 0;
|
||||
for (size_t i = 0; i < wordsToRead; ++i) {
|
||||
BinaryIO::BinaryRead(file, word);
|
||||
m_Words.push_back(word);
|
||||
if (whiteList) m_ApprovedWords.push_back(word);
|
||||
else m_DeniedWords.push_back(word);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Newer file or corrupt" << std::endl;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
file.close();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath) {
|
||||
std::ofstream file(filepath, std::ios::binary);
|
||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) {
|
||||
std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
|
||||
if (file) {
|
||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
||||
BinaryIO::BinaryWrite(file, size_t(m_Words.size()));
|
||||
BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size()));
|
||||
|
||||
for (size_t word : m_Words) {
|
||||
for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) {
|
||||
BinaryIO::BinaryWrite(file, word);
|
||||
}
|
||||
|
||||
@@ -97,31 +108,45 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath) {
|
||||
}
|
||||
}
|
||||
|
||||
bool dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel) {
|
||||
if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return true; //If anything but a forum mod, return true.
|
||||
if (message.empty()) return true;
|
||||
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList) {
|
||||
if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
|
||||
if (message.empty()) return { };
|
||||
if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } };
|
||||
|
||||
std::stringstream sMessage(message);
|
||||
std::string segment;
|
||||
std::regex reg("(!*|\\?*|\\;*|\\.*|\\,*)");
|
||||
|
||||
std::vector<std::pair<uint8_t, uint8_t>> listOfBadSegments = std::vector<std::pair<uint8_t, uint8_t>>();
|
||||
|
||||
uint32_t position = 0;
|
||||
|
||||
while (std::getline(sMessage, segment, ' ')) {
|
||||
std::string originalSegment = segment;
|
||||
|
||||
std::transform(segment.begin(), segment.end(), segment.begin(), ::tolower); //Transform to lowercase
|
||||
segment = std::regex_replace(segment, reg, "");
|
||||
|
||||
size_t hash = CalculateHash(segment);
|
||||
|
||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end()) {
|
||||
return false;
|
||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) {
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
if (!IsInWordlist(hash)) {
|
||||
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) {
|
||||
m_UserUnapprovedWordCache.push_back(hash);
|
||||
return false;
|
||||
}
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
return true;
|
||||
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) {
|
||||
m_UserUnapprovedWordCache.push_back(hash);
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
position += segment.length() + 1;
|
||||
}
|
||||
|
||||
return listOfBadSegments;
|
||||
}
|
||||
|
||||
size_t dChatFilter::CalculateHash(const std::string& word) {
|
||||
@@ -131,7 +156,3 @@ size_t dChatFilter::CalculateHash(const std::string& word) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool dChatFilter::IsInWordlist(size_t word) {
|
||||
return std::find(m_Words.begin(), m_Words.end(), word) != m_Words.end();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace dChatFilterDCF {
|
||||
static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24));
|
||||
static const uint32_t formatVersion = 1;
|
||||
static const uint32_t formatVersion = 2;
|
||||
|
||||
struct fileHeader {
|
||||
uint32_t header;
|
||||
@@ -20,17 +20,17 @@ public:
|
||||
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
||||
~dChatFilter();
|
||||
|
||||
void ReadWordlistPlaintext(const std::string & filepath);
|
||||
void ReadWordlistDCF(const std::string & filepath);
|
||||
void ExportWordlistToDCF(const std::string & filepath);
|
||||
bool IsSentenceOkay(const std::string& message, int gmLevel);
|
||||
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
|
||||
bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
|
||||
void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
|
||||
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true);
|
||||
|
||||
private:
|
||||
bool m_DontGenerateDCF;
|
||||
std::vector<size_t> m_Words;
|
||||
std::vector<size_t> m_DeniedWords;
|
||||
std::vector<size_t> m_ApprovedWords;
|
||||
std::vector<size_t> m_UserUnapprovedWordCache;
|
||||
|
||||
//Private functions:
|
||||
size_t CalculateHash(const std::string& word);
|
||||
bool IsInWordlist(size_t word);
|
||||
};
|
||||
|
||||
6
dChatServer/CMakeLists.txt
Normal file
6
dChatServer/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
set(DCHATSERVER_SOURCES "ChatPacketHandler.cpp"
|
||||
"ChatServer.cpp"
|
||||
"PlayerContainer.cpp")
|
||||
|
||||
add_executable(ChatServer ${DCHATSERVER_SOURCES})
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "dServer.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "dLogger.h"
|
||||
#include "AddFriendResponseCode.h"
|
||||
#include "AddFriendResponseType.h"
|
||||
#include "RakString.h"
|
||||
#include "dConfig.h"
|
||||
|
||||
extern PlayerContainer playerContainer;
|
||||
|
||||
@@ -21,46 +25,42 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
auto player = playerContainer.GetPlayerData(playerID);
|
||||
if (!player) return;
|
||||
|
||||
//Get our friends list from the Db:
|
||||
auto stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE player_id = ? OR friend_id = ?");
|
||||
stmt->setUInt64(1, playerID);
|
||||
stmt->setUInt64(2, playerID);
|
||||
//Get our friends list from the Db. Using a derived table since the friend of a player can be in either column.
|
||||
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
|
||||
"SELECT fr.requested_player, best_friend, ci.name FROM "
|
||||
"(SELECT CASE "
|
||||
"WHEN player_id = ? THEN friend_id "
|
||||
"WHEN friend_id = ? THEN player_id "
|
||||
"END AS requested_player, best_friend FROM friends) AS fr "
|
||||
"JOIN charinfo AS ci ON ci.id = fr.requested_player "
|
||||
"WHERE fr.requested_player IS NOT NULL;"));
|
||||
stmt->setUInt(1, static_cast<uint32_t>(playerID));
|
||||
stmt->setUInt(2, static_cast<uint32_t>(playerID));
|
||||
|
||||
std::vector<FriendData> friends;
|
||||
|
||||
auto res = stmt->executeQuery();
|
||||
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery());
|
||||
while (res->next()) {
|
||||
FriendData fd;
|
||||
fd.isFTP = false; // not a thing in DLU
|
||||
fd.friendID = res->getInt64(1);
|
||||
if (fd.friendID == playerID) fd.friendID = res->getUInt64(2);
|
||||
fd.friendID = res->getUInt(1);
|
||||
GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||
GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||
|
||||
fd.isBestFriend = res->getInt(3) == 2; //0 = friends, 1 = requested, 2 = bffs
|
||||
|
||||
//We need to find their name as well:
|
||||
{
|
||||
auto stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE id=? limit 1");
|
||||
stmt->setInt(1, fd.friendID);
|
||||
|
||||
auto res = stmt->executeQuery();
|
||||
while (res->next()) {
|
||||
fd.friendName = res->getString(1);
|
||||
}
|
||||
|
||||
delete res;
|
||||
delete stmt;
|
||||
}
|
||||
fd.isBestFriend = res->getInt(2) == 3; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs
|
||||
if (fd.isBestFriend) player->countOfBestFriends += 1;
|
||||
fd.friendName = res->getString(3);
|
||||
|
||||
//Now check if they're online:
|
||||
auto fr = playerContainer.GetPlayerData(fd.friendID);
|
||||
|
||||
if (fr) {
|
||||
fd.isOnline = true;
|
||||
fd.zoneID = fr->zoneID;
|
||||
|
||||
//Since this friend is online, we need to update them on the fact that we've just logged in:
|
||||
SendFriendUpdate(fr, player, 1);
|
||||
}
|
||||
else {
|
||||
SendFriendUpdate(fr, player, 1, fd.isBestFriend);
|
||||
} else {
|
||||
fd.isOnline = false;
|
||||
fd.zoneID = LWOZONEID();
|
||||
}
|
||||
@@ -68,9 +68,6 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
friends.push_back(fd);
|
||||
}
|
||||
|
||||
delete res;
|
||||
delete stmt;
|
||||
|
||||
//Now, we need to send the friendlist to the server they came from:
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
@@ -93,20 +90,150 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
auto maxNumberOfBestFriendsAsString = Game::config->GetValue("max_number_of_best_friends");
|
||||
// If this config option doesn't exist, default to 5 which is what live used.
|
||||
auto maxNumberOfBestFriends = maxNumberOfBestFriendsAsString != "" ? std::stoi(maxNumberOfBestFriendsAsString) : 5U;
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
std::string playerName = PacketUtils::ReadString(0x14, packet, true);
|
||||
//There's another bool here to determine if it's a best friend request, but we're not handling it right now.
|
||||
LWOOBJID requestorPlayerID;
|
||||
inStream.Read(requestorPlayerID);
|
||||
inStream.Read(requestorPlayerID);
|
||||
uint32_t spacing{};
|
||||
inStream.Read(spacing);
|
||||
std::string playerName = "";
|
||||
uint16_t character;
|
||||
bool noMoreLettersInName = false;
|
||||
|
||||
//PacketUtils::SavePacket("FriendRequest.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
|
||||
|
||||
//We need to check to see if the player is actually online or not:
|
||||
auto targetData = playerContainer.GetPlayerData(playerName);
|
||||
if (targetData) {
|
||||
SendFriendRequest(targetData, playerContainer.GetPlayerData(playerID));
|
||||
for (uint32_t j = 0; j < 33; j++) {
|
||||
inStream.Read(character);
|
||||
if (character == '\0') noMoreLettersInName = true;
|
||||
if (!noMoreLettersInName) playerName.push_back(static_cast<char>(character));
|
||||
}
|
||||
|
||||
char isBestFriendRequest{};
|
||||
inStream.Read(isBestFriendRequest);
|
||||
|
||||
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
|
||||
std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName));
|
||||
|
||||
// Check if player is online first
|
||||
if (isBestFriendRequest && !requestee) {
|
||||
for (auto friendDataCandidate : requestor->friends) {
|
||||
if (friendDataCandidate.friendName == playerName) {
|
||||
requestee.reset(new PlayerData());
|
||||
// Setup the needed info since you can add a best friend offline.
|
||||
requestee->playerID = friendDataCandidate.friendID;
|
||||
requestee->playerName = friendDataCandidate.friendName;
|
||||
requestee->zoneID = LWOZONEID();
|
||||
|
||||
FriendData requesteeFriendData{};
|
||||
requesteeFriendData.friendID = requestor->playerID;
|
||||
requesteeFriendData.friendName = requestor->playerName;
|
||||
requesteeFriendData.isFTP = false;
|
||||
requesteeFriendData.isOnline = false;
|
||||
requesteeFriendData.zoneID = requestor->zoneID;
|
||||
requestee->friends.push_back(requesteeFriendData);
|
||||
requestee->sysAddr = UNASSIGNED_SYSTEM_ADDRESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If at this point we dont have a target, then they arent online and we cant send the request.
|
||||
// Send the response code that corresponds to what the error is.
|
||||
if (!requestee) {
|
||||
std::unique_ptr<sql::PreparedStatement> nameQuery(Database::CreatePreppedStmt("SELECT name from charinfo where name = ?;"));
|
||||
nameQuery->setString(1, playerName);
|
||||
std::unique_ptr<sql::ResultSet> result(nameQuery->executeQuery());
|
||||
|
||||
requestee.reset(new PlayerData());
|
||||
requestee->playerName = playerName;
|
||||
|
||||
SendFriendResponse(requestor, requestee.get(), result->next() ? AddFriendResponseType::NOTONLINE : AddFriendResponseType::INVALIDCHARACTER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBestFriendRequest) {
|
||||
std::unique_ptr<sql::PreparedStatement> friendUpdate(Database::CreatePreppedStmt("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"));
|
||||
friendUpdate->setUInt(1, static_cast<uint32_t>(requestorPlayerID));
|
||||
friendUpdate->setUInt(2, static_cast<uint32_t>(requestee->playerID));
|
||||
friendUpdate->setUInt(3, static_cast<uint32_t>(requestee->playerID));
|
||||
friendUpdate->setUInt(4, static_cast<uint32_t>(requestorPlayerID));
|
||||
std::unique_ptr<sql::ResultSet> result(friendUpdate->executeQuery());
|
||||
|
||||
LWOOBJID queryPlayerID = LWOOBJID_EMPTY;
|
||||
LWOOBJID queryFriendID = LWOOBJID_EMPTY;
|
||||
uint8_t oldBestFriendStatus{};
|
||||
uint8_t bestFriendStatus{};
|
||||
|
||||
if (result->next()) {
|
||||
// Get the IDs
|
||||
queryPlayerID = result->getInt(1);
|
||||
queryFriendID = result->getInt(2);
|
||||
oldBestFriendStatus = result->getInt(3);
|
||||
bestFriendStatus = oldBestFriendStatus;
|
||||
|
||||
// Set the bits
|
||||
GeneralUtils::SetBit(queryPlayerID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||
GeneralUtils::SetBit(queryPlayerID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||
GeneralUtils::SetBit(queryFriendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||
GeneralUtils::SetBit(queryFriendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||
|
||||
// Since this player can either be the friend of someone else or be friends with someone else
|
||||
// their column in the database determines what bit gets set. When the value hits 3, they
|
||||
// are now best friends with the other player.
|
||||
if (queryPlayerID == requestorPlayerID) {
|
||||
bestFriendStatus |= 1ULL << 0;
|
||||
} else {
|
||||
bestFriendStatus |= 1ULL << 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Only do updates if there was a change in the bff status.
|
||||
if (oldBestFriendStatus != bestFriendStatus) {
|
||||
if (requestee->countOfBestFriends >= maxNumberOfBestFriends || requestor->countOfBestFriends >= maxNumberOfBestFriends) {
|
||||
if (requestee->countOfBestFriends >= maxNumberOfBestFriends) {
|
||||
SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||
}
|
||||
if (requestor->countOfBestFriends >= maxNumberOfBestFriends) {
|
||||
SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::YOURFRIENDSLISTFULL, false);
|
||||
}
|
||||
} else {
|
||||
// Then update the database with this new info.
|
||||
std::unique_ptr<sql::PreparedStatement> updateQuery(Database::CreatePreppedStmt("UPDATE friends SET best_friend = ? WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"));
|
||||
updateQuery->setUInt(1, bestFriendStatus);
|
||||
updateQuery->setUInt(2, static_cast<uint32_t>(requestorPlayerID));
|
||||
updateQuery->setUInt(3, static_cast<uint32_t>(requestee->playerID));
|
||||
updateQuery->setUInt(4, static_cast<uint32_t>(requestee->playerID));
|
||||
updateQuery->setUInt(5, static_cast<uint32_t>(requestorPlayerID));
|
||||
updateQuery->executeUpdate();
|
||||
// Sent the best friend update here if the value is 3
|
||||
if (bestFriendStatus == 3U) {
|
||||
requestee->countOfBestFriends += 1;
|
||||
requestor->countOfBestFriends += 1;
|
||||
if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, AddFriendResponseType::ACCEPTED, false, true);
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::ACCEPTED, false, true);
|
||||
for (auto& friendData : requestor->friends) {
|
||||
if (friendData.friendID == requestee->playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
}
|
||||
}
|
||||
for (auto& friendData : requestee->friends) {
|
||||
if (friendData.friendID == requestor->playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::WAITINGAPPROVAL, true, true);
|
||||
}
|
||||
} else {
|
||||
// Do not send this if we are requesting to be a best friend.
|
||||
SendFriendRequest(requestee.get(), requestor);
|
||||
}
|
||||
|
||||
// If the player is actually a player and not a ghost one defined above, release it from being deleted.
|
||||
if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) requestee.release();
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
@@ -115,29 +242,74 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
|
||||
uint8_t responseCode = packet->data[0x14];
|
||||
AddFriendResponseCode clientResponseCode = static_cast<AddFriendResponseCode>(packet->data[0x14]);
|
||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Friend response code: %i\n", responseCode);
|
||||
|
||||
if (responseCode != 0) return; //If we're not accepting the request, end here, do not insert to friends table.
|
||||
|
||||
PacketUtils::SavePacket("HandleFriendResponse.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
|
||||
|
||||
//Now to try and find both of these:
|
||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
||||
auto goonB = playerContainer.GetPlayerData(friendName);
|
||||
if (!goonA || !goonB) return;
|
||||
auto requestor = playerContainer.GetPlayerData(playerID);
|
||||
auto requestee = playerContainer.GetPlayerData(friendName);
|
||||
if (!requestor || !requestee) return;
|
||||
|
||||
SendFriendResponse(goonB, goonA, responseCode);
|
||||
SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk.
|
||||
AddFriendResponseType serverResponseCode{};
|
||||
uint8_t isAlreadyBestFriends = 0U;
|
||||
// We need to convert this response code to one we can actually send back to the client.
|
||||
switch (clientResponseCode) {
|
||||
case AddFriendResponseCode::ACCEPTED:
|
||||
serverResponseCode = AddFriendResponseType::ACCEPTED;
|
||||
break;
|
||||
case AddFriendResponseCode::BUSY:
|
||||
serverResponseCode = AddFriendResponseType::BUSY;
|
||||
break;
|
||||
case AddFriendResponseCode::CANCELLED:
|
||||
serverResponseCode = AddFriendResponseType::CANCELLED;
|
||||
break;
|
||||
case AddFriendResponseCode::REJECTED:
|
||||
serverResponseCode = AddFriendResponseType::DECLINED;
|
||||
break;
|
||||
}
|
||||
|
||||
auto stmt = Database::CreatePreppedStmt("INSERT INTO `friends`(`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?)");
|
||||
stmt->setUInt64(1, goonA->playerID);
|
||||
stmt->setUInt64(2, goonB->playerID);
|
||||
stmt->setInt(3, 0);
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
// Now that we have handled the base cases, we need to check the other cases.
|
||||
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||
for (auto friendData : requestor->friends) {
|
||||
if (friendData.friendID == requestee->playerID) {
|
||||
serverResponseCode = AddFriendResponseType::ALREADYFRIEND;
|
||||
if (friendData.isBestFriend) {
|
||||
isAlreadyBestFriends = 1U;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This message is NOT sent for best friends and is handled differently for those requests.
|
||||
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||
// Add the each player to the others friend list.
|
||||
FriendData requestorData;
|
||||
requestorData.zoneID = requestor->zoneID;
|
||||
requestorData.friendID = requestor->playerID;
|
||||
requestorData.friendName = requestor->playerName;
|
||||
requestorData.isBestFriend = false;
|
||||
requestorData.isFTP = false;
|
||||
requestorData.isOnline = true;
|
||||
requestee->friends.push_back(requestorData);
|
||||
|
||||
FriendData requesteeData;
|
||||
requesteeData.zoneID = requestee->zoneID;
|
||||
requesteeData.friendID = requestee->playerID;
|
||||
requesteeData.friendName = requestee->playerName;
|
||||
requesteeData.isBestFriend = false;
|
||||
requesteeData.isFTP = false;
|
||||
requesteeData.isOnline = true;
|
||||
requestor->friends.push_back(requesteeData);
|
||||
|
||||
std::unique_ptr<sql::PreparedStatement> statement(Database::CreatePreppedStmt("INSERT IGNORE INTO `friends` (`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?);"));
|
||||
statement->setUInt(1, static_cast<uint32_t>(requestor->playerID));
|
||||
statement->setUInt(2, static_cast<uint32_t>(requestee->playerID));
|
||||
statement->setInt(3, 0);
|
||||
statement->execute();
|
||||
}
|
||||
|
||||
if (serverResponseCode != AddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends);
|
||||
if (serverResponseCode != AddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
@@ -145,56 +317,60 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
std::string friendName = PacketUtils::ReadString(16, packet, true);
|
||||
std::string friendName = PacketUtils::ReadString(0x14, packet, true);
|
||||
|
||||
//we'll have to query the db here to find the user, since you can delete them while they're offline.
|
||||
//First, we need to find their ID:
|
||||
auto stmt = Database::CreatePreppedStmt("select id from charinfo where name=? limit 1;");
|
||||
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? LIMIT 1;"));
|
||||
stmt->setString(1, friendName.c_str());
|
||||
|
||||
LWOOBJID friendID = 0;
|
||||
auto res = stmt->executeQuery();
|
||||
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery());
|
||||
while (res->next()) {
|
||||
friendID = res->getUInt64(1);
|
||||
friendID = res->getUInt(1);
|
||||
}
|
||||
|
||||
delete res;
|
||||
delete stmt;
|
||||
// Convert friendID to LWOOBJID
|
||||
GeneralUtils::SetBit(friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||
GeneralUtils::SetBit(friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||
|
||||
//Set our bits to convert to the BIG BOY objectID.
|
||||
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_CHARACTER);
|
||||
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_PERSISTENT);
|
||||
|
||||
//YEET:
|
||||
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
|
||||
deletestmt->setUInt64(1, playerID);
|
||||
deletestmt->setUInt64(2, friendID);
|
||||
std::unique_ptr<sql::PreparedStatement> deletestmt(Database::CreatePreppedStmt("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"));
|
||||
deletestmt->setUInt(1, static_cast<uint32_t>(playerID));
|
||||
deletestmt->setUInt(2, static_cast<uint32_t>(friendID));
|
||||
deletestmt->setUInt(3, static_cast<uint32_t>(friendID));
|
||||
deletestmt->setUInt(4, static_cast<uint32_t>(playerID));
|
||||
deletestmt->execute();
|
||||
delete deletestmt;
|
||||
|
||||
//because I'm lazy and they can be reversed:
|
||||
{
|
||||
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
|
||||
deletestmt->setUInt64(1, friendID);
|
||||
deletestmt->setUInt64(2, playerID);
|
||||
deletestmt->execute();
|
||||
delete deletestmt;
|
||||
}
|
||||
|
||||
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
|
||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
||||
if (goonA) {
|
||||
// Remove the friend from our list of friends
|
||||
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
|
||||
if ((*friendData).friendID == friendID) {
|
||||
if ((*friendData).isBestFriend) --goonA->countOfBestFriends;
|
||||
goonA->friends.erase(friendData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SendRemoveFriend(goonA, friendName, true);
|
||||
}
|
||||
|
||||
auto goonB = playerContainer.GetPlayerData(friendID);
|
||||
if (!goonB) return;
|
||||
// Do it again for other person
|
||||
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
|
||||
if ((*friendData).friendID == playerID) {
|
||||
if ((*friendData).isBestFriend) --goonB->countOfBestFriends;
|
||||
goonB->friends.erase(friendData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID));
|
||||
SendRemoveFriend(goonB, goonAName, true);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -206,7 +382,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
|
||||
if (playerContainer.GetIsMuted(sender)) return;
|
||||
|
||||
const auto senderName = std::string(sender->playerName.C_String());
|
||||
const auto senderName = std::string(sender->playerName.c_str());
|
||||
|
||||
inStream.SetReadOffset(0x14 * 8);
|
||||
|
||||
@@ -215,9 +391,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
|
||||
std::string message = PacketUtils::ReadString(0x66, packet, true);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str());
|
||||
|
||||
//PacketUtils::SavePacket("chat.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
|
||||
|
||||
if (channel != 8) return;
|
||||
|
||||
@@ -225,13 +399,12 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
|
||||
if (team == nullptr) return;
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = playerContainer.GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == nullptr) return;
|
||||
|
||||
const auto otherName = std::string(otherMember->playerName.C_String());
|
||||
const auto otherName = std::string(otherMember->playerName.c_str());
|
||||
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
@@ -267,8 +440,8 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
|
||||
if (playerContainer.GetIsMuted(goonA)) return;
|
||||
|
||||
std::string goonAName = goonA->playerName.C_String();
|
||||
std::string goonBName = goonB->playerName.C_String();
|
||||
std::string goonAName = goonA->playerName.c_str();
|
||||
std::string goonBName = goonB->playerName.c_str();
|
||||
|
||||
//To the sender:
|
||||
{
|
||||
@@ -317,8 +490,7 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamInvite(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
@@ -327,37 +499,39 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet)
|
||||
|
||||
auto* player = playerContainer.GetPlayerData(playerID);
|
||||
|
||||
if (player == nullptr)
|
||||
{
|
||||
if (player == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team == nullptr)
|
||||
{
|
||||
if (team == nullptr) {
|
||||
team = playerContainer.CreateTeam(playerID);
|
||||
}
|
||||
|
||||
auto* other = playerContainer.GetPlayerData(invitedPlayer);
|
||||
|
||||
if (other == nullptr)
|
||||
{
|
||||
if (other == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerContainer.GetTeam(other->playerID) != nullptr)
|
||||
{
|
||||
if (playerContainer.GetTeam(other->playerID) != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (team->memberIDs.size() > 3) {
|
||||
// no more teams greater than 4
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team");
|
||||
return;
|
||||
}
|
||||
|
||||
SendTeamInvite(other, player);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s\n", playerID, invitedPlayer.c_str());
|
||||
Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -369,33 +543,29 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet)
|
||||
LWOOBJID leaderID = LWOOBJID_EMPTY;
|
||||
inStream.Read(leaderID);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)\n", playerID, leaderID, declined);
|
||||
Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
|
||||
|
||||
if (declined)
|
||||
{
|
||||
if (declined) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* team = playerContainer.GetTeam(leaderID);
|
||||
|
||||
if (team == nullptr)
|
||||
{
|
||||
Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)\n", leaderID);
|
||||
if (team == nullptr) {
|
||||
Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)", leaderID);
|
||||
|
||||
team = playerContainer.GetTeam(playerID);
|
||||
}
|
||||
|
||||
if (team == nullptr)
|
||||
{
|
||||
Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)\n", playerID);
|
||||
if (team == nullptr) {
|
||||
Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)", playerID);
|
||||
return;
|
||||
}
|
||||
|
||||
playerContainer.AddMember(team, playerID);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamLeave(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -405,16 +575,14 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet)
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "(%llu) leaving team\n", playerID);
|
||||
Game::logger->Log("ChatPacketHandler", "(%llu) leaving team", playerID);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
if (team != nullptr) {
|
||||
playerContainer.RemoveMember(team, playerID, false, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamKick(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamKick(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -422,37 +590,30 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet)
|
||||
|
||||
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team\n", playerID, kickedPlayer.c_str());
|
||||
Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
|
||||
|
||||
auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
|
||||
|
||||
LWOOBJID kickedId = LWOOBJID_EMPTY;
|
||||
|
||||
if (kicked != nullptr)
|
||||
{
|
||||
if (kicked != nullptr) {
|
||||
kickedId = kicked->playerID;
|
||||
}
|
||||
else
|
||||
{
|
||||
kickedId = playerContainer.GetId(GeneralUtils::ASCIIToUTF16(kickedPlayer));
|
||||
} else {
|
||||
kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
|
||||
}
|
||||
|
||||
if (kickedId == LWOOBJID_EMPTY) return;
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
if (team != nullptr) {
|
||||
if (team->leaderID != playerID || team->leaderID == kickedId) return;
|
||||
|
||||
playerContainer.RemoveMember(team, kickedId, false, true, false);
|
||||
}
|
||||
|
||||
//PacketUtils::SavePacket("kick.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -460,7 +621,7 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
||||
|
||||
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "(%llu) promiting (%s) to team leader\n", playerID, promotedPlayer.c_str());
|
||||
Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
|
||||
|
||||
auto* promoted = playerContainer.GetPlayerData(promotedPlayer);
|
||||
|
||||
@@ -468,18 +629,14 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
if (team != nullptr) {
|
||||
if (team->leaderID != playerID) return;
|
||||
|
||||
playerContainer.PromoteMember(team, promoted->playerID);
|
||||
}
|
||||
|
||||
//PacketUtils::SavePacket("promote.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -492,8 +649,7 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
if (team != nullptr) {
|
||||
if (team->leaderID != playerID) return;
|
||||
|
||||
team->lootFlag = option;
|
||||
@@ -502,12 +658,9 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
||||
|
||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
|
||||
//PacketUtils::SavePacket("option.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||
{
|
||||
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
@@ -516,46 +669,37 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* data = playerContainer.GetPlayerData(playerID);
|
||||
|
||||
if (team != nullptr && data != nullptr)
|
||||
{
|
||||
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID())
|
||||
{
|
||||
if (team != nullptr && data != nullptr) {
|
||||
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) {
|
||||
playerContainer.RemoveMember(team, playerID, false, false, true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (team->memberIDs.size() <= 1 && !team->local)
|
||||
{
|
||||
if (team->memberIDs.size() <= 1 && !team->local) {
|
||||
playerContainer.DisbandTeam(team);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!team->local)
|
||||
{
|
||||
if (!team->local) {
|
||||
ChatPacketHandler::SendTeamSetLeader(data, team->leaderID);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
playerContainer.TeamStatusUpdate(team);
|
||||
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String()));
|
||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = playerContainer.GetPlayerData(memberId);
|
||||
|
||||
if (memberId == playerID) continue;
|
||||
|
||||
const auto memberName = playerContainer.GetName(memberId);
|
||||
|
||||
//ChatPacketHandler::SendTeamAddPlayer(otherMember, false, false, false, data->playerID, leaderName, data->zoneID);
|
||||
if (otherMember != nullptr)
|
||||
{
|
||||
if (otherMember != nullptr) {
|
||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
||||
}
|
||||
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
||||
@@ -565,8 +709,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||
}
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
@@ -574,21 +717,20 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
|
||||
//portion that will get routed:
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TEAM_INVITE);
|
||||
|
||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
bitStream.Write(sender->playerID);
|
||||
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver->playerID);
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_INVITE_CONFIRM);
|
||||
@@ -601,8 +743,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
|
||||
bitStream.Write(ucNumOfOtherPlayers);
|
||||
bitStream.Write(ucResponseCode);
|
||||
bitStream.Write(static_cast<uint32_t>(wsLeaderName.size()));
|
||||
for (const auto character : wsLeaderName)
|
||||
{
|
||||
for (const auto character : wsLeaderName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
@@ -610,14 +751,13 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver->playerID);
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_GET_STATUS_RESPONSE);
|
||||
@@ -628,8 +768,7 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
|
||||
bitStream.Write(ucLootFlag);
|
||||
bitStream.Write(ucNumOfOtherPlayers);
|
||||
bitStream.Write(static_cast<uint32_t>(wsLeaderName.size()));
|
||||
for (const auto character : wsLeaderName)
|
||||
{
|
||||
for (const auto character : wsLeaderName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
@@ -637,14 +776,13 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver->playerID);
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_LEADER);
|
||||
@@ -655,14 +793,13 @@ void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64Play
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver->playerID);
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_ADD_PLAYER);
|
||||
@@ -672,13 +809,11 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
|
||||
bitStream.Write(bNoLootOnDeath);
|
||||
bitStream.Write(i64PlayerID);
|
||||
bitStream.Write(static_cast<uint32_t>(wsPlayerName.size()));
|
||||
for (const auto character : wsPlayerName)
|
||||
{
|
||||
for (const auto character : wsPlayerName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
bitStream.Write1();
|
||||
if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID())
|
||||
{
|
||||
if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
||||
zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0);
|
||||
}
|
||||
bitStream.Write(zoneID);
|
||||
@@ -687,14 +822,13 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver->playerID);
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_REMOVE_PLAYER);
|
||||
@@ -706,8 +840,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
|
||||
bitStream.Write(i64LeaderID);
|
||||
bitStream.Write(i64PlayerID);
|
||||
bitStream.Write(static_cast<uint32_t>(wsPlayerName.size()));
|
||||
for (const auto character : wsPlayerName)
|
||||
{
|
||||
for (const auto character : wsPlayerName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
@@ -715,21 +848,19 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID)
|
||||
{
|
||||
void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver->playerID);
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_OFF_WORLD_FLAG);
|
||||
|
||||
bitStream.Write(i64PlayerID);
|
||||
if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID())
|
||||
{
|
||||
if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
||||
zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0);
|
||||
}
|
||||
bitStream.Write(zoneID);
|
||||
@@ -738,7 +869,7 @@ void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType) {
|
||||
void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend) {
|
||||
/*chat notification is displayed if log in / out and friend is updated in friends list
|
||||
[u8] - update type
|
||||
Update types
|
||||
@@ -760,35 +891,33 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_UPDATE_FRIEND_NOTIFY);
|
||||
bitStream.Write<uint8_t>(notifyType);
|
||||
|
||||
std::string playerName = playerData->playerName.C_String();
|
||||
std::string playerName = playerData->playerName.c_str();
|
||||
|
||||
PacketUtils::WritePacketWString(playerName, 33, &bitStream);
|
||||
|
||||
bitStream.Write(playerData->zoneID.GetMapID());
|
||||
bitStream.Write(playerData->zoneID.GetInstanceID());
|
||||
|
||||
if (playerData->zoneID.GetCloneID() == friendData->zoneID.GetCloneID())
|
||||
{
|
||||
if (playerData->zoneID.GetCloneID() == friendData->zoneID.GetCloneID()) {
|
||||
bitStream.Write(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
bitStream.Write(playerData->zoneID.GetCloneID());
|
||||
}
|
||||
|
||||
bitStream.Write<uint8_t>(0); //isBFF
|
||||
bitStream.Write<uint8_t>(isBestFriend); //isBFF
|
||||
bitStream.Write<uint8_t>(0); //isFTP
|
||||
|
||||
SystemAddress sysAddr = friendData->sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq) {
|
||||
void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender) {
|
||||
if (!receiver || !sender) return;
|
||||
|
||||
//Make sure people aren't requesting people that they're already friends with:
|
||||
for (auto fr : receiver->friends) {
|
||||
if (fr.friendID == sender->playerID) {
|
||||
SendFriendResponse(sender, receiver, AddFriendResponseType::ALREADYFRIEND, fr.isBestFriend);
|
||||
return; //we have this player as a friend, yeet this function so it doesn't send another request.
|
||||
}
|
||||
}
|
||||
@@ -799,30 +928,34 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send
|
||||
|
||||
//portion that will get routed:
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_REQUEST);
|
||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0);
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
|
||||
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode) {
|
||||
void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
|
||||
if (!receiver || !sender) return;
|
||||
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
// Portion that will get routed:
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE);
|
||||
bitStream.Write<uint8_t>(responseCode);
|
||||
bitStream.Write<uint8_t>(1); //isOnline
|
||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
||||
bitStream.Write(responseCode);
|
||||
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
|
||||
bitStream.Write<uint8_t>(responseCode != AddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||
// Then write the player name
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
// Then if this is an acceptance code, write the following extra info.
|
||||
if (responseCode == AddFriendResponseType::ACCEPTED) {
|
||||
bitStream.Write(sender->playerID);
|
||||
bitStream.Write(sender->zoneID);
|
||||
bitStream.Write<uint8_t>(0); //isBFF
|
||||
bitStream.Write(isBestFriendRequest); //isBFF
|
||||
bitStream.Write<uint8_t>(0); //isFTP
|
||||
|
||||
}
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "BitStream.h"
|
||||
|
||||
struct PlayerData;
|
||||
enum class AddFriendResponseType : uint8_t;
|
||||
|
||||
namespace ChatPacketHandler {
|
||||
void HandleFriendlistRequest(Packet* packet);
|
||||
@@ -31,10 +32,9 @@ namespace ChatPacketHandler {
|
||||
void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
|
||||
|
||||
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
|
||||
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType);
|
||||
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
|
||||
|
||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq = false);
|
||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode = 3);
|
||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
|
||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
||||
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
|
||||
};
|
||||
|
||||
|
||||
@@ -40,14 +40,15 @@ int main(int argc, char** argv) {
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger();
|
||||
if (!Game::logger) return 0;
|
||||
Game::logger->Log("ChatServer", "Starting Chat server...\n");
|
||||
Game::logger->Log("ChatServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
Game::logger->Log("ChatServer", "Compiled on: %s\n", __TIMESTAMP__);
|
||||
Game::logger->Log("ChatServer", "Starting Chat server...");
|
||||
Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
//Read our config:
|
||||
dConfig config("chatconfig.ini");
|
||||
Game::config = &config;
|
||||
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
|
||||
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
|
||||
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = config.GetValue("mysql_host");
|
||||
@@ -57,10 +58,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
try {
|
||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
}
|
||||
catch (sql::SQLException& ex) {
|
||||
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s\n", ex.what());
|
||||
Database::Destroy();
|
||||
} catch (sql::SQLException& ex) {
|
||||
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s", ex.what());
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
return 0;
|
||||
@@ -103,8 +103,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (framesSinceMasterDisconnect >= 30)
|
||||
break; //Exit our loop, shut down.
|
||||
}
|
||||
else framesSinceMasterDisconnect = 0;
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
//In world we'd update our other systems here.
|
||||
|
||||
@@ -121,8 +120,7 @@ int main(int argc, char** argv) {
|
||||
if (framesSinceLastFlush >= 900) {
|
||||
Game::logger->Flush();
|
||||
framesSinceLastFlush = 0;
|
||||
}
|
||||
else framesSinceLastFlush++;
|
||||
} else framesSinceLastFlush++;
|
||||
|
||||
//Every 10 min we ping our sql server to keep it alive hopefully:
|
||||
if (framesSinceLastSQLPing >= 40000) {
|
||||
@@ -140,8 +138,7 @@ int main(int argc, char** argv) {
|
||||
delete stmt;
|
||||
|
||||
framesSinceLastSQLPing = 0;
|
||||
}
|
||||
else framesSinceLastSQLPing++;
|
||||
} else framesSinceLastSQLPing++;
|
||||
|
||||
//Sleep our thread since auth can afford to.
|
||||
t += std::chrono::milliseconds(mediumFramerate); //Chat can run at a lower "fps"
|
||||
@@ -149,30 +146,33 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//Delete our objects here:
|
||||
Database::Destroy();
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
|
||||
return 0;
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
dLogger* SetupLogger() {
|
||||
std::string logPath = "./logs/ChatServer_" + std::to_string(time(nullptr)) + ".log";
|
||||
bool logToConsole = false;
|
||||
bool logDebugStatements = false;
|
||||
#ifdef _DEBUG
|
||||
logToConsole = true;
|
||||
logDebugStatements = true;
|
||||
#endif
|
||||
|
||||
return new dLogger(logPath, logToConsole);
|
||||
return new dLogger(logPath, logToConsole, logDebugStatements);
|
||||
}
|
||||
|
||||
void HandlePacket(Packet* packet) {
|
||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.\n");
|
||||
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.");
|
||||
}
|
||||
|
||||
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.\n");
|
||||
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
|
||||
}
|
||||
|
||||
if (packet->data[1] == CHAT_INTERNAL) {
|
||||
@@ -201,7 +201,7 @@ void HandlePacket(Packet* packet) {
|
||||
}
|
||||
|
||||
default:
|
||||
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i\n", int(packet->data[3]));
|
||||
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ void HandlePacket(Packet* packet) {
|
||||
break;
|
||||
|
||||
case MSG_CHAT_GET_IGNORE_LIST:
|
||||
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.\n");
|
||||
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.");
|
||||
break;
|
||||
|
||||
case MSG_CHAT_TEAM_GET_STATUS:
|
||||
@@ -270,19 +270,19 @@ void HandlePacket(Packet* packet) {
|
||||
break;
|
||||
|
||||
default:
|
||||
Game::logger->Log("ChatServer", "Unknown CHAT id: %i\n", int(packet->data[3]));
|
||||
Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3]));
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->data[1] == WORLD) {
|
||||
switch (packet->data[3]) {
|
||||
case MSG_WORLD_CLIENT_ROUTE_PACKET: {
|
||||
printf("routing packet from world\n");
|
||||
Game::logger->Log("ChatServer", "Routing packet from world");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Game::logger->Log("ChatServer", "Unknown World id: %i\n", int(packet->data[3]));
|
||||
Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,17 +20,25 @@ PlayerContainer::~PlayerContainer() {
|
||||
void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||
CINSTREAM;
|
||||
PlayerData* data = new PlayerData();
|
||||
inStream.SetReadOffset(inStream.GetReadOffset() + 64);
|
||||
inStream.Read(data->playerID);
|
||||
inStream.Read(data->playerID);
|
||||
inStream.Read(data->playerName);
|
||||
|
||||
uint32_t len;
|
||||
inStream.Read<uint32_t>(len);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char character; inStream.Read<char>(character);
|
||||
data->playerName += character;
|
||||
}
|
||||
|
||||
inStream.Read(data->zoneID);
|
||||
inStream.Read(data->muteExpire);
|
||||
data->sysAddr = packet->systemAddress;
|
||||
|
||||
mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String()));
|
||||
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
|
||||
|
||||
mPlayers.insert(std::make_pair(data->playerID, data));
|
||||
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.C_String(), data->playerID, data->zoneID.GetMapID());
|
||||
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
|
||||
|
||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
||||
|
||||
@@ -49,39 +57,32 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
inStream.Read(playerID);
|
||||
|
||||
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
||||
auto player = this->GetPlayerData(playerID);
|
||||
std::unique_ptr<PlayerData> player(this->GetPlayerData(playerID));
|
||||
|
||||
if (player == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& fr : player->friends) {
|
||||
//if (!fr.isOnline) continue;
|
||||
|
||||
auto fd = this->GetPlayerData(fr.friendID);
|
||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0);
|
||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend);
|
||||
}
|
||||
|
||||
auto* team = GetTeam(playerID);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
//TeamStatusUpdate(team);
|
||||
if (team != nullptr) {
|
||||
const auto memberName = GeneralUtils::UTF8ToUTF16(std::string(player->playerName.c_str()));
|
||||
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.C_String()));
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == nullptr) continue;
|
||||
|
||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, {0, 0, 0});
|
||||
//ChatPacketHandler::SendTeamRemovePlayer(otherMember, false, false, true, false, team->leaderID, player->playerID, memberName);
|
||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
|
||||
}
|
||||
}
|
||||
|
||||
Game::logger->Log("PlayerContainer", "Removed user: %llu\n", playerID);
|
||||
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
|
||||
mPlayers.erase(playerID);
|
||||
|
||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
||||
@@ -94,8 +95,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
insertLog->executeUpdate();
|
||||
}
|
||||
|
||||
void PlayerContainer::MuteUpdate(Packet* packet)
|
||||
{
|
||||
void PlayerContainer::MuteUpdate(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID); //skip header
|
||||
@@ -105,9 +105,8 @@ void PlayerContainer::MuteUpdate(Packet* packet)
|
||||
|
||||
auto* player = this->GetPlayerData(playerID);
|
||||
|
||||
if (player == nullptr)
|
||||
{
|
||||
Game::logger->Log("PlayerContainer", "Failed to find user: %llu\n", playerID);
|
||||
if (player == nullptr) {
|
||||
Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -117,8 +116,7 @@ void PlayerContainer::MuteUpdate(Packet* packet)
|
||||
BroadcastMuteUpdate(playerID, expire);
|
||||
}
|
||||
|
||||
void PlayerContainer::CreateTeamServer(Packet* packet)
|
||||
{
|
||||
void PlayerContainer::CreateTeamServer(Packet* packet) {
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID); //skip header
|
||||
@@ -130,8 +128,7 @@ void PlayerContainer::CreateTeamServer(Packet* packet)
|
||||
|
||||
members.reserve(membersSize);
|
||||
|
||||
for (size_t i = 0; i < membersSize; i++)
|
||||
{
|
||||
for (size_t i = 0; i < membersSize; i++) {
|
||||
LWOOBJID member;
|
||||
inStream.Read(member);
|
||||
members.push_back(member);
|
||||
@@ -143,16 +140,14 @@ void PlayerContainer::CreateTeamServer(Packet* packet)
|
||||
|
||||
auto* team = CreateLocalTeam(members);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
if (team != nullptr) {
|
||||
team->zoneId = zoneId;
|
||||
}
|
||||
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
|
||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time)
|
||||
{
|
||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_MUTE_UPDATE);
|
||||
|
||||
@@ -162,30 +157,23 @@ void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time)
|
||||
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
}
|
||||
|
||||
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members)
|
||||
{
|
||||
if (members.empty())
|
||||
{
|
||||
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
|
||||
if (members.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TeamData* newTeam = nullptr;
|
||||
|
||||
for (const auto member : members)
|
||||
{
|
||||
for (const auto member : members) {
|
||||
auto* team = GetTeam(member);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
if (team != nullptr) {
|
||||
RemoveMember(team, member, false, false, true);
|
||||
}
|
||||
|
||||
if (newTeam == nullptr)
|
||||
{
|
||||
if (newTeam == nullptr) {
|
||||
newTeam = CreateTeam(member, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
AddMember(newTeam, member);
|
||||
}
|
||||
}
|
||||
@@ -197,8 +185,7 @@ TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members)
|
||||
return newTeam;
|
||||
}
|
||||
|
||||
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local)
|
||||
{
|
||||
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
||||
auto* team = new TeamData();
|
||||
|
||||
team->teamID = ++mTeamIDCounter;
|
||||
@@ -212,10 +199,8 @@ TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local)
|
||||
return team;
|
||||
}
|
||||
|
||||
TeamData* PlayerContainer::GetTeam(LWOOBJID playerID)
|
||||
{
|
||||
for (auto* team : mTeams)
|
||||
{
|
||||
TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
|
||||
for (auto* team : mTeams) {
|
||||
if (std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID) == team->memberIDs.end()) continue;
|
||||
|
||||
return team;
|
||||
@@ -224,8 +209,7 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
||||
{
|
||||
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
|
||||
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
||||
|
||||
if (index != team->memberIDs.end()) return;
|
||||
@@ -237,30 +221,20 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
||||
|
||||
if (leader == nullptr || member == nullptr) return;
|
||||
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.C_String()));
|
||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
|
||||
const auto memberName = GeneralUtils::UTF8ToUTF16(member->playerName);
|
||||
|
||||
ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName);
|
||||
|
||||
/*
|
||||
ChatPacketHandler::SendTeamAddPlayer(member, false, false, false, leader->playerID, leaderName, leader->zoneID);
|
||||
|
||||
Game::logger->Log("PlayerContainer", "Team invite successfully accepted, leader: %s, member: %s\n", leader->playerName.C_String(), member->playerName.C_String());
|
||||
*/
|
||||
|
||||
if (!team->local)
|
||||
{
|
||||
if (!team->local) {
|
||||
ChatPacketHandler::SendTeamSetLeader(member, leader->playerID);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == member) continue;
|
||||
@@ -269,32 +243,27 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
||||
|
||||
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
||||
|
||||
if (otherMember != nullptr)
|
||||
{
|
||||
if (otherMember != nullptr) {
|
||||
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent)
|
||||
{
|
||||
void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent) {
|
||||
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
||||
|
||||
if (index == team->memberIDs.end()) return;
|
||||
|
||||
auto* member = GetPlayerData(playerID);
|
||||
|
||||
if (member != nullptr && !silent)
|
||||
{
|
||||
if (member != nullptr && !silent) {
|
||||
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
const auto memberName = GetName(playerID);
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
if (silent && memberId == playerID)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
if (silent && memberId == playerID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -309,25 +278,19 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
|
||||
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
|
||||
if (team->memberIDs.size() <= 1)
|
||||
{
|
||||
if (team->memberIDs.size() <= 1) {
|
||||
DisbandTeam(team);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playerID == team->leaderID)
|
||||
{
|
||||
} else {
|
||||
if (playerID == team->leaderID) {
|
||||
PromoteMember(team, team->memberIDs[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader)
|
||||
{
|
||||
void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
|
||||
team->leaderID = newLeader;
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == nullptr) continue;
|
||||
@@ -336,19 +299,17 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader)
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerContainer::DisbandTeam(TeamData* team)
|
||||
{
|
||||
void PlayerContainer::DisbandTeam(TeamData* team) {
|
||||
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
||||
|
||||
if (index == mTeams.end()) return;
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == nullptr) continue;
|
||||
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.C_String()));
|
||||
const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember->playerName);
|
||||
|
||||
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
||||
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName);
|
||||
@@ -361,8 +322,7 @@ void PlayerContainer::DisbandTeam(TeamData* team)
|
||||
delete team;
|
||||
}
|
||||
|
||||
void PlayerContainer::TeamStatusUpdate(TeamData* team)
|
||||
{
|
||||
void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
||||
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
||||
|
||||
if (index == mTeams.end()) return;
|
||||
@@ -371,41 +331,32 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team)
|
||||
|
||||
if (leader == nullptr) return;
|
||||
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == nullptr) continue;
|
||||
|
||||
if (!team->local)
|
||||
{
|
||||
if (!team->local) {
|
||||
ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ChatPacketHandler::SendTeamStatus(otherMember, LWOOBJID_EMPTY, LWOZONEID(0, 0, 0), 1, 0, u"");
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
|
||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam)
|
||||
{
|
||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_TEAM_UPDATE);
|
||||
|
||||
bitStream.Write(team->teamID);
|
||||
bitStream.Write(deleteTeam);
|
||||
|
||||
if (!deleteTeam)
|
||||
{
|
||||
if (!deleteTeam) {
|
||||
bitStream.Write(team->lootFlag);
|
||||
bitStream.Write(static_cast<char>(team->memberIDs.size()));
|
||||
for (const auto memberID : team->memberIDs)
|
||||
{
|
||||
for (const auto memberID : team->memberIDs) {
|
||||
bitStream.Write(memberID);
|
||||
}
|
||||
}
|
||||
@@ -413,8 +364,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam)
|
||||
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
}
|
||||
|
||||
std::u16string PlayerContainer::GetName(LWOOBJID playerID)
|
||||
{
|
||||
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
||||
const auto& pair = mNames.find(playerID);
|
||||
|
||||
if (pair == mNames.end()) return u"";
|
||||
@@ -422,12 +372,9 @@ std::u16string PlayerContainer::GetName(LWOOBJID playerID)
|
||||
return pair->second;
|
||||
}
|
||||
|
||||
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName)
|
||||
{
|
||||
for (const auto& pair : mNames)
|
||||
{
|
||||
if (pair.second == playerName)
|
||||
{
|
||||
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
||||
for (const auto& pair : mNames) {
|
||||
if (pair.second == playerName) {
|
||||
return pair.first;
|
||||
}
|
||||
}
|
||||
@@ -435,7 +382,6 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName)
|
||||
return LWOOBJID_EMPTY;
|
||||
}
|
||||
|
||||
bool PlayerContainer::GetIsMuted(PlayerData* data)
|
||||
{
|
||||
bool PlayerContainer::GetIsMuted(PlayerData* data) {
|
||||
return data->muteExpire == 1 || data->muteExpire > time(NULL);
|
||||
}
|
||||
|
||||
@@ -9,17 +9,18 @@
|
||||
|
||||
struct PlayerData {
|
||||
LWOOBJID playerID;
|
||||
RakNet::RakString playerName;
|
||||
std::string playerName;
|
||||
SystemAddress sysAddr;
|
||||
LWOZONEID zoneID;
|
||||
std::vector<FriendData> friends;
|
||||
time_t muteExpire;
|
||||
uint8_t countOfBestFriends = 0;
|
||||
};
|
||||
|
||||
struct TeamData {
|
||||
LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use
|
||||
LWOOBJID leaderID = LWOOBJID_EMPTY;
|
||||
std::vector<LWOOBJID> memberIDs {};
|
||||
std::vector<LWOOBJID> memberIDs{};
|
||||
uint8_t lootFlag = 0;
|
||||
bool local = false;
|
||||
LWOZONEID zoneId = {};
|
||||
@@ -45,7 +46,7 @@ public:
|
||||
PlayerData* GetPlayerData(const std::string& playerName) {
|
||||
for (auto player : mPlayers) {
|
||||
if (player.second) {
|
||||
std::string pn = player.second->playerName.C_String();
|
||||
std::string pn = player.second->playerName.c_str();
|
||||
if (pn == playerName) return player.second;
|
||||
}
|
||||
}
|
||||
|
||||
160
dCommon/AMFDeserialize.cpp
Normal file
160
dCommon/AMFDeserialize.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "AMFDeserialize.h"
|
||||
|
||||
#include "AMFFormat.h"
|
||||
|
||||
/**
|
||||
* AMF3 Reference document https://rtmp.veriskope.com/pdf/amf3-file-format-spec.pdf
|
||||
* AMF3 Deserializer written by EmosewaMC
|
||||
*/
|
||||
|
||||
AMFValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
|
||||
if (!inStream) return nullptr;
|
||||
AMFValue* returnValue = nullptr;
|
||||
// Read in the value type from the bitStream
|
||||
int8_t marker;
|
||||
inStream->Read(marker);
|
||||
// Based on the typing, create the value associated with that and return the base value class
|
||||
switch (marker) {
|
||||
case AMFValueType::AMFUndefined: {
|
||||
returnValue = new AMFUndefinedValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFNull: {
|
||||
returnValue = new AMFNullValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFFalse: {
|
||||
returnValue = new AMFFalseValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFTrue: {
|
||||
returnValue = new AMFTrueValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFInteger: {
|
||||
returnValue = ReadAmfInteger(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFDouble: {
|
||||
returnValue = ReadAmfDouble(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFString: {
|
||||
returnValue = ReadAmfString(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFValueType::AMFArray: {
|
||||
returnValue = ReadAmfArray(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO We do not need these values, but if someone wants to implement them
|
||||
// then please do so and add the corresponding unit tests.
|
||||
case AMFValueType::AMFXMLDoc:
|
||||
case AMFValueType::AMFDate:
|
||||
case AMFValueType::AMFObject:
|
||||
case AMFValueType::AMFXML:
|
||||
case AMFValueType::AMFByteArray:
|
||||
case AMFValueType::AMFVectorInt:
|
||||
case AMFValueType::AMFVectorUInt:
|
||||
case AMFValueType::AMFVectorDouble:
|
||||
case AMFValueType::AMFVectorObject:
|
||||
case AMFValueType::AMFDictionary: {
|
||||
throw static_cast<AMFValueType>(marker);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw static_cast<AMFValueType>(marker);
|
||||
break;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
|
||||
bool byteFlag = true;
|
||||
uint32_t actualNumber{};
|
||||
uint8_t numberOfBytesRead{};
|
||||
while (byteFlag && numberOfBytesRead < 4) {
|
||||
uint8_t byte{};
|
||||
inStream->Read(byte);
|
||||
// Parse the byte
|
||||
if (numberOfBytesRead < 3) {
|
||||
byteFlag = byte & static_cast<uint8_t>(1 << 7);
|
||||
byte = byte << 1UL;
|
||||
}
|
||||
// Combine the read byte with our current read in number
|
||||
actualNumber <<= 8UL;
|
||||
actualNumber |= static_cast<uint32_t>(byte);
|
||||
// If we are not done reading in bytes, shift right 1 bit
|
||||
if (numberOfBytesRead < 3) actualNumber = actualNumber >> 1UL;
|
||||
numberOfBytesRead++;
|
||||
}
|
||||
return actualNumber;
|
||||
}
|
||||
|
||||
std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
auto length = ReadU29(inStream);
|
||||
// Check if this is a reference
|
||||
bool isReference = length % 2 == 1;
|
||||
// Right shift by 1 bit to get index if reference or size of next string if value
|
||||
length = length >> 1;
|
||||
if (isReference) {
|
||||
std::string value(length, 0);
|
||||
inStream->Read(&value[0], length);
|
||||
// Empty strings are never sent by reference
|
||||
if (!value.empty()) accessedElements.push_back(value);
|
||||
return value;
|
||||
} else {
|
||||
// Length is a reference to a previous index - use that as the read in value
|
||||
return accessedElements[length];
|
||||
}
|
||||
}
|
||||
|
||||
AMFValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
|
||||
auto doubleValue = new AMFDoubleValue();
|
||||
double value;
|
||||
inStream->Read<double>(value);
|
||||
doubleValue->SetDoubleValue(value);
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
|
||||
auto arrayValue = new AMFArrayValue();
|
||||
|
||||
// Read size of dense array
|
||||
auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||
|
||||
// Then read Key'd portion
|
||||
while (true) {
|
||||
auto key = ReadString(inStream);
|
||||
// No more values when we encounter an empty string
|
||||
if (key.size() == 0) break;
|
||||
arrayValue->InsertValue(key, Read(inStream));
|
||||
}
|
||||
|
||||
// Finally read dense portion
|
||||
for (uint32_t i = 0; i < sizeOfDenseArray; i++) {
|
||||
arrayValue->PushBackValue(Read(inStream));
|
||||
}
|
||||
|
||||
return arrayValue;
|
||||
}
|
||||
|
||||
AMFValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
|
||||
auto stringValue = new AMFStringValue();
|
||||
stringValue->SetStringValue(ReadString(inStream));
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
AMFValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
|
||||
auto integerValue = new AMFIntegerValue();
|
||||
integerValue->SetIntegerValue(ReadU29(inStream));
|
||||
return integerValue;
|
||||
}
|
||||
71
dCommon/AMFDeserialize.h
Normal file
71
dCommon/AMFDeserialize.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "BitStream.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class AMFValue;
|
||||
class AMFDeserialize {
|
||||
public:
|
||||
/**
|
||||
* Read an AMF3 value from a bitstream.
|
||||
*
|
||||
* @param inStream inStream to read value from.
|
||||
* @return Returns an AMFValue with all the information from the bitStream in it.
|
||||
*/
|
||||
AMFValue* Read(RakNet::BitStream* inStream);
|
||||
private:
|
||||
/**
|
||||
* @brief Private method to read a U29 integer from a bitstream
|
||||
*
|
||||
* @param inStream bitstream to read data from
|
||||
* @return The number as an unsigned 29 bit integer
|
||||
*/
|
||||
uint32_t ReadU29(RakNet::BitStream* inStream);
|
||||
|
||||
/**
|
||||
* @brief Reads a string from a bitstream
|
||||
*
|
||||
* @param inStream bitStream to read data from
|
||||
* @return The read string
|
||||
*/
|
||||
std::string ReadString(RakNet::BitStream* inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFDouble value from a bitStream
|
||||
*
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Double value represented as an AMFValue
|
||||
*/
|
||||
AMFValue* ReadAmfDouble(RakNet::BitStream* inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFArray from a bitStream
|
||||
*
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Array value represented as an AMFValue
|
||||
*/
|
||||
AMFValue* ReadAmfArray(RakNet::BitStream* inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFString from a bitStream
|
||||
*
|
||||
* @param inStream bitStream to read data from
|
||||
* @return String value represented as an AMFValue
|
||||
*/
|
||||
AMFValue* ReadAmfString(RakNet::BitStream* inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFInteger from a bitStream
|
||||
*
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Integer value represented as an AMFValue
|
||||
*/
|
||||
AMFValue* ReadAmfInteger(RakNet::BitStream* inStream);
|
||||
|
||||
/**
|
||||
* List of strings read so far saved to be read by reference.
|
||||
*/
|
||||
std::vector<std::string> accessedElements;
|
||||
};
|
||||
@@ -108,6 +108,14 @@ _AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() {
|
||||
return this->dense.end();
|
||||
}
|
||||
|
||||
AMFArrayValue::~AMFArrayValue() {
|
||||
for (auto valueToDelete : GetDenseArray()) {
|
||||
if (valueToDelete) delete valueToDelete;
|
||||
}
|
||||
for (auto valueToDelete : GetAssociativeMap()) {
|
||||
if (valueToDelete.second) delete valueToDelete.second;
|
||||
}
|
||||
}
|
||||
|
||||
// AMFObject Constructor
|
||||
AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) {
|
||||
@@ -155,3 +163,9 @@ _AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
|
||||
uint32_t AMFObjectValue::GetTraitArrayCount() {
|
||||
return (uint32_t)this->traits.size();
|
||||
}
|
||||
|
||||
AMFObjectValue::~AMFObjectValue() {
|
||||
for (auto valueToDelete = GetTraitsIteratorBegin(); valueToDelete != GetTraitsIteratorEnd(); valueToDelete++) {
|
||||
if (valueToDelete->second.second) delete valueToDelete->second.second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
\return The AMF value type
|
||||
*/
|
||||
virtual AMFValueType GetValueType() = 0;
|
||||
virtual ~AMFValue() {};
|
||||
};
|
||||
|
||||
//! A typedef for a pointer to an AMF value
|
||||
@@ -233,6 +234,7 @@ public:
|
||||
};
|
||||
|
||||
//! The array value AMF type
|
||||
// This object will manage it's own memory map and list. Do not delete its values.
|
||||
class AMFArrayValue : public AMFValue {
|
||||
private:
|
||||
_AMFArrayMap_ associative; //!< The array map (associative part)
|
||||
@@ -245,6 +247,7 @@ private:
|
||||
AMFValueType GetValueType() { return AMFArray; }
|
||||
|
||||
public:
|
||||
~AMFArrayValue() override;
|
||||
//! Inserts an item into the array map for a specific key
|
||||
/*!
|
||||
\param key The key to set
|
||||
@@ -308,6 +311,18 @@ public:
|
||||
\return Where the iterator ends
|
||||
*/
|
||||
_AMFArrayList_::iterator GetDenseIteratorEnd();
|
||||
|
||||
//! Returns the associative map
|
||||
/*!
|
||||
\return The associative map
|
||||
*/
|
||||
_AMFArrayMap_ GetAssociativeMap() { return this->associative; };
|
||||
|
||||
//! Returns the dense array
|
||||
/*!
|
||||
\return The dense array
|
||||
*/
|
||||
_AMFArrayList_ GetDenseArray() { return this->dense; };
|
||||
};
|
||||
|
||||
//! The anonymous object value AMF type
|
||||
@@ -320,6 +335,7 @@ private:
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFObject; }
|
||||
~AMFObjectValue() override;
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
|
||||
@@ -37,6 +37,12 @@ void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFDouble: {
|
||||
AMFDoubleValue* v = (AMFDoubleValue*)value;
|
||||
this->Write(*v);
|
||||
break;
|
||||
}
|
||||
|
||||
case AMFString: {
|
||||
AMFStringValue* v = (AMFStringValue*)value;
|
||||
this->Write(*v);
|
||||
@@ -56,15 +62,17 @@ void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
|
||||
}
|
||||
|
||||
case AMFArray: {
|
||||
AMFArrayValue* v = (AMFArrayValue*)value;
|
||||
this->Write(*v);
|
||||
this->Write((AMFArrayValue*)value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A private function to write an value to a RakNet::BitStream
|
||||
/**
|
||||
* A private function to write an value to a RakNet::BitStream
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
unsigned char b4 = (unsigned char)v;
|
||||
if (v < 0x00200000) {
|
||||
@@ -102,79 +110,50 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
bs->Write(b4);
|
||||
}
|
||||
|
||||
// Writes a flag number to a RakNet::BitStream
|
||||
/**
|
||||
* Writes a flag number to a RakNet::BitStream
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
||||
v = (v << 1) | 0x01;
|
||||
WriteUInt29(bs, v);
|
||||
}
|
||||
|
||||
// Writes an AMFString to a RakNet::BitStream
|
||||
/**
|
||||
* Writes an AMFString to a RakNet::BitStream
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
|
||||
WriteFlagNumber(bs, (uint32_t)str.size());
|
||||
bs->Write(str.c_str(), (uint32_t)str.size());
|
||||
}
|
||||
|
||||
// Writes an AMF U16 to a RakNet::BitStream
|
||||
/**
|
||||
* Writes an U16 to a bitstream
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
|
||||
unsigned char b2;
|
||||
b2 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
bs->Write((unsigned char)value);
|
||||
bs->Write(b2);
|
||||
bs->Write(value);
|
||||
}
|
||||
|
||||
// Writes an AMF U32 to RakNet::BitStream
|
||||
/**
|
||||
* Writes an U32 to a bitstream
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
|
||||
unsigned char b2;
|
||||
unsigned char b3;
|
||||
unsigned char b4;
|
||||
|
||||
b4 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b3 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b2 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
|
||||
bs->Write((unsigned char)value);
|
||||
bs->Write(b2);
|
||||
bs->Write(b3);
|
||||
bs->Write(b4);
|
||||
bs->Write(value);
|
||||
}
|
||||
|
||||
// Writes an AMF U64 to RakNet::BitStream
|
||||
/**
|
||||
* Writes an U64 to a bitstream
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
|
||||
unsigned char b2;
|
||||
unsigned char b3;
|
||||
unsigned char b4;
|
||||
unsigned char b5;
|
||||
unsigned char b6;
|
||||
unsigned char b7;
|
||||
unsigned char b8;
|
||||
|
||||
b8 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b7 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b6 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b5 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b4 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b3 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
b2 = (unsigned char)value;
|
||||
value = value >> 8;
|
||||
|
||||
bs->Write((unsigned char)value);
|
||||
bs->Write(b2);
|
||||
bs->Write(b3);
|
||||
bs->Write(b4);
|
||||
bs->Write(b5);
|
||||
bs->Write(b6);
|
||||
bs->Write(b7);
|
||||
bs->Write(b8);
|
||||
bs->Write(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +193,7 @@ template<>
|
||||
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value) {
|
||||
this->Write(AMFDouble);
|
||||
double d = value.GetDoubleValue();
|
||||
WriteAMFU64(this, *((unsigned long long*)&d));
|
||||
WriteAMFU64(this, *((unsigned long long*) & d));
|
||||
}
|
||||
|
||||
// Writes an AMFStringValue to BitStream
|
||||
@@ -243,13 +222,13 @@ void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
|
||||
|
||||
// Writes an AMFArrayValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value) {
|
||||
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value) {
|
||||
this->Write(AMFArray);
|
||||
uint32_t denseSize = value.GetDenseValueSize();
|
||||
uint32_t denseSize = value->GetDenseValueSize();
|
||||
WriteFlagNumber(this, denseSize);
|
||||
|
||||
_AMFArrayMap_::iterator it = value.GetAssociativeIteratorValueBegin();
|
||||
_AMFArrayMap_::iterator end = value.GetAssociativeIteratorValueEnd();
|
||||
_AMFArrayMap_::iterator it = value->GetAssociativeIteratorValueBegin();
|
||||
_AMFArrayMap_::iterator end = value->GetAssociativeIteratorValueEnd();
|
||||
|
||||
while (it != end) {
|
||||
WriteAMFString(this, it->first);
|
||||
@@ -260,8 +239,8 @@ void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value) {
|
||||
this->Write(AMFNull);
|
||||
|
||||
if (denseSize > 0) {
|
||||
_AMFArrayList_::iterator it2 = value.GetDenseIteratorBegin();
|
||||
_AMFArrayList_::iterator end2 = value.GetDenseIteratorEnd();
|
||||
_AMFArrayList_::iterator it2 = value->GetDenseIteratorBegin();
|
||||
_AMFArrayList_::iterator end2 = value->GetDenseIteratorEnd();
|
||||
|
||||
while (it2 != end2) {
|
||||
this->Write(*it2);
|
||||
|
||||
@@ -7,86 +7,86 @@
|
||||
#include <BitStream.h>
|
||||
|
||||
/*!
|
||||
\file AMFBitStream.hpp
|
||||
\file AMFFormat_BitStream.h
|
||||
\brief A class that implements native writing of AMF values to RakNet::BitStream
|
||||
*/
|
||||
|
||||
// We are using the RakNet namespace
|
||||
// We are using the RakNet namespace
|
||||
namespace RakNet {
|
||||
//! Writes an AMFValue pointer to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value);
|
||||
|
||||
//! Writes an AMFUndefinedValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value);
|
||||
|
||||
//! Writes an AMFNullValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value);
|
||||
|
||||
//! Writes an AMFFalseValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value);
|
||||
|
||||
//! Writes an AMFTrueValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value);
|
||||
|
||||
//! Writes an AMFIntegerValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value);
|
||||
|
||||
//! Writes an AMFDoubleValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value);
|
||||
|
||||
//! Writes an AMFStringValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value);
|
||||
|
||||
//! Writes an AMFXMLDocValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value);
|
||||
|
||||
//! Writes an AMFDateValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value);
|
||||
|
||||
//! Writes an AMFArrayValue to a RakNet::BitStream
|
||||
/*!
|
||||
\param value The value to write
|
||||
*/
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value);
|
||||
}
|
||||
template <>
|
||||
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value);
|
||||
} // namespace RakNet
|
||||
|
||||
15
dCommon/AddFriendResponseCode.h
Normal file
15
dCommon/AddFriendResponseCode.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __ADDFRIENDRESPONSECODE__H__
|
||||
#define __ADDFRIENDRESPONSECODE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class AddFriendResponseCode : uint8_t {
|
||||
ACCEPTED = 0,
|
||||
REJECTED,
|
||||
BUSY,
|
||||
CANCELLED
|
||||
};
|
||||
|
||||
#endif //!__ADDFRIENDRESPONSECODE__H__
|
||||
24
dCommon/AddFriendResponseType.h
Normal file
24
dCommon/AddFriendResponseType.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __ADDFRIENDRESPONSETYPE__H__
|
||||
#define __ADDFRIENDRESPONSETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class AddFriendResponseType : uint8_t {
|
||||
ACCEPTED = 0,
|
||||
ALREADYFRIEND,
|
||||
INVALIDCHARACTER,
|
||||
GENERALERROR,
|
||||
YOURFRIENDSLISTFULL,
|
||||
THEIRFRIENDLISTFULL,
|
||||
DECLINED,
|
||||
BUSY,
|
||||
NOTONLINE,
|
||||
WAITINGAPPROVAL,
|
||||
MYTHRAN,
|
||||
CANCELLED,
|
||||
FRIENDISFREETRIAL
|
||||
};
|
||||
|
||||
#endif //!__ADDFRIENDRESPONSETYPE__H__
|
||||
@@ -10,7 +10,7 @@ void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outs
|
||||
}
|
||||
|
||||
//For reading null-terminated strings
|
||||
std::string BinaryIO::ReadString(std::ifstream & instream) {
|
||||
std::string BinaryIO::ReadString(std::ifstream& instream) {
|
||||
std::string toReturn;
|
||||
char buffer;
|
||||
|
||||
@@ -37,7 +37,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) {
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
std::string BinaryIO::ReadWString(std::ifstream & instream) {
|
||||
std::string BinaryIO::ReadWString(std::ifstream& instream) {
|
||||
size_t size;
|
||||
BinaryRead(instream, size);
|
||||
//toReturn.resize(size);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace BinaryIO {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::istream & BinaryRead(std::istream& stream, T& value) {
|
||||
std::istream& BinaryRead(std::istream& stream, T& value) {
|
||||
if (!stream.good())
|
||||
printf("bla");
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BinaryIO {
|
||||
}
|
||||
|
||||
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
|
||||
std::string ReadString(std::ifstream & instream);
|
||||
std::string ReadString(std::ifstream& instream);
|
||||
std::string ReadString(std::ifstream& instream, size_t size);
|
||||
std::string ReadWString(std::ifstream& instream);
|
||||
|
||||
|
||||
27
dCommon/CMakeLists.txt
Normal file
27
dCommon/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
set(DCOMMON_SOURCES "AMFFormat.cpp"
|
||||
"AMFDeserialize.cpp"
|
||||
"AMFFormat_BitStream.cpp"
|
||||
"BinaryIO.cpp"
|
||||
"dConfig.cpp"
|
||||
"Diagnostics.cpp"
|
||||
"dLogger.cpp"
|
||||
"GeneralUtils.cpp"
|
||||
"LDFFormat.cpp"
|
||||
"MD5.cpp"
|
||||
"Metrics.cpp"
|
||||
"NiPoint3.cpp"
|
||||
"NiQuaternion.cpp"
|
||||
"SHA512.cpp"
|
||||
"Type.cpp"
|
||||
"ZCompression.cpp")
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
||||
|
||||
add_library(dCommon STATIC ${DCOMMON_SOURCES})
|
||||
|
||||
target_link_libraries(dCommon bcrypt)
|
||||
|
||||
if (UNIX)
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
endif()
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
// If we're on Win32, we'll include our minidump writer
|
||||
#ifdef _WIN32
|
||||
#include <Dbghelp.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Dbghelp.h>
|
||||
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
@@ -141,12 +142,12 @@ void CatchUnhandled(int sig) {
|
||||
demangled = demangle(functionName.c_str());
|
||||
|
||||
if (demangled.empty()) {
|
||||
printf("[%02d] %s\n", i, demangled.c_str());
|
||||
printf("[%02zu] %s\n", i, demangled.c_str());
|
||||
} else {
|
||||
printf("[%02d] %s\n", i, functionName.c_str());
|
||||
printf("[%02zu] %s\n", i, functionName.c_str());
|
||||
}
|
||||
} else {
|
||||
printf("[%02d] %s\n", i, functionName.c_str());
|
||||
printf("[%02zu] %s\n", i, functionName.c_str());
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -170,7 +171,7 @@ void CatchUnhandled(int sig) {
|
||||
ErrorCallback,
|
||||
nullptr);
|
||||
|
||||
struct bt_ctx ctx = {state, 0};
|
||||
struct bt_ctx ctx = { state, 0 };
|
||||
Bt(state);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
template <typename T>
|
||||
inline size_t MinSize(size_t size, const std::basic_string<T>& string) {
|
||||
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
||||
if (size == size_t(-1) || size > string.size()) {
|
||||
return string.size();
|
||||
} else {
|
||||
@@ -24,7 +24,7 @@ inline bool IsTrailSurrogate(char16_t c) {
|
||||
|
||||
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||
if (cp <= 0x007F) {
|
||||
ret.push_back(cp);
|
||||
ret.push_back(static_cast<uint8_t>(cp));
|
||||
} else if (cp <= 0x07FF) {
|
||||
ret.push_back(0xC0 | (cp >> 6));
|
||||
ret.push_back(0x80 | (cp & 0x3F));
|
||||
@@ -42,16 +42,123 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||
|
||||
bool _IsSuffixChar(uint8_t c) {
|
||||
return (c & 0xC0) == 0x80;
|
||||
}
|
||||
|
||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
size_t rem = slice.length();
|
||||
const uint8_t* bytes = (const uint8_t*)&slice.front();
|
||||
if (rem > 0) {
|
||||
uint8_t first = bytes[0];
|
||||
if (first < 0x80) { // 1 byte character
|
||||
out = static_cast<uint32_t>(first & 0x7F);
|
||||
slice.remove_prefix(1);
|
||||
return true;
|
||||
} else if (first < 0xC0) {
|
||||
// middle byte, not valid at start, fall through
|
||||
} else if (first < 0xE0) { // two byte character
|
||||
if (rem > 1) {
|
||||
uint8_t second = bytes[1];
|
||||
if (_IsSuffixChar(second)) {
|
||||
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||
+ static_cast<uint32_t>(second & 0x3F);
|
||||
slice.remove_prefix(2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (first < 0xF0) { // three byte character
|
||||
if (rem > 2) {
|
||||
uint8_t second = bytes[1];
|
||||
uint8_t third = bytes[2];
|
||||
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
||||
+ static_cast<uint32_t>(third & 0x3F);
|
||||
slice.remove_prefix(3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (first < 0xF8) { // four byte character
|
||||
if (rem > 3) {
|
||||
uint8_t second = bytes[1];
|
||||
uint8_t third = bytes[2];
|
||||
uint8_t fourth = bytes[3];
|
||||
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
||||
+ (static_cast<uint32_t>(third & 0x3F) << 6)
|
||||
+ static_cast<uint32_t>(fourth & 0x3F);
|
||||
slice.remove_prefix(4);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
out = static_cast<uint32_t>(REPLACEMENT_CHARACTER);
|
||||
slice.remove_prefix(1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
|
||||
bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
if (output.length() >= size) return false;
|
||||
if (U < 0x10000) {
|
||||
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
||||
output.push_back(static_cast<uint16_t>(U));
|
||||
return true;
|
||||
} else if (U > 0x10FFFF) {
|
||||
output.push_back(REPLACEMENT_CHARACTER);
|
||||
return true;
|
||||
} else if (output.length() + 1 < size) {
|
||||
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
|
||||
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
||||
// represented in 20 bits.
|
||||
uint32_t Ut = U - 0x10000;
|
||||
|
||||
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
||||
// 0xDC00, respectively. These integers each have 10 bits free to
|
||||
// encode the character value, for a total of 20 bits.
|
||||
uint16_t W1 = 0xD800;
|
||||
uint16_t W2 = 0xDC00;
|
||||
|
||||
// Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
|
||||
// bits of W1 and the 10 low-order bits of U' to the 10 low-order
|
||||
// bits of W2.
|
||||
W1 += static_cast<uint16_t>((Ut & 0x3FC00) >> 10);
|
||||
W2 += static_cast<uint16_t>((Ut & 0x3FF) >> 0);
|
||||
|
||||
// Terminate.
|
||||
output.push_back(W1); // high surrogate
|
||||
output.push_back(W2); // low surrogate
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::u16string output;
|
||||
output.reserve(newSize);
|
||||
std::string_view iterator = string;
|
||||
|
||||
uint32_t c;
|
||||
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||
return output;
|
||||
}
|
||||
|
||||
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string& string, size_t size) {
|
||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::u16string ret;
|
||||
ret.reserve(newSize);
|
||||
|
||||
for (size_t i = 0; i < newSize; i++) {
|
||||
char c = string[i];
|
||||
assert(c > 0 && c <= 127);
|
||||
ret.push_back(static_cast<char16_t>(c));
|
||||
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
||||
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -59,7 +166,7 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string& string, size_t size
|
||||
|
||||
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
||||
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string& string, size_t size) {
|
||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::string ret;
|
||||
ret.reserve(newSize);
|
||||
@@ -86,7 +193,7 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string& string, size_t size)
|
||||
}
|
||||
|
||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) {
|
||||
return std::equal(a.begin(), a.end (), b.begin(), b.end(),[](char a, char b) { return tolower(a) == tolower(b); });
|
||||
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
||||
}
|
||||
|
||||
// MARK: Bits
|
||||
@@ -108,14 +215,13 @@ bool GeneralUtils::CheckBit(int64_t value, uint32_t index) {
|
||||
|
||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
||||
size_t start_pos = str.find(from);
|
||||
if(start_pos == std::string::npos)
|
||||
if (start_pos == std::string::npos)
|
||||
return false;
|
||||
str.replace(start_pos, from.length(), to);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter)
|
||||
{
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) {
|
||||
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||
std::wstring current;
|
||||
|
||||
@@ -132,8 +238,7 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char16_t delimiter)
|
||||
{
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char16_t delimiter) {
|
||||
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||
std::u16string current;
|
||||
|
||||
@@ -150,22 +255,17 @@ std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char1
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter)
|
||||
{
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter) {
|
||||
std::vector<std::string> vector = std::vector<std::string>();
|
||||
std::string current = "";
|
||||
|
||||
for (size_t i = 0; i < str.length(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
char c = str[i];
|
||||
|
||||
if (c == delimiter)
|
||||
{
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
current += c;
|
||||
}
|
||||
}
|
||||
@@ -175,7 +275,7 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) {
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
|
||||
uint32_t length;
|
||||
inStream->Read<uint32_t>(length);
|
||||
|
||||
@@ -188,3 +288,52 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) {
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) {
|
||||
std::vector<std::string> names;
|
||||
std::string search_path = folder + "/*.*";
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
names.push_back(fd.cFileName);
|
||||
}
|
||||
} while (::FindNextFile(hFind, &fd));
|
||||
::FindClose(hFind);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) {
|
||||
std::vector<std::string> names;
|
||||
struct dirent* entry;
|
||||
DIR* dir = opendir(folder.c_str());
|
||||
if (dir == NULL) {
|
||||
return names;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
std::string value(entry->d_name, strlen(entry->d_name));
|
||||
if (value == "." || value == "..") {
|
||||
continue;
|
||||
}
|
||||
names.push_back(value);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return names;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
\brief A namespace containing general utility functions
|
||||
*/
|
||||
|
||||
//! The general utils namespace
|
||||
//! The general utils namespace
|
||||
namespace GeneralUtils {
|
||||
//! Converts a plain ASCII string to a UTF-16 string
|
||||
/*!
|
||||
@@ -26,7 +26,18 @@ namespace GeneralUtils {
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\return An UTF-16 representation of the string
|
||||
*/
|
||||
std::u16string ASCIIToUTF16(const std::string& string, size_t size = -1);
|
||||
std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1);
|
||||
|
||||
//! Converts a UTF-8 String to a UTF-16 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\return An UTF-16 representation of the string
|
||||
*/
|
||||
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1);
|
||||
|
||||
//! Internal, do not use
|
||||
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||
|
||||
//! Converts a UTF-16 string to a UTF-8 string
|
||||
/*!
|
||||
@@ -34,7 +45,7 @@ namespace GeneralUtils {
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\return An UTF-8 representation of the string
|
||||
*/
|
||||
std::string UTF16ToWTF8(const std::u16string& string, size_t size = -1);
|
||||
std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1);
|
||||
|
||||
/**
|
||||
* Compares two basic strings but does so ignoring case sensitivity
|
||||
@@ -109,8 +120,7 @@ namespace GeneralUtils {
|
||||
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
|
||||
std::uniform_int_distribution<T> distribution(min, max);
|
||||
return distribution(Game::randomEngine);
|
||||
}
|
||||
else if (std::is_floating_point_v<T>) {
|
||||
} else if (std::is_floating_point_v<T>) {
|
||||
std::uniform_real_distribution<T> distribution(min, max);
|
||||
return distribution(Game::randomEngine);
|
||||
}
|
||||
@@ -120,7 +130,7 @@ namespace GeneralUtils {
|
||||
|
||||
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
std::u16string ReadWString(RakNet::BitStream *inStream);
|
||||
std::u16string ReadWString(RakNet::BitStream* inStream);
|
||||
|
||||
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
|
||||
|
||||
@@ -128,82 +138,70 @@ namespace GeneralUtils {
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
||||
|
||||
std::vector<std::string> GetFileNamesFromFolder(const std::string& folder);
|
||||
|
||||
template <typename T>
|
||||
T Parse(const char* value);
|
||||
|
||||
template <>
|
||||
inline int32_t Parse(const char* value)
|
||||
{
|
||||
inline int32_t Parse(const char* value) {
|
||||
return std::stoi(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64_t Parse(const char* value)
|
||||
{
|
||||
inline int64_t Parse(const char* value) {
|
||||
return std::stoll(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float Parse(const char* value)
|
||||
{
|
||||
inline float Parse(const char* value) {
|
||||
return std::stof(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double Parse(const char* value)
|
||||
{
|
||||
inline double Parse(const char* value) {
|
||||
return std::stod(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t Parse(const char* value)
|
||||
{
|
||||
inline uint32_t Parse(const char* value) {
|
||||
return std::stoul(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint64_t Parse(const char* value)
|
||||
{
|
||||
inline uint64_t Parse(const char* value) {
|
||||
return std::stoull(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TryParse(const char* value, T& dst)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool TryParse(const char* value, T& dst) {
|
||||
try {
|
||||
dst = Parse<T>(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Parse(const std::string& value)
|
||||
{
|
||||
T Parse(const std::string& value) {
|
||||
return Parse<T>(value.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TryParse(const std::string& value, T& dst)
|
||||
{
|
||||
bool TryParse(const std::string& value, T& dst) {
|
||||
return TryParse<T>(value.c_str(), dst);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::u16string to_u16string(T value)
|
||||
{
|
||||
std::u16string to_u16string(T value) {
|
||||
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
||||
}
|
||||
|
||||
// From boost::hash_combine
|
||||
template <class T>
|
||||
void hash_combine(std::size_t& s, const T& v)
|
||||
{
|
||||
void hash_combine(std::size_t& s, const T& v) {
|
||||
std::hash<T> h;
|
||||
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
//! Returns a pointer to a LDFData value based on string format
|
||||
LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
|
||||
LDFBaseData* LDFBaseData::DataFromString(const std::string& format) {
|
||||
|
||||
// First, check the format
|
||||
std::istringstream ssFormat(format);
|
||||
@@ -49,12 +49,12 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
|
||||
|
||||
switch (type) {
|
||||
case LDF_TYPE_UTF_16: {
|
||||
std::u16string data = GeneralUtils::ASCIIToUTF16(dataArray[1]);
|
||||
std::u16string data = GeneralUtils::UTF8ToUTF16(dataArray[1]);
|
||||
return new LDFData<std::u16string>(key, data);
|
||||
}
|
||||
|
||||
case LDF_TYPE_S32: {
|
||||
int32_t data = static_cast<int32_t>(stol(dataArray[1]));
|
||||
int32_t data = static_cast<int32_t>(stoull(dataArray[1]));
|
||||
return new LDFData<int32_t>(key, data);
|
||||
}
|
||||
|
||||
@@ -72,16 +72,11 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
if (dataArray[1] == "true")
|
||||
{
|
||||
if (dataArray[1] == "true") {
|
||||
data = 1;
|
||||
}
|
||||
else if (dataArray[1] == "false")
|
||||
{
|
||||
} else if (dataArray[1] == "false") {
|
||||
data = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
data = static_cast<uint32_t>(stoul(dataArray[1]));
|
||||
}
|
||||
|
||||
@@ -91,16 +86,11 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
|
||||
case LDF_TYPE_BOOLEAN: {
|
||||
bool data;
|
||||
|
||||
if (dataArray[1] == "true")
|
||||
{
|
||||
if (dataArray[1] == "true") {
|
||||
data = true;
|
||||
}
|
||||
else if (dataArray[1] == "false")
|
||||
{
|
||||
} else if (dataArray[1] == "false") {
|
||||
data = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
data = static_cast<bool>(stoi(dataArray[1]));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
\brief A collection of LDF format classes
|
||||
*/
|
||||
|
||||
//! An enum for LDF Data Types
|
||||
//! An enum for LDF Data Types
|
||||
enum eLDFType {
|
||||
LDF_TYPE_UNKNOWN = -1, //!< Unknown data type
|
||||
LDF_TYPE_UTF_16 = 0, //!< UTF-16 wstring data type
|
||||
@@ -36,13 +36,13 @@ class LDFBaseData {
|
||||
public:
|
||||
|
||||
//! Destructor
|
||||
virtual ~LDFBaseData(void) { }
|
||||
virtual ~LDFBaseData(void) {}
|
||||
|
||||
//! Writes the data to a packet
|
||||
/*!
|
||||
\param packet The packet
|
||||
*/
|
||||
virtual void WriteToPacket(RakNet::BitStream * packet) = 0;
|
||||
virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
|
||||
|
||||
//! Gets the key
|
||||
/*!
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
|
||||
virtual std::string GetValueAsString() = 0;
|
||||
|
||||
virtual LDFBaseData * Copy() = 0;
|
||||
virtual LDFBaseData* Copy() = 0;
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
/*!
|
||||
\param format The format
|
||||
*/
|
||||
static LDFBaseData * DataFromString(const std::string& format);
|
||||
static LDFBaseData* DataFromString(const std::string& format);
|
||||
|
||||
};
|
||||
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
T value;
|
||||
|
||||
//! Writes the key to the packet
|
||||
void WriteKey(RakNet::BitStream * packet) {
|
||||
void WriteKey(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->key.length() * sizeof(uint16_t)));
|
||||
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
||||
packet->Write(static_cast<uint16_t>(this->key[i]));
|
||||
@@ -94,7 +94,7 @@ private:
|
||||
}
|
||||
|
||||
//! Writes the value to the packet
|
||||
void WriteValue(RakNet::BitStream * packet) {
|
||||
void WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
packet->Write(this->value);
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
~LDFData(void) override { }
|
||||
~LDFData(void) override {}
|
||||
|
||||
//! Gets the value
|
||||
/*!
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
/*!
|
||||
\param packet The packet
|
||||
*/
|
||||
void WriteToPacket(RakNet::BitStream * packet) override {
|
||||
void WriteToPacket(RakNet::BitStream* packet) override {
|
||||
this->WriteKey(packet);
|
||||
this->WriteValue(packet);
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
return this->GetValueString();
|
||||
}
|
||||
|
||||
LDFBaseData * Copy() override {
|
||||
LDFBaseData* Copy() override {
|
||||
return new LDFData<T>(key, value);
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
|
||||
|
||||
// The specialized version for std::u16string (UTF-16)
|
||||
template<>
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream * packet) {
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
|
||||
packet->Write(static_cast<uint32_t>(this->value.length()));
|
||||
@@ -217,7 +217,7 @@ inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream * packet) {
|
||||
|
||||
// The specialized version for bool
|
||||
template<>
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream * packet) {
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
|
||||
packet->Write(static_cast<uint8_t>(this->value));
|
||||
@@ -225,7 +225,7 @@ inline void LDFData<bool>::WriteValue(RakNet::BitStream * packet) {
|
||||
|
||||
// The specialized version for std::string (UTF-8)
|
||||
template<>
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream * packet) {
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
|
||||
packet->Write(static_cast<uint32_t>(this->value.length()));
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
*/
|
||||
|
||||
/* interface header */
|
||||
/* interface header */
|
||||
#include "MD5.h"
|
||||
|
||||
/* system implementation headers */
|
||||
@@ -59,15 +59,15 @@
|
||||
|
||||
// F, G, H and I are basic MD5 functions.
|
||||
inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
|
||||
return x&y | ~x&z;
|
||||
return x & y | ~x & z;
|
||||
}
|
||||
|
||||
inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
|
||||
return x&z | y&~z;
|
||||
return x & z | y & ~z;
|
||||
}
|
||||
|
||||
inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
|
||||
return x^y^z;
|
||||
return x ^ y ^ z;
|
||||
}
|
||||
|
||||
inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
|
||||
@@ -81,35 +81,33 @@ inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
|
||||
|
||||
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
// Rotation is separate from addition to prevent recomputation.
|
||||
inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + F(b, c, d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + G(b, c, d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + H(b, c, d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||
a = rotate_left(a + I(b, c, d) + x + ac, s) + b;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
// default ctor, just initailize
|
||||
MD5::MD5()
|
||||
{
|
||||
MD5::MD5() {
|
||||
init();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
// nifty shortcut ctor, compute MD5 for string and finalize it right away
|
||||
MD5::MD5(const std::string &text)
|
||||
{
|
||||
MD5::MD5(const std::string& text) {
|
||||
init();
|
||||
update(text.c_str(), text.length());
|
||||
finalize();
|
||||
@@ -117,8 +115,7 @@ MD5::MD5(const std::string &text)
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
void MD5::init()
|
||||
{
|
||||
void MD5::init() {
|
||||
finalized = false;
|
||||
|
||||
count[0] = 0;
|
||||
@@ -134,8 +131,7 @@ void MD5::init()
|
||||
//////////////////////////////
|
||||
|
||||
// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
|
||||
void MD5::decode(uint4 output[], const uint1 input[], size_type len)
|
||||
{
|
||||
void MD5::decode(uint4 output[], const uint1 input[], size_type len) {
|
||||
for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((uint4)input[j]) | (((uint4)input[j + 1]) << 8) |
|
||||
(((uint4)input[j + 2]) << 16) | (((uint4)input[j + 3]) << 24);
|
||||
@@ -145,8 +141,7 @@ void MD5::decode(uint4 output[], const uint1 input[], size_type len)
|
||||
|
||||
// encodes input (uint4) into output (unsigned char). Assumes len is
|
||||
// a multiple of 4.
|
||||
void MD5::encode(uint1 output[], const uint4 input[], size_type len)
|
||||
{
|
||||
void MD5::encode(uint1 output[], const uint4 input[], size_type len) {
|
||||
for (size_type i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = input[i] & 0xff;
|
||||
output[j + 1] = (input[i] >> 8) & 0xff;
|
||||
@@ -158,8 +153,7 @@ void MD5::encode(uint1 output[], const uint4 input[], size_type len)
|
||||
//////////////////////////////
|
||||
|
||||
// apply MD5 algo on a block
|
||||
void MD5::transform(const uint1 block[blocksize])
|
||||
{
|
||||
void MD5::transform(const uint1 block[blocksize]) {
|
||||
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
decode(x, block, blocksize);
|
||||
|
||||
@@ -248,8 +242,7 @@ void MD5::transform(const uint1 block[blocksize])
|
||||
|
||||
// MD5 block update operation. Continues an MD5 message-digest
|
||||
// operation, processing another message block
|
||||
void MD5::update(const unsigned char input[], size_type length)
|
||||
{
|
||||
void MD5::update(const unsigned char input[], size_type length) {
|
||||
// compute number of bytes mod 64
|
||||
size_type index = count[0] / 8 % blocksize;
|
||||
|
||||
@@ -264,8 +257,7 @@ void MD5::update(const unsigned char input[], size_type length)
|
||||
size_type i;
|
||||
|
||||
// transform as many times as possible.
|
||||
if (length >= firstpart)
|
||||
{
|
||||
if (length >= firstpart) {
|
||||
// fill buffer first, transform
|
||||
memcpy(&buffer[index], input, firstpart);
|
||||
transform(buffer);
|
||||
@@ -275,8 +267,7 @@ void MD5::update(const unsigned char input[], size_type length)
|
||||
transform(&input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
} else
|
||||
i = 0;
|
||||
|
||||
// buffer remaining input
|
||||
@@ -286,8 +277,7 @@ void MD5::update(const unsigned char input[], size_type length)
|
||||
//////////////////////////////
|
||||
|
||||
// for convenience provide a verson with signed char
|
||||
void MD5::update(const char input[], size_type length)
|
||||
{
|
||||
void MD5::update(const char input[], size_type length) {
|
||||
update((const unsigned char*)input, length);
|
||||
}
|
||||
|
||||
@@ -295,8 +285,7 @@ void MD5::update(const char input[], size_type length)
|
||||
|
||||
// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
// the message digest and zeroizing the context.
|
||||
MD5& MD5::finalize()
|
||||
{
|
||||
MD5& MD5::finalize() {
|
||||
static unsigned char padding[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -332,13 +321,12 @@ MD5& MD5::finalize()
|
||||
//////////////////////////////
|
||||
|
||||
// return hex representation of digest as string
|
||||
std::string MD5::hexdigest() const
|
||||
{
|
||||
std::string MD5::hexdigest() const {
|
||||
if (!finalized)
|
||||
return "";
|
||||
|
||||
char buf[33];
|
||||
for (int i = 0; i<16; i++)
|
||||
for (int i = 0; i < 16; i++)
|
||||
sprintf(buf + i * 2, "%02x", digest[i]);
|
||||
buf[32] = 0;
|
||||
|
||||
@@ -347,15 +335,13 @@ std::string MD5::hexdigest() const
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, MD5 md5)
|
||||
{
|
||||
std::ostream& operator<<(std::ostream& out, MD5 md5) {
|
||||
return out << md5.hexdigest();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
std::string md5(const std::string str)
|
||||
{
|
||||
std::string md5(const std::string str) {
|
||||
MD5 md5 = MD5(str);
|
||||
|
||||
return md5.hexdigest();
|
||||
|
||||
@@ -37,16 +37,16 @@
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// a small class for calculating MD5 hashes of strings or byte arrays
|
||||
// it is not meant to be fast or secure
|
||||
//
|
||||
// usage: 1) feed it blocks of uchars with update()
|
||||
// 2) finalize()
|
||||
// 3) get hexdigest() string
|
||||
// or
|
||||
// MD5(std::string).hexdigest()
|
||||
//
|
||||
// assumes that char is 8 bit and int is 32 bit
|
||||
// a small class for calculating MD5 hashes of strings or byte arrays
|
||||
// it is not meant to be fast or secure
|
||||
//
|
||||
// usage: 1) feed it blocks of uchars with update()
|
||||
// 2) finalize()
|
||||
// 3) get hexdigest() string
|
||||
// or
|
||||
// MD5(std::string).hexdigest()
|
||||
//
|
||||
// assumes that char is 8 bit and int is 32 bit
|
||||
class MD5
|
||||
{
|
||||
public:
|
||||
@@ -54,8 +54,8 @@ public:
|
||||
|
||||
MD5();
|
||||
MD5(const std::string& text);
|
||||
void update(const unsigned char *buf, size_type length);
|
||||
void update(const char *buf, size_type length);
|
||||
void update(const unsigned char* buf, size_type length);
|
||||
void update(const char* buf, size_type length);
|
||||
MD5& finalize();
|
||||
std::string hexdigest() const;
|
||||
friend std::ostream& operator<<(std::ostream&, MD5 md5);
|
||||
@@ -82,10 +82,10 @@ private:
|
||||
static inline uint4 H(uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 I(uint4 x, uint4 y, uint4 z);
|
||||
static inline uint4 rotate_left(uint4 x, int n);
|
||||
static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
static inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||
};
|
||||
|
||||
std::string md5(const std::string str);
|
||||
|
||||
@@ -14,57 +14,49 @@ std::vector<MetricVariable> Metrics::m_Variables = {
|
||||
MetricVariable::CPUTime,
|
||||
MetricVariable::Sleep,
|
||||
MetricVariable::Frame,
|
||||
#ifdef BUILD_VISUAL_DEBUGGER
|
||||
MetricVariable::VisualDebugger,
|
||||
#endif
|
||||
};
|
||||
|
||||
void Metrics::AddMeasurement(MetricVariable variable, int64_t value)
|
||||
{
|
||||
void Metrics::AddMeasurement(MetricVariable variable, int64_t value) {
|
||||
const auto& iter = m_Metrics.find(variable);
|
||||
|
||||
Metric* metric;
|
||||
|
||||
if (iter == m_Metrics.end())
|
||||
{
|
||||
if (iter == m_Metrics.end()) {
|
||||
metric = new Metric();
|
||||
|
||||
m_Metrics[variable] = metric;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
metric = iter->second;
|
||||
}
|
||||
|
||||
AddMeasurement(metric, value);
|
||||
}
|
||||
|
||||
void Metrics::AddMeasurement(Metric* metric, int64_t value)
|
||||
{
|
||||
void Metrics::AddMeasurement(Metric* metric, int64_t value) {
|
||||
const auto index = metric->measurementIndex;
|
||||
|
||||
metric->measurements[index] = value;
|
||||
|
||||
if (metric->max == -1 || value > metric->max)
|
||||
{
|
||||
if (metric->max == -1 || value > metric->max) {
|
||||
metric->max = value;
|
||||
}
|
||||
else if (metric->min == -1 || metric->min > value)
|
||||
{
|
||||
} else if (metric->min == -1 || metric->min > value) {
|
||||
metric->min = value;
|
||||
}
|
||||
|
||||
if (metric->measurementSize < MAX_MEASURMENT_POINTS)
|
||||
{
|
||||
if (metric->measurementSize < MAX_MEASURMENT_POINTS) {
|
||||
metric->measurementSize++;
|
||||
}
|
||||
|
||||
metric->measurementIndex = (index + 1) % MAX_MEASURMENT_POINTS;
|
||||
}
|
||||
|
||||
const Metric* Metrics::GetMetric(MetricVariable variable)
|
||||
{
|
||||
const Metric* Metrics::GetMetric(MetricVariable variable) {
|
||||
const auto& iter = m_Metrics.find(variable);
|
||||
|
||||
if (iter == m_Metrics.end())
|
||||
{
|
||||
if (iter == m_Metrics.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -72,8 +64,7 @@ const Metric* Metrics::GetMetric(MetricVariable variable)
|
||||
|
||||
int64_t average = 0;
|
||||
|
||||
for (size_t i = 0; i < metric->measurementSize; i++)
|
||||
{
|
||||
for (size_t i = 0; i < metric->measurementSize; i++) {
|
||||
average += metric->measurements[i];
|
||||
}
|
||||
|
||||
@@ -84,34 +75,28 @@ const Metric* Metrics::GetMetric(MetricVariable variable)
|
||||
return metric;
|
||||
}
|
||||
|
||||
void Metrics::StartMeasurement(MetricVariable variable)
|
||||
{
|
||||
void Metrics::StartMeasurement(MetricVariable variable) {
|
||||
const auto& iter = m_Metrics.find(variable);
|
||||
|
||||
Metric* metric;
|
||||
|
||||
if (iter == m_Metrics.end())
|
||||
{
|
||||
if (iter == m_Metrics.end()) {
|
||||
metric = new Metric();
|
||||
|
||||
m_Metrics[variable] = metric;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
metric = iter->second;
|
||||
}
|
||||
|
||||
metric->activeMeasurement = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void Metrics::EndMeasurement(MetricVariable variable)
|
||||
{
|
||||
void Metrics::EndMeasurement(MetricVariable variable) {
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
|
||||
const auto& iter = m_Metrics.find(variable);
|
||||
|
||||
if (iter == m_Metrics.end())
|
||||
{
|
||||
if (iter == m_Metrics.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,15 +109,12 @@ void Metrics::EndMeasurement(MetricVariable variable)
|
||||
AddMeasurement(metric, nanoseconds);
|
||||
}
|
||||
|
||||
float Metrics::ToMiliseconds(int64_t nanoseconds)
|
||||
{
|
||||
return (float) nanoseconds / 1e6;
|
||||
float Metrics::ToMiliseconds(int64_t nanoseconds) {
|
||||
return (float)nanoseconds / 1e6;
|
||||
}
|
||||
|
||||
std::string Metrics::MetricVariableToString(MetricVariable variable)
|
||||
{
|
||||
switch (variable)
|
||||
{
|
||||
std::string Metrics::MetricVariableToString(MetricVariable variable) {
|
||||
switch (variable) {
|
||||
case MetricVariable::GameLoop:
|
||||
return "GameLoop";
|
||||
case MetricVariable::PacketHandling:
|
||||
@@ -153,21 +135,21 @@ std::string Metrics::MetricVariableToString(MetricVariable variable)
|
||||
return "Frame";
|
||||
case MetricVariable::Ghosting:
|
||||
return "Ghosting";
|
||||
|
||||
#ifdef BUILD_VISUAL_DEBUGGER
|
||||
case MetricVariable::VisualDebugger:
|
||||
return "VisualDebugger";
|
||||
#endif
|
||||
default:
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<MetricVariable>& Metrics::GetAllMetrics()
|
||||
{
|
||||
const std::vector<MetricVariable>& Metrics::GetAllMetrics() {
|
||||
return m_Variables;
|
||||
}
|
||||
|
||||
void Metrics::Clear()
|
||||
{
|
||||
for (const auto& pair : m_Metrics)
|
||||
{
|
||||
void Metrics::Clear() {
|
||||
for (const auto& pair : m_Metrics) {
|
||||
delete pair.second;
|
||||
}
|
||||
|
||||
@@ -207,37 +189,35 @@ void Metrics::Clear()
|
||||
#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
|
||||
#endif
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the peak (maximum so far) resident set size (physical
|
||||
* memory use) measured in bytes, or zero if the value cannot be
|
||||
* determined on this OS.
|
||||
*/
|
||||
size_t Metrics::GetPeakRSS()
|
||||
{
|
||||
size_t Metrics::GetPeakRSS() {
|
||||
#if defined(_WIN32)
|
||||
/* Windows -------------------------------------------------- */
|
||||
PROCESS_MEMORY_COUNTERS info;
|
||||
GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||
return (size_t)info.PeakWorkingSetSize;
|
||||
|
||||
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
|
||||
/* AIX and Solaris ------------------------------------------ */
|
||||
struct psinfo psinfo;
|
||||
int fd = -1;
|
||||
if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
|
||||
if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
|
||||
return (size_t)0L; /* Can't open? */
|
||||
if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
|
||||
{
|
||||
close( fd );
|
||||
if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
|
||||
close(fd);
|
||||
return (size_t)0L; /* Can't read? */
|
||||
}
|
||||
close( fd );
|
||||
close(fd);
|
||||
return (size_t)(psinfo.pr_rssize * 1024L);
|
||||
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||
/* BSD, Linux, and OSX -------------------------------------- */
|
||||
struct rusage rusage;
|
||||
getrusage( RUSAGE_SELF, &rusage );
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
return (size_t)rusage.ru_maxrss;
|
||||
#else
|
||||
@@ -255,20 +235,19 @@ size_t Metrics::GetPeakRSS()
|
||||
* Returns the current resident set size (physical memory use) measured
|
||||
* in bytes, or zero if the value cannot be determined on this OS.
|
||||
*/
|
||||
size_t Metrics::GetCurrentRSS()
|
||||
{
|
||||
size_t Metrics::GetCurrentRSS() {
|
||||
#if defined(_WIN32)
|
||||
/* Windows -------------------------------------------------- */
|
||||
PROCESS_MEMORY_COUNTERS info;
|
||||
GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||
return (size_t)info.WorkingSetSize;
|
||||
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
/* OSX ------------------------------------------------------ */
|
||||
struct mach_task_basic_info info;
|
||||
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
||||
if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
|
||||
(task_info_t)&info, &infoCount ) != KERN_SUCCESS )
|
||||
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
|
||||
(task_info_t)&info, &infoCount) != KERN_SUCCESS)
|
||||
return (size_t)0L; /* Can't access? */
|
||||
return (size_t)info.resident_size;
|
||||
|
||||
@@ -276,15 +255,14 @@ size_t Metrics::GetCurrentRSS()
|
||||
/* Linux ---------------------------------------------------- */
|
||||
long rss = 0L;
|
||||
FILE* fp = NULL;
|
||||
if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
|
||||
if ((fp = fopen("/proc/self/statm", "r")) == NULL)
|
||||
return (size_t)0L; /* Can't open? */
|
||||
if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
|
||||
{
|
||||
fclose( fp );
|
||||
if (fscanf(fp, "%*s%ld", &rss) != 1) {
|
||||
fclose(fp);
|
||||
return (size_t)0L; /* Can't read? */
|
||||
}
|
||||
fclose( fp );
|
||||
return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
|
||||
fclose(fp);
|
||||
return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
|
||||
|
||||
#else
|
||||
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
|
||||
@@ -293,8 +271,7 @@ size_t Metrics::GetCurrentRSS()
|
||||
|
||||
}
|
||||
|
||||
size_t Metrics::GetProcessID()
|
||||
{
|
||||
size_t Metrics::GetProcessID() {
|
||||
#if defined(_WIN32)
|
||||
return GetCurrentProcessId();
|
||||
#else
|
||||
|
||||
@@ -20,6 +20,9 @@ enum class MetricVariable : int32_t
|
||||
CPUTime,
|
||||
Sleep,
|
||||
Frame,
|
||||
#ifdef BUILD_VISUAL_DEBUGGER
|
||||
VisualDebugger
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Metric
|
||||
|
||||
@@ -71,36 +71,31 @@ void NiPoint3::SetZ(float z) {
|
||||
|
||||
//! Gets the length of the vector
|
||||
float NiPoint3::Length(void) const {
|
||||
return sqrt(x*x + y*y + z*z);
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
//! Gets the squared length of a vector
|
||||
float NiPoint3::SquaredLength(void) const {
|
||||
return (x*x + y*y + z*z);
|
||||
return (x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
//! Returns the dot product of the vector dotted with another vector
|
||||
float NiPoint3::DotProduct(const Vector3& vec) const {
|
||||
float NiPoint3::DotProduct(const NiPoint3& vec) const {
|
||||
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
|
||||
}
|
||||
|
||||
//! Returns the cross product of the vector crossed with another vector
|
||||
Vector3 NiPoint3::CrossProduct(const Vector3& vec) const {
|
||||
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
|
||||
NiPoint3 NiPoint3::CrossProduct(const NiPoint3& vec) const {
|
||||
return NiPoint3(((this->y * vec.z) - (this->z * vec.y)),
|
||||
((this->z * vec.x) - (this->x * vec.z)),
|
||||
((this->x * vec.y) - (this->y * vec.x)));
|
||||
}
|
||||
|
||||
//! Unitize the vector
|
||||
NiPoint3 NiPoint3::Unitize(void) const {
|
||||
NiPoint3 unitVec;
|
||||
float length = this->Length();
|
||||
|
||||
unitVec.x = length != 0 ? this->x / length : 0;
|
||||
unitVec.y = length != 0 ? this->y / length : 0;
|
||||
unitVec.z = length != 0 ? this->z / length : 0;
|
||||
|
||||
return unitVec;
|
||||
return length != 0 ? *this / length : NiPoint3::ZERO;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,13 +113,13 @@ bool NiPoint3::operator!=(const NiPoint3& point) const {
|
||||
|
||||
//! Operator for subscripting
|
||||
float& NiPoint3::operator[](int i) {
|
||||
float * base = &x;
|
||||
float* base = &x;
|
||||
return (float&)base[i];
|
||||
}
|
||||
|
||||
//! Operator for subscripting
|
||||
const float& NiPoint3::operator[](int i) const {
|
||||
const float * base = &x;
|
||||
const float* base = &x;
|
||||
return (float&)base[i];
|
||||
}
|
||||
|
||||
@@ -171,17 +166,16 @@ bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3&
|
||||
if (this->y < minPoint.y) return false;
|
||||
if (this->y > maxPoint.y) return false;
|
||||
|
||||
return (this->z < maxPoint.z && this->z > minPoint.z);
|
||||
return (this->z < maxPoint.z&& this->z > minPoint.z);
|
||||
}
|
||||
|
||||
//! Checks to see if the point (or vector) is within a sphere
|
||||
bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) {
|
||||
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
|
||||
NiPoint3 diffVec = NiPoint3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
|
||||
return (diffVec.SquaredLength() <= (radius * radius));
|
||||
}
|
||||
|
||||
NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p)
|
||||
{
|
||||
NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) {
|
||||
if (a == b) return a;
|
||||
|
||||
const auto pa = p - a;
|
||||
@@ -196,16 +190,14 @@ NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, cons
|
||||
return a + ab * t;
|
||||
}
|
||||
|
||||
float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b)
|
||||
{
|
||||
float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) {
|
||||
const auto dot = a.DotProduct(b);
|
||||
const auto lenA = a.SquaredLength();
|
||||
const auto lenB = a.SquaredLength();
|
||||
return acos(dot / sqrt(lenA * lenB));
|
||||
}
|
||||
|
||||
float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b)
|
||||
{
|
||||
float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) {
|
||||
const auto dx = a.x - b.x;
|
||||
const auto dy = a.y - b.y;
|
||||
const auto dz = a.z - b.z;
|
||||
@@ -213,8 +205,7 @@ float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b)
|
||||
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b)
|
||||
{
|
||||
float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) {
|
||||
const auto dx = a.x - b.x;
|
||||
const auto dy = a.y - b.y;
|
||||
const auto dz = a.z - b.z;
|
||||
@@ -222,21 +213,20 @@ float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b)
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta)
|
||||
{
|
||||
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta) {
|
||||
float dx = target.x - current.x;
|
||||
float dy = target.y - current.y;
|
||||
float dz = target.z - current.z;
|
||||
float lengthSquared = (float) ((double) dx * (double) dx + (double) dy * (double) dy + (double) dz * (double) dz);
|
||||
if ((double) lengthSquared == 0.0 || (double) maxDistanceDelta >= 0.0 && (double) lengthSquared <= (double) maxDistanceDelta * (double) maxDistanceDelta)
|
||||
float lengthSquared = (float)((double)dx * (double)dx + (double)dy * (double)dy + (double)dz * (double)dz);
|
||||
if ((double)lengthSquared == 0.0 || (double)maxDistanceDelta >= 0.0 && (double)lengthSquared <= (double)maxDistanceDelta * (double)maxDistanceDelta)
|
||||
return target;
|
||||
float length = (float) std::sqrt((double) lengthSquared);
|
||||
float length = (float)std::sqrt((double)lengthSquared);
|
||||
return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta);
|
||||
}
|
||||
|
||||
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
|
||||
NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) {
|
||||
Vector3 vector;
|
||||
NiPoint3 vector;
|
||||
float num12 = rotation.x + rotation.x;
|
||||
float num2 = rotation.y + rotation.y;
|
||||
float num = rotation.z + rotation.z;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
class NiPoint3;
|
||||
class NiQuaternion;
|
||||
typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoint3 class, but typedef'd for clarity in some cases
|
||||
|
||||
//! A custom class the defines a point in space
|
||||
class NiPoint3 {
|
||||
@@ -102,14 +101,14 @@ public:
|
||||
\param vec The second vector
|
||||
\return The dot product of the two vectors
|
||||
*/
|
||||
float DotProduct(const Vector3& vec) const;
|
||||
float DotProduct(const NiPoint3& vec) const;
|
||||
|
||||
//! Returns the cross product of the vector crossed with another vector
|
||||
/*!
|
||||
\param vec The second vector
|
||||
\return The cross product of the two vectors
|
||||
*/
|
||||
Vector3 CrossProduct(const Vector3& vec) const;
|
||||
NiPoint3 CrossProduct(const NiPoint3& vec) const;
|
||||
|
||||
//! Unitize the vector
|
||||
/*!
|
||||
|
||||
@@ -72,22 +72,22 @@ void NiQuaternion::SetZ(float z) {
|
||||
// MARK: Member Functions
|
||||
|
||||
//! Returns the forward vector from the quaternion
|
||||
Vector3 NiQuaternion::GetForwardVector(void) const {
|
||||
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
|
||||
NiPoint3 NiQuaternion::GetForwardVector(void) const {
|
||||
return NiPoint3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
|
||||
}
|
||||
|
||||
//! Returns the up vector from the quaternion
|
||||
Vector3 NiQuaternion::GetUpVector(void) const {
|
||||
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
|
||||
NiPoint3 NiQuaternion::GetUpVector(void) const {
|
||||
return NiPoint3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
|
||||
}
|
||||
|
||||
//! Returns the right vector from the quaternion
|
||||
Vector3 NiQuaternion::GetRightVector(void) const {
|
||||
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
|
||||
NiPoint3 NiQuaternion::GetRightVector(void) const {
|
||||
return NiPoint3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
|
||||
}
|
||||
|
||||
Vector3 NiQuaternion::GetEulerAngles() const {
|
||||
Vector3 angles;
|
||||
NiPoint3 NiQuaternion::GetEulerAngles() const {
|
||||
NiPoint3 angles;
|
||||
|
||||
// roll (x-axis rotation)
|
||||
const float sinr_cosp = 2 * (w * x + y * z);
|
||||
@@ -99,8 +99,7 @@ Vector3 NiQuaternion::GetEulerAngles() const {
|
||||
|
||||
if (std::abs(sinp) >= 1) {
|
||||
angles.y = std::copysign(3.14 / 2, sinp); // use 90 degrees if out of range
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
angles.y = std::asin(sinp);
|
||||
}
|
||||
|
||||
@@ -149,8 +148,7 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
|
||||
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
|
||||
}
|
||||
|
||||
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint)
|
||||
{
|
||||
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
|
||||
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
|
||||
|
||||
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
||||
@@ -166,7 +164,7 @@ NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiP
|
||||
}
|
||||
|
||||
//! Creates a Quaternion from a specific axis and angle relative to that axis
|
||||
NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle) {
|
||||
NiQuaternion NiQuaternion::CreateFromAxisAngle(const NiPoint3& axis, float angle) {
|
||||
float halfAngle = angle * 0.5f;
|
||||
float s = static_cast<float>(sin(halfAngle));
|
||||
|
||||
@@ -179,8 +177,7 @@ NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle)
|
||||
return q;
|
||||
}
|
||||
|
||||
NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles)
|
||||
{
|
||||
NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles) {
|
||||
// Abbreviations for the various angular functions
|
||||
float cy = cos(eulerAngles.z * 0.5);
|
||||
float sy = sin(eulerAngles.z * 0.5);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
class NiQuaternion;
|
||||
typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version of NiQuaternion
|
||||
|
||||
//! A class that defines a rotation in space
|
||||
class NiQuaternion {
|
||||
@@ -95,21 +94,21 @@ public:
|
||||
/*!
|
||||
\return The forward vector of the quaternion
|
||||
*/
|
||||
Vector3 GetForwardVector(void) const;
|
||||
NiPoint3 GetForwardVector(void) const;
|
||||
|
||||
//! Returns the up vector from the quaternion
|
||||
/*!
|
||||
\return The up vector fo the quaternion
|
||||
*/
|
||||
Vector3 GetUpVector(void) const;
|
||||
NiPoint3 GetUpVector(void) const;
|
||||
|
||||
//! Returns the right vector from the quaternion
|
||||
/*!
|
||||
\return The right vector of the quaternion
|
||||
*/
|
||||
Vector3 GetRightVector(void) const;
|
||||
NiPoint3 GetRightVector(void) const;
|
||||
|
||||
Vector3 GetEulerAngles() const;
|
||||
NiPoint3 GetEulerAngles() const;
|
||||
|
||||
|
||||
// MARK: Operators
|
||||
@@ -145,7 +144,7 @@ public:
|
||||
\param angle The angle relative to this axis
|
||||
\return A quaternion created from the axis and angle
|
||||
*/
|
||||
static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
|
||||
static NiQuaternion CreateFromAxisAngle(const NiPoint3& axis, float angle);
|
||||
|
||||
static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
|
||||
};
|
||||
|
||||
@@ -45,12 +45,11 @@ const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
|
||||
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
||||
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
|
||||
|
||||
void SHA512::transform(const unsigned char *message, unsigned int block_nb)
|
||||
{
|
||||
void SHA512::transform(const unsigned char* message, unsigned int block_nb) {
|
||||
uint64 w[80];
|
||||
uint64 wv[8];
|
||||
uint64 t1, t2;
|
||||
const unsigned char *sub_block;
|
||||
const unsigned char* sub_block;
|
||||
int i, j;
|
||||
for (i = 0; i < (int)block_nb; i++) {
|
||||
sub_block = message + (i << 7);
|
||||
@@ -83,8 +82,7 @@ void SHA512::transform(const unsigned char *message, unsigned int block_nb)
|
||||
}
|
||||
}
|
||||
|
||||
void SHA512::init()
|
||||
{
|
||||
void SHA512::init() {
|
||||
m_h[0] = 0x6a09e667f3bcc908ULL;
|
||||
m_h[1] = 0xbb67ae8584caa73bULL;
|
||||
m_h[2] = 0x3c6ef372fe94f82bULL;
|
||||
@@ -97,11 +95,10 @@ void SHA512::init()
|
||||
m_tot_len = 0;
|
||||
}
|
||||
|
||||
void SHA512::update(const unsigned char *message, unsigned int len)
|
||||
{
|
||||
void SHA512::update(const unsigned char* message, unsigned int len) {
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char *shifted_message;
|
||||
const unsigned char* shifted_message;
|
||||
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
memcpy(&m_block[m_len], message, rem_len);
|
||||
@@ -120,8 +117,7 @@ void SHA512::update(const unsigned char *message, unsigned int len)
|
||||
m_tot_len += (block_nb + 1) << 7;
|
||||
}
|
||||
|
||||
void SHA512::final(unsigned char *digest)
|
||||
{
|
||||
void SHA512::final(unsigned char* digest) {
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
@@ -139,8 +135,7 @@ void SHA512::final(unsigned char *digest)
|
||||
}
|
||||
}
|
||||
|
||||
std::string sha512(std::string input)
|
||||
{
|
||||
std::string sha512(std::string input) {
|
||||
unsigned char digest[SHA512::DIGEST_SIZE];
|
||||
memset(digest, 0, SHA512::DIGEST_SIZE);
|
||||
class SHA512 ctx;
|
||||
|
||||
@@ -14,12 +14,12 @@ protected:
|
||||
|
||||
public:
|
||||
void init();
|
||||
void update(const unsigned char *message, unsigned int len);
|
||||
void final(unsigned char *digest);
|
||||
void update(const unsigned char* message, unsigned int len);
|
||||
void final(unsigned char* digest);
|
||||
static const unsigned int DIGEST_SIZE = (512 / 8);
|
||||
|
||||
protected:
|
||||
void transform(const unsigned char *message, unsigned int block_nb);
|
||||
void transform(const unsigned char* message, unsigned int block_nb);
|
||||
unsigned int m_tot_len;
|
||||
unsigned int m_len;
|
||||
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
|
||||
|
||||
@@ -9,12 +9,12 @@ std::string demangle(const char* name) {
|
||||
int status = -4; // some arbitrary value to eliminate the compiler warning
|
||||
|
||||
// enable c++11 by passing the flag -std=c++11 to g++
|
||||
std::unique_ptr<char, void(*)(void*)> res {
|
||||
std::unique_ptr<char, void(*)(void*)> res{
|
||||
abi::__cxa_demangle(name, NULL, NULL, &status),
|
||||
std::free
|
||||
};
|
||||
|
||||
return (status==0) ? res.get() : name ;
|
||||
return (status == 0) ? res.get() : name;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#include "ZCompression.h"
|
||||
#include "ZCompression.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
namespace ZCompression
|
||||
{
|
||||
int32_t GetMaxCompressedLength(int32_t nLenSrc)
|
||||
{
|
||||
namespace ZCompression {
|
||||
int32_t GetMaxCompressedLength(int32_t nLenSrc) {
|
||||
int32_t n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block
|
||||
return (nLenSrc + 6 + (n16kBlocks * 5));
|
||||
}
|
||||
|
||||
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst)
|
||||
{
|
||||
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst) {
|
||||
z_stream zInfo = { 0 };
|
||||
zInfo.total_in = zInfo.avail_in = nLenSrc;
|
||||
zInfo.total_out = zInfo.avail_out = nLenDst;
|
||||
@@ -31,8 +30,7 @@ namespace ZCompression
|
||||
|
||||
}
|
||||
|
||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr)
|
||||
{
|
||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr) {
|
||||
// Get the size of the decompressed data
|
||||
z_stream zInfo = { 0 };
|
||||
zInfo.total_in = zInfo.avail_in = nLenSrc;
|
||||
@@ -71,3 +69,5 @@ namespace ZCompression
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ZCompression
|
||||
{
|
||||
#include "dPlatforms.h"
|
||||
|
||||
#ifndef DARKFLAME_PLATFORM_WIN32
|
||||
|
||||
namespace ZCompression {
|
||||
int32_t GetMaxCompressedLength(int32_t nLenSrc);
|
||||
|
||||
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst);
|
||||
|
||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,9 @@ const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
|
||||
|
||||
typedef std::set<LWOOBJID> TSetObjID;
|
||||
|
||||
const float PI = 3.14159f;
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
#endif
|
||||
|
||||
#if defined(__unix) || defined(__APPLE__)
|
||||
//For Linux:
|
||||
@@ -387,6 +389,7 @@ enum eReplicaComponentType : int32_t {
|
||||
COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component
|
||||
COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component
|
||||
COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component
|
||||
COMPONENT_TYPE_MODEL = 42, //!< The Model Component
|
||||
COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component
|
||||
COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component
|
||||
COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component
|
||||
@@ -401,18 +404,24 @@ enum eReplicaComponentType : int32_t {
|
||||
COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component
|
||||
COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component
|
||||
COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component
|
||||
COMPONENT_TYPE_RACING_STATS = 74, //!< The Exhibit Component
|
||||
COMPONENT_TYPE_RACING_STATS = 74, //!< The Racing Stats Component
|
||||
COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component
|
||||
COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component
|
||||
COMPONENT_TYPE_MISSION = 84, //!< The Mission Component
|
||||
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen
|
||||
COMPONENT_TYPE_RAIL_ACTIVATOR = 104,
|
||||
COMPONENT_TYPE_POSSESSOR = 107, //!< The Component 107
|
||||
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Component 108
|
||||
COMPONENT_TYPE_RAIL_ACTIVATOR = 104, //!< The Rail Activator Component
|
||||
COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT = 106, //!< The Player Forced Movement Component
|
||||
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component
|
||||
COMPONENT_TYPE_LEVEL_PROGRESSION = 109, //!< The Level Progression Component
|
||||
COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component
|
||||
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
|
||||
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
|
||||
};
|
||||
|
||||
COMPONENT_TYPE_MODEL = 5398484 //look man idk
|
||||
enum class UseItemResponse : uint32_t {
|
||||
NoImaginationForPet = 1,
|
||||
FailedPrecondition,
|
||||
MountsNotAllowed
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -434,33 +443,6 @@ enum eInventoryType : uint32_t {
|
||||
INVALID // made up, for internal use!!!
|
||||
};
|
||||
|
||||
enum eItemType : int32_t {
|
||||
ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type
|
||||
ITEM_TYPE_BRICK = 1, //!< A brick
|
||||
ITEM_TYPE_HAT = 2, //!< A hat / head item
|
||||
ITEM_TYPE_HAIR = 3, //!< A hair item
|
||||
ITEM_TYPE_NECK = 4, //!< A neck item
|
||||
ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item
|
||||
ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item
|
||||
ITEM_TYPE_LEGS = 7, //!< A pants item
|
||||
ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item
|
||||
ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item
|
||||
ITEM_TYPE_BEHAVIOR = 10, //!< A behavior
|
||||
ITEM_TYPE_PROPERTY = 11, //!< A property
|
||||
ITEM_TYPE_MODEL = 12, //!< A model
|
||||
ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item
|
||||
ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item
|
||||
ITEM_TYPE_CHEST = 15, //!< A chest item
|
||||
ITEM_TYPE_EGG = 16, //!< An egg
|
||||
ITEM_TYPE_PET_FOOD = 17, //!< A pet food item
|
||||
ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item
|
||||
ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item
|
||||
ITEM_TYPE_PACKAGE = 20, //!< A package
|
||||
ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model
|
||||
ITEM_TYPE_VEHICLE = 22, //!< A vehicle
|
||||
ITEM_TYPE_CURRENCY = 23 //!< Currency
|
||||
};
|
||||
|
||||
enum eRebuildState : uint32_t {
|
||||
REBUILD_OPEN,
|
||||
REBUILD_COMPLETED = 2,
|
||||
@@ -469,6 +451,34 @@ enum eRebuildState : uint32_t {
|
||||
REBUILD_INCOMPLETE
|
||||
};
|
||||
|
||||
/**
|
||||
* The loot source's type.
|
||||
*/
|
||||
enum eLootSourceType : int32_t {
|
||||
LOOT_SOURCE_NONE = 0,
|
||||
LOOT_SOURCE_CHEST,
|
||||
LOOT_SOURCE_MISSION,
|
||||
LOOT_SOURCE_MAIL,
|
||||
LOOT_SOURCE_CURRENCY,
|
||||
LOOT_SOURCE_ACHIEVEMENT,
|
||||
LOOT_SOURCE_TRADE,
|
||||
LOOT_SOURCE_QUICKBUILD,
|
||||
LOOT_SOURCE_DELETION,
|
||||
LOOT_SOURCE_VENDOR,
|
||||
LOOT_SOURCE_ACTIVITY,
|
||||
LOOT_SOURCE_PICKUP,
|
||||
LOOT_SOURCE_BRICK,
|
||||
LOOT_SOURCE_PROPERTY,
|
||||
LOOT_SOURCE_MODERATION,
|
||||
LOOT_SOURCE_EXHIBIT,
|
||||
LOOT_SOURCE_INVENTORY,
|
||||
LOOT_SOURCE_CLAIMCODE,
|
||||
LOOT_SOURCE_CONSUMPTION,
|
||||
LOOT_SOURCE_CRAFTING,
|
||||
LOOT_SOURCE_LEVEL_REWARD,
|
||||
LOOT_SOURCE_RELOCATE
|
||||
};
|
||||
|
||||
enum eGameActivities : uint32_t {
|
||||
ACTIVITY_NONE,
|
||||
ACTIVITY_QUICKBUILDING,
|
||||
@@ -534,7 +544,7 @@ enum ePlayerFlags {
|
||||
TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52,
|
||||
MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53,
|
||||
MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54,
|
||||
AG_BEACON_QB,_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55,
|
||||
AG_BEACON_QB_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55,
|
||||
GF_PET_DIG_FLAG_1 = 56,
|
||||
GF_PET_DIG_FLAG_2 = 57,
|
||||
GF_PET_DIG_FLAG_3 = 58,
|
||||
@@ -620,6 +630,7 @@ enum ePlayerFlags {
|
||||
GF_BINOC_IN_CROC_AREA = 1308,
|
||||
GF_BINOC_IN_JAIL_AREA = 1309,
|
||||
GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310,
|
||||
NT_PLINTH_REBUILD = 1919,
|
||||
NT_FACTION_SPY_DUKE = 1974,
|
||||
NT_FACTION_SPY_OVERBUILD = 1976,
|
||||
NT_FACTION_SPY_HAEL = 1977,
|
||||
@@ -630,7 +641,6 @@ enum ePlayerFlags {
|
||||
NJ_WU_SHOW_DAILY_CHEST = 2099
|
||||
};
|
||||
|
||||
|
||||
//======== FUNC ===========
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "dLogger.h"
|
||||
|
||||
dLogger::dLogger(const std::string& outpath, bool logToConsole) {
|
||||
dLogger::dLogger(const std::string& outpath, bool logToConsole, bool logDebugStatements) {
|
||||
m_logToConsole = logToConsole;
|
||||
m_logDebugStatements = logDebugStatements;
|
||||
m_outpath = outpath;
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -24,39 +25,25 @@ dLogger::~dLogger() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void dLogger::LogBasic(const std::string & message) {
|
||||
LogBasic(message.c_str());
|
||||
}
|
||||
|
||||
void dLogger::LogBasic(const char * format, ...) {
|
||||
void dLogger::vLog(const char* format, va_list args) {
|
||||
#ifdef _WIN32
|
||||
time_t t = time(NULL);
|
||||
struct tm time;
|
||||
localtime_s(&time, &t);
|
||||
|
||||
char timeStr[70];
|
||||
|
||||
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", &time);
|
||||
|
||||
char message[2048];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf_s(message, format, args);
|
||||
va_end(args);
|
||||
vsnprintf(message, 2048, format, args);
|
||||
|
||||
if (m_logToConsole) std::cout << "[" << "time machine broke" << "] " << message;
|
||||
mFile << "[" << "time" << "] " << message;
|
||||
if (m_logToConsole) std::cout << "[" << timeStr << "] " << message;
|
||||
mFile << "[" << timeStr << "] " << message;
|
||||
#else
|
||||
time_t t = time(NULL);
|
||||
struct tm * time = localtime(&t);
|
||||
struct tm* time = localtime(&t);
|
||||
char timeStr[70];
|
||||
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time);
|
||||
|
||||
char message[2048];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(message, format, args);
|
||||
va_end(args);
|
||||
vsnprintf(message, 2048, format, args);
|
||||
|
||||
if (m_logToConsole) {
|
||||
fputs("[", stdout);
|
||||
@@ -76,62 +63,42 @@ void dLogger::LogBasic(const char * format, ...) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void dLogger::Log(const char * className, const char * format, ...) {
|
||||
#ifdef _WIN32
|
||||
time_t t = time(NULL);
|
||||
struct tm time;
|
||||
localtime_s(&time, &t);
|
||||
|
||||
char timeStr[70];
|
||||
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", &time);
|
||||
|
||||
char message[2048];
|
||||
void dLogger::LogBasic(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf_s(message, format, args);
|
||||
|
||||
vLog(format, args);
|
||||
va_end(args);
|
||||
|
||||
if (m_logToConsole) std::cout << "[" << "timeStr" << "] [" << className << "]: " << message;
|
||||
mFile << "[" << "timeStr" << "] [" << className << "]: " << message;
|
||||
#else
|
||||
time_t t = time(NULL);
|
||||
struct tm * time = localtime(&t);
|
||||
char timeStr[70];
|
||||
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time);
|
||||
|
||||
char message[2048];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(message, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (m_logToConsole) {
|
||||
fputs("[", stdout);
|
||||
fputs(timeStr, stdout);
|
||||
fputs("] ", stdout);
|
||||
fputs("[", stdout);
|
||||
fputs(className, stdout);
|
||||
fputs("]: ", stdout);
|
||||
fputs(message, stdout);
|
||||
}
|
||||
|
||||
if (fp != NULL) {
|
||||
fputs("[", fp);
|
||||
fputs(timeStr, fp);
|
||||
fputs("] ", fp);
|
||||
fputs("[", fp);
|
||||
fputs(className, fp);
|
||||
fputs("]: ", fp);
|
||||
fputs(message, fp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void dLogger::Log(const std::string & className, const std::string & message) {
|
||||
void dLogger::LogBasic(const std::string& message) {
|
||||
LogBasic(message.c_str());
|
||||
}
|
||||
|
||||
void dLogger::Log(const char* className, const char* format, ...) {
|
||||
va_list args;
|
||||
std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n";
|
||||
va_start(args, format);
|
||||
vLog(log.c_str(), args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dLogger::Log(const std::string& className, const std::string& message) {
|
||||
Log(className.c_str(), message.c_str());
|
||||
}
|
||||
|
||||
void dLogger::LogDebug(const char* className, const char* format, ...) {
|
||||
if (!m_logDebugStatements) return;
|
||||
va_list args;
|
||||
std::string log = "[" + std::string(className) + "] " + std::string(format);
|
||||
va_start(args, format);
|
||||
vLog(log.c_str(), args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dLogger::LogDebug(const std::string& className, const std::string& message) {
|
||||
LogDebug(className.c_str(), message.c_str());
|
||||
}
|
||||
|
||||
void dLogger::Flush() {
|
||||
#ifdef _WIN32
|
||||
mFile.flush();
|
||||
|
||||
@@ -7,27 +7,32 @@
|
||||
|
||||
class dLogger {
|
||||
public:
|
||||
dLogger(const std::string& outpath, bool logToConsole);
|
||||
dLogger(const std::string& outpath, bool logToConsole, bool logDebugStatements);
|
||||
~dLogger();
|
||||
|
||||
void SetLogToConsole(bool logToConsole) { m_logToConsole = logToConsole; }
|
||||
void SetLogDebugStatements(bool logDebugStatements) { m_logDebugStatements = logDebugStatements; }
|
||||
void vLog(const char* format, va_list args);
|
||||
|
||||
void LogBasic(const std::string& message);
|
||||
void LogBasic(const char* format, ...);
|
||||
void Log(const char* className, const char* format, ...);
|
||||
void Log(const std::string& className, const std::string& message);
|
||||
void LogDebug(const std::string& className, const std::string& message);
|
||||
void LogDebug(const char* className, const char* format, ...);
|
||||
|
||||
void Flush();
|
||||
|
||||
const bool GetIsLoggingToConsole() const { return m_logToConsole; }
|
||||
|
||||
private:
|
||||
bool m_logDebugStatements;
|
||||
bool m_logToConsole;
|
||||
std::string m_outpath;
|
||||
std::ofstream mFile;
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
//Glorious linux can run with SPEED:
|
||||
FILE* fp = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
29
dCommon/dPlatforms.h
Normal file
29
dCommon/dPlatforms.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define DARKFLAME_PLATFORM_WIN32
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||
#define DARKFLAME_PLATFORM_IOS
|
||||
#elif TARGET_OS_MAC
|
||||
#define DARKFLAME_PLATFORM_MACOS
|
||||
#else
|
||||
#error unknown Apple operating system
|
||||
#endif
|
||||
#elif defined(__unix__)
|
||||
#define DARKFLAME_PLATFORM_UNIX
|
||||
#if defined(__ANDROID__)
|
||||
#define DARKFLAME_PLATFORM_ANDROID
|
||||
#elif defined(__linux__)
|
||||
#define DARKFLAME_PLATFORM_LINUX
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#define DARKFLAME_PLATFORM_FREEBSD
|
||||
#elif defined(__CYGWIN__)
|
||||
#define DARKFLAME_PLATFORM_CYGWIN
|
||||
#else
|
||||
#error unknown unix operating system
|
||||
#endif
|
||||
#else
|
||||
#error unknown operating system
|
||||
#endif
|
||||
44
dCommon/eAninmationFlags.h
Normal file
44
dCommon/eAninmationFlags.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EANINMATIONFLAGS__H__
|
||||
#define __EANINMATIONFLAGS__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eAnimationFlags : uint32_t {
|
||||
IDLE_INVALID = 0, // made up, for internal use!!!
|
||||
IDLE_BASIC,
|
||||
IDLE_SWIM,
|
||||
IDLE_CARRY,
|
||||
IDLE_SWORD,
|
||||
IDLE_HAMMER,
|
||||
IDLE_SPEAR,
|
||||
IDLE_PISTOL,
|
||||
IDLE_BOW,
|
||||
IDLE_COMBAT,
|
||||
IDLE_JETPACK,
|
||||
IDLE_HORSE,
|
||||
IDLE_SG,
|
||||
IDLE_ORGAN,
|
||||
IDLE_SKATEBOARD,
|
||||
IDLE_DAREDEVIL,
|
||||
IDLE_SAMURAI,
|
||||
IDLE_SUMMONER,
|
||||
IDLE_BUCCANEER,
|
||||
IDLE_MISC,
|
||||
IDLE_NINJA,
|
||||
IDLE_MISC1,
|
||||
IDLE_MISC2,
|
||||
IDLE_MISC3,
|
||||
IDLE_MISC4,
|
||||
IDLE_MISC5,
|
||||
IDLE_MISC6,
|
||||
IDLE_MISC7,
|
||||
IDLE_MISC8,
|
||||
IDLE_MISC9,
|
||||
IDLE_MISC10,
|
||||
IDLE_MISC11,
|
||||
IDLE_MISC12
|
||||
};
|
||||
|
||||
#endif //!__EANINMATIONFLAGS__H__
|
||||
36
dCommon/eItemType.h
Normal file
36
dCommon/eItemType.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EITEMTYPE__H__
|
||||
#define __EITEMTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eItemType : int32_t {
|
||||
ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type
|
||||
ITEM_TYPE_BRICK = 1, //!< A brick
|
||||
ITEM_TYPE_HAT = 2, //!< A hat / head item
|
||||
ITEM_TYPE_HAIR = 3, //!< A hair item
|
||||
ITEM_TYPE_NECK = 4, //!< A neck item
|
||||
ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item
|
||||
ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item
|
||||
ITEM_TYPE_LEGS = 7, //!< A pants item
|
||||
ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item
|
||||
ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item
|
||||
ITEM_TYPE_BEHAVIOR = 10, //!< A behavior
|
||||
ITEM_TYPE_PROPERTY = 11, //!< A property
|
||||
ITEM_TYPE_MODEL = 12, //!< A model
|
||||
ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item
|
||||
ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item
|
||||
ITEM_TYPE_CHEST = 15, //!< A chest item
|
||||
ITEM_TYPE_EGG = 16, //!< An egg
|
||||
ITEM_TYPE_PET_FOOD = 17, //!< A pet food item
|
||||
ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item
|
||||
ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item
|
||||
ITEM_TYPE_PACKAGE = 20, //!< A package
|
||||
ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model
|
||||
ITEM_TYPE_VEHICLE = 22, //!< A vehicle
|
||||
ITEM_TYPE_CURRENCY = 23, //!< Currency
|
||||
ITEM_TYPE_MOUNT = 24 //!< A Mount
|
||||
};
|
||||
|
||||
#endif //!__EITEMTYPE__H__
|
||||
14
dCommon/eUnequippableActiveType.h
Normal file
14
dCommon/eUnequippableActiveType.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EUNEQUIPPABLEACTIVETYPE__H__
|
||||
#define __EUNEQUIPPABLEACTIVETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eUnequippableActiveType : int32_t {
|
||||
INVALID = -1,
|
||||
PET = 0,
|
||||
MOUNT
|
||||
};
|
||||
|
||||
#endif //!__EUNEQUIPPABLEACTIVETYPE__H__
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
|
||||
// Static Variables
|
||||
static CppSQLite3DB * conn = new CppSQLite3DB();
|
||||
static CppSQLite3DB* conn = new CppSQLite3DB();
|
||||
|
||||
//! Opens a connection with the CDClient
|
||||
void CDClientDatabase::Connect(const std::string& filename) {
|
||||
@@ -13,3 +13,8 @@ void CDClientDatabase::Connect(const std::string& filename) {
|
||||
CppSQLite3Query CDClientDatabase::ExecuteQuery(const std::string& query) {
|
||||
return conn->execQuery(query.c_str());
|
||||
}
|
||||
|
||||
//! Makes prepared statements
|
||||
CppSQLite3Statement CDClientDatabase::CreatePreppedStmt(const std::string& query) {
|
||||
return conn->compileStatement(query.c_str());
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// Enable this to cache all entries in each table for fast access, comes with more memory cost
|
||||
//#define CDCLIENT_CACHE_ALL
|
||||
// Enable this to cache all entries in each table for fast access, comes with more memory cost
|
||||
//#define CDCLIENT_CACHE_ALL
|
||||
|
||||
// Enable this to skip some unused columns in some tables
|
||||
// Enable this to skip some unused columns in some tables
|
||||
#define UNUSED(v)
|
||||
|
||||
/*!
|
||||
@@ -24,7 +24,7 @@
|
||||
\brief An interface between the CDClient.sqlite file and the server
|
||||
*/
|
||||
|
||||
//! The CDClient Database namespace
|
||||
//! The CDClient Database namespace
|
||||
namespace CDClientDatabase {
|
||||
|
||||
//! Opens a connection with the CDClient
|
||||
@@ -40,4 +40,10 @@ namespace CDClientDatabase {
|
||||
*/
|
||||
CppSQLite3Query ExecuteQuery(const std::string& query);
|
||||
|
||||
//! Queries the CDClient and parses arguments
|
||||
/*!
|
||||
\param query The query with formatted arguments
|
||||
\return prepared SQLite Statement
|
||||
*/
|
||||
CppSQLite3Statement CreatePreppedStmt(const std::string& query);
|
||||
};
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "CDClientManager.h"
|
||||
|
||||
// Static Variables
|
||||
CDClientManager * CDClientManager::m_Address = nullptr;
|
||||
CDClientManager* CDClientManager::m_Address = nullptr;
|
||||
|
||||
//! Initializes the manager
|
||||
void CDClientManager::Initialize(void) {
|
||||
tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable()));
|
||||
UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable())));
|
||||
tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable()));
|
||||
UNUSED(tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable())));
|
||||
tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable()));
|
||||
tables.insert(std::make_pair("ComponentsRegistry", new CDComponentsRegistryTable()));
|
||||
tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable()));
|
||||
tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable()));
|
||||
|
||||
@@ -52,17 +52,17 @@
|
||||
\brief A manager for the CDClient tables
|
||||
*/
|
||||
|
||||
//! Manages all data from the CDClient
|
||||
//! Manages all data from the CDClient
|
||||
class CDClientManager {
|
||||
private:
|
||||
static CDClientManager * m_Address; //!< The singleton address
|
||||
static CDClientManager* m_Address; //!< The singleton address
|
||||
|
||||
std::unordered_map<std::string, CDTable*> tables; //!< The tables
|
||||
|
||||
public:
|
||||
|
||||
//! The singleton method
|
||||
static CDClientManager * Instance() {
|
||||
static CDClientManager* Instance() {
|
||||
if (m_Address == 0) {
|
||||
m_Address = new CDClientManager;
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
\return The class or nullptr
|
||||
*/
|
||||
template<typename T>
|
||||
T * GetTable(const std::string& tableName) {
|
||||
T* GetTable(const std::string& tableName) {
|
||||
static_assert(std::is_base_of<CDTable, T>::value, "T should inherit from CDTable!");
|
||||
|
||||
for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) {
|
||||
|
||||
13
dDatabase/CMakeLists.txt
Normal file
13
dDatabase/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
set(DDATABASE_SOURCES "CDClientDatabase.cpp"
|
||||
"CDClientManager.cpp"
|
||||
"Database.cpp"
|
||||
"MigrationRunner.cpp")
|
||||
|
||||
add_subdirectory(Tables)
|
||||
|
||||
foreach(file ${DDATABASE_TABLES_SOURCES})
|
||||
set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Tables/${file}")
|
||||
endforeach()
|
||||
|
||||
add_library(dDatabase STATIC ${DDATABASE_SOURCES})
|
||||
target_link_libraries(dDatabase sqlite3 mariadbConnCpp)
|
||||
@@ -6,11 +6,12 @@ using namespace std;
|
||||
|
||||
#pragma warning (disable:4251) //Disables SQL warnings
|
||||
|
||||
sql::Driver * Database::driver;
|
||||
sql::Connection * Database::con;
|
||||
sql::Driver* Database::driver;
|
||||
sql::Connection* Database::con;
|
||||
sql::Properties Database::props;
|
||||
std::string Database::database;
|
||||
|
||||
void Database::Connect(const string& host, const string& database, const string& username, const string& password) {
|
||||
driver = get_driver_instance();
|
||||
|
||||
//To bypass debug issues:
|
||||
std::string newHost = "tcp://" + host;
|
||||
@@ -19,16 +20,33 @@ void Database::Connect(const string& host, const string& database, const string&
|
||||
const char* szUsername = username.c_str();
|
||||
const char* szPassword = password.c_str();
|
||||
|
||||
con = driver->connect(szHost, szUsername, szPassword);
|
||||
con->setSchema(szDatabase);
|
||||
driver = sql::mariadb::get_driver_instance();
|
||||
|
||||
bool myTrue = true;
|
||||
con->setClientOption("MYSQL_OPT_RECONNECT", &myTrue);
|
||||
} //Connect
|
||||
sql::Properties properties;
|
||||
properties["hostName"] = szHost;
|
||||
properties["user"] = szUsername;
|
||||
properties["password"] = szPassword;
|
||||
properties["autoReconnect"] = "true";
|
||||
|
||||
void Database::Destroy() {
|
||||
Database::props = properties;
|
||||
Database::database = database;
|
||||
|
||||
Database::Connect();
|
||||
}
|
||||
|
||||
void Database::Connect() {
|
||||
con = driver->connect(Database::props);
|
||||
con->setSchema(Database::database);
|
||||
}
|
||||
|
||||
void Database::Destroy(std::string source, bool log) {
|
||||
if (!con) return;
|
||||
cout << "Destroying MySQL connection!" << endl;
|
||||
|
||||
if (log) {
|
||||
if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!", source.c_str());
|
||||
else Game::logger->Log("Database", "Destroying MySQL connection!");
|
||||
}
|
||||
|
||||
con->close();
|
||||
delete con;
|
||||
} //Destroy
|
||||
@@ -44,33 +62,24 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
||||
sql::SQLString str(test, size);
|
||||
|
||||
if (!con) {
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||
|
||||
Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
Game::logger->Log("Database", "Trying to reconnect to MySQL\n");
|
||||
Connect();
|
||||
Game::logger->Log("Database", "Trying to reconnect to MySQL");
|
||||
}
|
||||
|
||||
if (!con->isValid() || con->isClosed())
|
||||
{
|
||||
if (!con->isValid() || con->isClosed()) {
|
||||
delete con;
|
||||
|
||||
con = nullptr;
|
||||
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||
|
||||
Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n");
|
||||
Connect();
|
||||
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection");
|
||||
}
|
||||
|
||||
auto* stmt = con->prepareStatement(str);
|
||||
|
||||
return stmt;
|
||||
} //CreatePreppedStmt
|
||||
|
||||
void Database::Commit() {
|
||||
Database::con->commit();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <mysql_connection.h>
|
||||
#include <cppconn/driver.h>
|
||||
#include <cppconn/exception.h>
|
||||
#include <cppconn/resultset.h>
|
||||
#include <cppconn/statement.h>
|
||||
#include <cppconn/prepared_statement.h>
|
||||
#include <cppconn/sqlstring.h>
|
||||
#include <conncpp.hpp>
|
||||
|
||||
class MySqlException : public std::runtime_error {
|
||||
public:
|
||||
@@ -17,12 +11,19 @@ public:
|
||||
|
||||
class Database {
|
||||
private:
|
||||
static sql::Driver *driver;
|
||||
static sql::Connection *con;
|
||||
|
||||
static sql::Driver* driver;
|
||||
static sql::Connection* con;
|
||||
static sql::Properties props;
|
||||
static std::string database;
|
||||
public:
|
||||
static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
|
||||
static void Destroy();
|
||||
static void Connect();
|
||||
static void Destroy(std::string source = "", bool log = true);
|
||||
|
||||
static sql::Statement* CreateStmt();
|
||||
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
||||
static void Commit();
|
||||
|
||||
static std::string GetDatabase() { return database; }
|
||||
static sql::Properties GetProperties() { return props; }
|
||||
};
|
||||
|
||||
77
dDatabase/MigrationRunner.cpp
Normal file
77
dDatabase/MigrationRunner.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "MigrationRunner.h"
|
||||
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
void MigrationRunner::RunMigrations() {
|
||||
auto stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
|
||||
stmt->executeQuery();
|
||||
delete stmt;
|
||||
|
||||
sql::SQLString finalSQL = "";
|
||||
Migration checkMigration{};
|
||||
|
||||
for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/")) {
|
||||
auto migration = LoadMigration(entry);
|
||||
|
||||
if (migration.data.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
checkMigration = migration;
|
||||
|
||||
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
|
||||
stmt->setString(1, migration.name);
|
||||
auto res = stmt->executeQuery();
|
||||
bool doExit = res->next();
|
||||
delete res;
|
||||
delete stmt;
|
||||
if (doExit) continue;
|
||||
|
||||
Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
|
||||
|
||||
finalSQL.append(migration.data);
|
||||
finalSQL.append('\n');
|
||||
|
||||
stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
|
||||
stmt->setString(1, entry);
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
}
|
||||
|
||||
if (!finalSQL.empty()) {
|
||||
try {
|
||||
auto simpleStatement = Database::CreateStmt();
|
||||
simpleStatement->execute(finalSQL);
|
||||
delete simpleStatement;
|
||||
} catch (sql::SQLException e) {
|
||||
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Migration MigrationRunner::LoadMigration(std::string path) {
|
||||
Migration migration{};
|
||||
std::ifstream file("./migrations/" + path);
|
||||
|
||||
if (file.is_open()) {
|
||||
std::hash<std::string> hash;
|
||||
|
||||
std::string line;
|
||||
std::string total = "";
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
total += line;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
migration.name = path;
|
||||
migration.data = total;
|
||||
}
|
||||
|
||||
return migration;
|
||||
}
|
||||
19
dDatabase/MigrationRunner.h
Normal file
19
dDatabase/MigrationRunner.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "Database.h"
|
||||
|
||||
#include "dCommonVars.h"
|
||||
#include "Game.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
struct Migration {
|
||||
std::string data;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class MigrationRunner {
|
||||
public:
|
||||
static void RunMigrations();
|
||||
static Migration LoadMigration(std::string path);
|
||||
};
|
||||
@@ -49,7 +49,7 @@ CDActivitiesTable::CDActivitiesTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDActivitiesTable::~CDActivitiesTable(void) { }
|
||||
CDActivitiesTable::~CDActivitiesTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDActivitiesTable::GetName(void) const {
|
||||
|
||||
@@ -37,7 +37,7 @@ CDActivityRewardsTable::CDActivityRewardsTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDActivityRewardsTable::~CDActivityRewardsTable(void) { }
|
||||
CDActivityRewardsTable::~CDActivityRewardsTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDActivityRewardsTable::GetName(void) const {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
\brief Contains data for the ActivityRewards table
|
||||
*/
|
||||
|
||||
//! ActivityRewards Entry Struct
|
||||
//! ActivityRewards Entry Struct
|
||||
struct CDActivityRewards {
|
||||
unsigned int objectTemplate; //!< The object template (?)
|
||||
unsigned int ActivityRewardIndex; //!< The activity reward index
|
||||
|
||||
@@ -43,7 +43,7 @@ CDAnimationsTable::CDAnimationsTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDAnimationsTable::~CDAnimationsTable(void) { }
|
||||
CDAnimationsTable::~CDAnimationsTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDAnimationsTable::GetName(void) const {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
\brief Contains data for the Animations table
|
||||
*/
|
||||
|
||||
//! Animations Entry Struct
|
||||
//! Animations Entry Struct
|
||||
struct CDAnimations {
|
||||
unsigned int animationGroupID; //!< The animation group ID
|
||||
std::string animation_type; //!< The animation type
|
||||
|
||||
@@ -3,88 +3,67 @@
|
||||
|
||||
//! Constructor
|
||||
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
|
||||
#ifdef CDCLIENT_CACHE_ALL
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
|
||||
size_t hash = 0;
|
||||
while (!tableData.eof()) {
|
||||
hash = 0;
|
||||
CDBehaviorParameter entry;
|
||||
entry.behaviorID = tableData.getIntField(0, -1);
|
||||
entry.parameterID = tableData.getStringField(1, "");
|
||||
auto candidateStringToAdd = std::string(tableData.getStringField(1, ""));
|
||||
auto parameter = m_ParametersList.find(candidateStringToAdd);
|
||||
if (parameter != m_ParametersList.end()) {
|
||||
entry.parameterID = parameter;
|
||||
} else {
|
||||
entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first;
|
||||
}
|
||||
entry.value = tableData.getFloatField(2, -1.0f);
|
||||
|
||||
//Check if we have an entry with this ID:
|
||||
auto it = m_entries.find(entry.behaviorID);
|
||||
if (it != m_entries.end()) {
|
||||
it->second.insert(std::make_pair(entry.parameterID, entry.value));
|
||||
}
|
||||
else {
|
||||
//Otherwise, insert it:
|
||||
m_entries.insert(std::make_pair(entry.behaviorID, std::map<std::string, float>()));
|
||||
auto jit = m_entries.find(entry.behaviorID);
|
||||
GeneralUtils::hash_combine(hash, entry.behaviorID);
|
||||
GeneralUtils::hash_combine(hash, *entry.parameterID);
|
||||
|
||||
//Add our value as well:
|
||||
jit->second.insert(std::make_pair(entry.parameterID, entry.value));
|
||||
}
|
||||
auto it = m_Entries.find(entry.behaviorID);
|
||||
m_ParametersList.insert(*entry.parameterID);
|
||||
m_Entries.insert(std::make_pair(hash, entry));
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDBehaviorParameterTable::~CDBehaviorParameterTable(void) { }
|
||||
CDBehaviorParameterTable::~CDBehaviorParameterTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDBehaviorParameterTable::GetName(void) const {
|
||||
return "BehaviorParameter";
|
||||
}
|
||||
|
||||
float CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name)
|
||||
{
|
||||
CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
|
||||
CDBehaviorParameter returnValue;
|
||||
returnValue.behaviorID = 0;
|
||||
returnValue.parameterID = m_ParametersList.end();
|
||||
returnValue.value = defaultValue;
|
||||
|
||||
size_t hash = 0;
|
||||
GeneralUtils::hash_combine(hash, behaviorID);
|
||||
GeneralUtils::hash_combine(hash, name);
|
||||
|
||||
// Search for specific perameter
|
||||
// Search for specific parameter
|
||||
const auto& it = m_Entries.find(hash);
|
||||
if (it != m_Entries.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Check if this behavior has already been checked
|
||||
const auto& itChecked = m_Entries.find(behaviorID);
|
||||
if (itChecked != m_Entries.end()) {
|
||||
return itChecked->second;
|
||||
}
|
||||
|
||||
#ifndef CDCLIENT_CACHE_ALL
|
||||
std::stringstream query;
|
||||
|
||||
query << "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = " << std::to_string(behaviorID);
|
||||
|
||||
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
|
||||
|
||||
m_Entries.insert_or_assign(behaviorID, 0);
|
||||
|
||||
while (!tableData.eof()) {
|
||||
const std::string parameterID = tableData.getStringField(0, "");
|
||||
const float value = tableData.getFloatField(1, 0);
|
||||
|
||||
size_t parameterHash = 0;
|
||||
GeneralUtils::hash_combine(parameterHash, behaviorID);
|
||||
GeneralUtils::hash_combine(parameterHash, parameterID);
|
||||
|
||||
m_Entries.insert_or_assign(parameterHash, value);
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
const auto& it2 = m_Entries.find(hash);
|
||||
if (it2 != m_Entries.end()) {
|
||||
return it2->second;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return it != m_Entries.end() ? it->second : returnValue;
|
||||
}
|
||||
|
||||
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
|
||||
size_t hash;
|
||||
std::map<std::string, float> returnInfo;
|
||||
for (auto parameterCandidate : m_ParametersList) {
|
||||
hash = 0;
|
||||
GeneralUtils::hash_combine(hash, behaviorID);
|
||||
GeneralUtils::hash_combine(hash, parameterCandidate);
|
||||
auto infoCandidate = m_Entries.find(hash);
|
||||
if (infoCandidate != m_Entries.end()) {
|
||||
returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value));
|
||||
}
|
||||
}
|
||||
return returnInfo;
|
||||
}
|
||||
|
||||
@@ -2,25 +2,26 @@
|
||||
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/*!
|
||||
\file CDBehaviorParameterTable.hpp
|
||||
\brief Contains data for the BehaviorParameter table
|
||||
*/
|
||||
|
||||
//! BehaviorParameter Entry Struct
|
||||
//! BehaviorParameter Entry Struct
|
||||
struct CDBehaviorParameter {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
std::string parameterID; //!< The Parameter ID
|
||||
std::unordered_set<std::string>::iterator parameterID; //!< The Parameter ID
|
||||
float value; //!< The value of the behavior template
|
||||
};
|
||||
|
||||
//! BehaviorParameter table
|
||||
class CDBehaviorParameterTable : public CDTable {
|
||||
private:
|
||||
std::map<size_t, float> m_Entries;
|
||||
|
||||
std::unordered_map<size_t, CDBehaviorParameter> m_Entries;
|
||||
std::unordered_set<std::string> m_ParametersList;
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
@@ -35,5 +36,7 @@ public:
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
float GetEntry(const uint32_t behaviorID, const std::string& name);
|
||||
CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
|
||||
|
||||
std::map<std::string, float> GetParametersByBehaviorID(uint32_t behaviorID);
|
||||
};
|
||||
|
||||
@@ -24,9 +24,16 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
||||
entry.behaviorID = tableData.getIntField(0, -1);
|
||||
entry.templateID = tableData.getIntField(1, -1);
|
||||
entry.effectID = tableData.getIntField(2, -1);
|
||||
entry.effectHandle = tableData.getStringField(3, "");
|
||||
auto candidateToAdd = tableData.getStringField(3, "");
|
||||
auto parameter = m_EffectHandles.find(candidateToAdd);
|
||||
if (parameter != m_EffectHandles.end()) {
|
||||
entry.effectHandle = parameter;
|
||||
} else {
|
||||
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
|
||||
}
|
||||
|
||||
this->entries.push_back(entry);
|
||||
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -34,7 +41,7 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) { }
|
||||
CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDBehaviorTemplateTable::GetName(void) const {
|
||||
@@ -55,3 +62,16 @@ std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<boo
|
||||
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
|
||||
auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
|
||||
if (entry == this->entriesMappedByBehaviorID.end()) {
|
||||
CDBehaviorTemplate entryToReturn;
|
||||
entryToReturn.behaviorID = 0;
|
||||
entryToReturn.effectHandle = m_EffectHandles.end();
|
||||
entryToReturn.effectID = 0;
|
||||
return entryToReturn;
|
||||
} else {
|
||||
return entry->second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/*!
|
||||
\file CDBehaviorTemplateTable.hpp
|
||||
\brief Contains data for the BehaviorTemplate table
|
||||
*/
|
||||
|
||||
//! BehaviorTemplate Entry Struct
|
||||
//! BehaviorTemplate Entry Struct
|
||||
struct CDBehaviorTemplate {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
unsigned int templateID; //!< The Template ID (LOT)
|
||||
unsigned int effectID; //!< The Effect ID attached
|
||||
std::string effectHandle; //!< The effect handle
|
||||
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +23,8 @@ struct CDBehaviorTemplate {
|
||||
class CDBehaviorTemplateTable : public CDTable {
|
||||
private:
|
||||
std::vector<CDBehaviorTemplate> entries;
|
||||
|
||||
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
|
||||
std::unordered_set<std::string> m_EffectHandles;
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
@@ -48,4 +51,5 @@ public:
|
||||
*/
|
||||
std::vector<CDBehaviorTemplate> GetEntries(void) const;
|
||||
|
||||
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDBrickIDTableTable::~CDBrickIDTableTable(void) { }
|
||||
CDBrickIDTableTable::~CDBrickIDTableTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDBrickIDTableTable::GetName(void) const {
|
||||
|
||||
@@ -28,7 +28,7 @@ CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
|
||||
entry.component_type = tableData.getIntField(1, -1);
|
||||
entry.component_id = tableData.getIntField(2, -1);
|
||||
|
||||
this->mappedEntries.insert_or_assign(((uint64_t) entry.component_type) << 32 | ((uint64_t) entry.id), entry.component_id);
|
||||
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id);
|
||||
|
||||
//this->entries.push_back(entry);
|
||||
|
||||
@@ -56,19 +56,17 @@ CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDComponentsRegistryTable::~CDComponentsRegistryTable(void) { }
|
||||
CDComponentsRegistryTable::~CDComponentsRegistryTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDComponentsRegistryTable::GetName(void) const {
|
||||
return "ComponentsRegistry";
|
||||
}
|
||||
|
||||
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue)
|
||||
{
|
||||
const auto& iter = this->mappedEntries.find(((uint64_t) componentType) << 32 | ((uint64_t) id));
|
||||
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue) {
|
||||
const auto& iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
|
||||
if (iter == this->mappedEntries.end())
|
||||
{
|
||||
if (iter == this->mappedEntries.end()) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@@ -106,8 +104,7 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen
|
||||
if (iter == it->second.end()) {
|
||||
it->second.insert(std::make_pair(entry.component_type, entry.component_id));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
std::map<unsigned int, unsigned int> map;
|
||||
map.insert(std::make_pair(entry.component_type, entry.component_id));
|
||||
this->mappedEntries.insert(std::make_pair(entry.id, map));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
\brief Contains data for the ComponentsRegistry table
|
||||
*/
|
||||
|
||||
//! ComponentsRegistry Entry Struct
|
||||
//! ComponentsRegistry Entry Struct
|
||||
struct CDComponentsRegistry {
|
||||
unsigned int id; //!< The LOT is used as the ID
|
||||
unsigned int component_type; //!< See ComponentTypes enum for values
|
||||
|
||||
@@ -35,7 +35,7 @@ CDCurrencyTableTable::CDCurrencyTableTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDCurrencyTableTable::~CDCurrencyTableTable(void) { }
|
||||
CDCurrencyTableTable::~CDCurrencyTableTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDCurrencyTableTable::GetName(void) const {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
\brief Contains data for the CurrencyTable table
|
||||
*/
|
||||
|
||||
//! CurrencyTable Struct
|
||||
//! CurrencyTable Struct
|
||||
struct CDCurrencyTable {
|
||||
unsigned int currencyIndex; //!< The Currency Index
|
||||
unsigned int npcminlevel; //!< The minimum level of the npc
|
||||
|
||||
@@ -44,7 +44,7 @@ CDDestructibleComponentTable::CDDestructibleComponentTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDDestructibleComponentTable::~CDDestructibleComponentTable(void) { }
|
||||
CDDestructibleComponentTable::~CDDestructibleComponentTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDDestructibleComponentTable::GetName(void) const {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
\brief Contains data for the DestructibleComponent table
|
||||
*/
|
||||
|
||||
//! ItemComponent Struct
|
||||
//! ItemComponent Struct
|
||||
struct CDDestructibleComponent {
|
||||
unsigned int id; //!< The component ID from the ComponentsRegistry Table
|
||||
int faction; //!< The Faction ID of the object
|
||||
|
||||
@@ -35,7 +35,7 @@ std::string CDEmoteTableTable::GetName(void) const {
|
||||
return "Emotes";
|
||||
}
|
||||
|
||||
CDEmoteTable * CDEmoteTableTable::GetEmote(int id) {
|
||||
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
|
||||
for (auto e : entries) {
|
||||
if (e.first == id) return e.second;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
\brief Contains data for the CDEmoteTable table
|
||||
*/
|
||||
|
||||
//! CDEmoteEntry Struct
|
||||
//! CDEmoteEntry Struct
|
||||
struct CDEmoteTable {
|
||||
CDEmoteTable() {
|
||||
ID = -1;
|
||||
|
||||
@@ -35,7 +35,7 @@ CDFeatureGatingTable::CDFeatureGatingTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDFeatureGatingTable::~CDFeatureGatingTable(void) { }
|
||||
CDFeatureGatingTable::~CDFeatureGatingTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDFeatureGatingTable::GetName(void) const {
|
||||
@@ -52,12 +52,9 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
|
||||
return data;
|
||||
}
|
||||
|
||||
bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const
|
||||
{
|
||||
for (const auto& entry : entries)
|
||||
{
|
||||
if (entry.featureName == feature)
|
||||
{
|
||||
bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const {
|
||||
for (const auto& entry : entries) {
|
||||
if (entry.featureName == feature) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
\file CDFeatureGatingTable.hpp
|
||||
*/
|
||||
|
||||
//! ItemComponent Struct
|
||||
//! ItemComponent Struct
|
||||
struct CDFeatureGating {
|
||||
std::string featureName;
|
||||
int32_t major;
|
||||
|
||||
@@ -34,7 +34,7 @@ CDInventoryComponentTable::CDInventoryComponentTable(void) {
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDInventoryComponentTable::~CDInventoryComponentTable(void) { }
|
||||
CDInventoryComponentTable::~CDInventoryComponentTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDInventoryComponentTable::GetName(void) const {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
\brief Contains data for the InventoryComponent table
|
||||
*/
|
||||
|
||||
//! ItemComponent Struct
|
||||
//! ItemComponent Struct
|
||||
struct CDInventoryComponent {
|
||||
unsigned int id; //!< The component ID for this object
|
||||
unsigned int itemid; //!< The LOT of the object
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user