mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-04 02:01:01 -06:00
Compare commits
1333 commits
Jul-31-202
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91bb6be123 | ||
|
|
2419bdb65e | ||
|
|
a6699243db | ||
|
|
a643299b0c | ||
|
|
e611b1780b | ||
|
|
d5527c268f | ||
|
|
5a37f2f8da | ||
|
|
592138d904 | ||
|
|
37b30d7561 | ||
|
|
efc324883b | ||
|
|
be744e73b3 | ||
|
|
ba372ef31f | ||
|
|
6cccaa79de | ||
|
|
9a4566cb0e | ||
|
|
5822b8df99 | ||
|
|
afeffc1b98 | ||
|
|
76523c0130 | ||
|
|
5d82897215 | ||
|
|
9a872f763d | ||
|
|
fd0976e5d5 | ||
|
|
392b13697b | ||
|
|
1d383f0ff3 | ||
|
|
09d9d1ec55 | ||
|
|
97f78b9058 | ||
|
|
5e6c5bdee1 | ||
|
|
e84798c82c | ||
|
|
166ecbacbf | ||
|
|
db960154e6 | ||
|
|
0d1dda90d8 | ||
|
|
559bdb5a68 | ||
|
|
7b55acaddc | ||
|
|
18d5fb62cd | ||
|
|
0fdbf323d6 | ||
|
|
5670ac5e9d | ||
|
|
fd8f672728 | ||
|
|
16187ad211 | ||
|
|
200dfc64f9 | ||
|
|
0443230b85 | ||
|
|
aa8c26f50c | ||
|
|
a5d98df06d | ||
|
|
eb5af4a5a8 | ||
|
|
9bfeea1d18 | ||
|
|
08e2e0b45e | ||
|
|
fecb243650 | ||
|
|
6546016d1a | ||
|
|
fcec1a765b | ||
|
|
34e386dbbf | ||
|
|
2c8885fa60 | ||
|
|
af9aaad94c | ||
|
|
39b6add4e9 | ||
|
|
a3fbce0e6f | ||
|
|
1727cde92f | ||
|
|
66a3410844 | ||
|
|
50e95c1101 | ||
|
|
353266d748 | ||
|
|
6508383fe8 | ||
|
|
dcaf28755d | ||
|
|
73840f7c28 | ||
|
|
c84539003f | ||
|
|
acc02e00d3 | ||
|
|
dc12d2d6ab | ||
|
|
dfcff908fe | ||
|
|
aae03d85fd | ||
|
|
13c4358d77 | ||
|
|
80c8b219ea | ||
|
|
acd0a9e22f | ||
|
|
da41694dd4 | ||
|
|
fc031be6ff | ||
|
|
bc6fd94f46 | ||
|
|
130cc79a17 | ||
|
|
cf6cc08b26 | ||
|
|
f98495d1ae | ||
|
|
50eb7582dd | ||
|
|
501b75aa22 | ||
|
|
0b41c5a146 | ||
|
|
8d7f78ac5b | ||
|
|
5633fbf115 | ||
|
|
7583f6bff2 | ||
|
|
39ac26f5d9 | ||
|
|
bd5ce18fc1 | ||
|
|
4795f25c09 | ||
|
|
4853262c25 | ||
|
|
e66be1b9d1 | ||
|
|
dec9c04fdd | ||
|
|
0c4cfcb1eb | ||
|
|
dd1cfbba51 | ||
|
|
626a3d0f80 | ||
|
|
40a495fcdc | ||
|
|
5d37bb20b0 | ||
|
|
15197bae85 | ||
|
|
0b4ac61c33 | ||
|
|
095f53114e | ||
|
|
5a76a71d21 | ||
|
|
d67fb26749 | ||
|
|
2806c08f7b | ||
|
|
8397452071 | ||
|
|
3793d2477e | ||
|
|
2537c36ad0 | ||
|
|
5d34fac117 | ||
|
|
8fd363a43c | ||
|
|
6479afde2d | ||
|
|
c1a5f74fa6 | ||
|
|
37d3ec002d | ||
|
|
d642c23a2c | ||
|
|
2269baac8a | ||
|
|
5356aa8b37 | ||
|
|
fa2f2af00f | ||
|
|
7d80b80ed8 | ||
|
|
082017b260 | ||
|
|
d1af9c212e | ||
|
|
c83ade9d79 | ||
|
|
12aef9467d | ||
|
|
643cd6c359 | ||
|
|
4eebfd0c7e | ||
|
|
6ffe0aa78c | ||
|
|
595758dbfd | ||
|
|
f837e4ffcc | ||
|
|
23bc594469 | ||
|
|
2bad80f141 | ||
|
|
187c513044 | ||
|
|
6dee708263 | ||
|
|
9ac738d1ea | ||
|
|
2845571082 | ||
|
|
42d871edb0 | ||
|
|
45c3c2488f | ||
|
|
df80d077ce | ||
|
|
496285dfdd | ||
|
|
a10909d54f | ||
|
|
9e690c1877 | ||
|
|
a7b29d7615 | ||
|
|
2e1ecd845b | ||
|
|
97b5892eac | ||
|
|
3692be6fd1 | ||
|
|
b39b75e959 | ||
|
|
f2e8e64cf6 | ||
|
|
a7a7985c84 | ||
|
|
50ef07052e | ||
|
|
18dadc54c8 | ||
|
|
8283ae6ba8 | ||
|
|
1b9dc0572d | ||
|
|
364f6460c8 | ||
|
|
685157543b | ||
|
|
4c2188aab5 | ||
|
|
48f949a452 | ||
|
|
b6b27190be | ||
|
|
3199974f59 | ||
|
|
02607f7121 | ||
|
|
6e9cd98e38 | ||
|
|
6f6ea174ed | ||
|
|
ee694b36b7 | ||
|
|
d8998b6d7d | ||
|
|
ba4cd277f4 | ||
|
|
1a1b238fca | ||
|
|
879f856c38 | ||
|
|
946227b44a | ||
|
|
0c21db9b47 | ||
|
|
0534799e39 | ||
|
|
9903e86ee1 | ||
|
|
014ea60f51 | ||
|
|
8ac850090a | ||
|
|
03e90f7678 | ||
|
|
7276590373 | ||
|
|
0f29ae93ff | ||
|
|
c4a0273c3b | ||
|
|
683af41399 | ||
|
|
8bdfc43fba | ||
|
|
12f217f8f3 | ||
|
|
07e48d91a8 | ||
|
|
0bf2f7d0ec | ||
|
|
a38d3734bd | ||
|
|
96c42c18d9 | ||
|
|
1765f3a3b6 | ||
|
|
5533a2f78a | ||
|
|
846d55365a | ||
|
|
da7c62d10c | ||
|
|
2239168074 | ||
|
|
8ba45e0ee1 | ||
|
|
82e5965220 | ||
|
|
3d5cbd90ed | ||
|
|
feb2b10247 | ||
|
|
56986ad6bc | ||
|
|
6241ff9ce5 | ||
|
|
dfb53cfa03 | ||
|
|
66030f36d6 | ||
|
|
8dd82dd356 | ||
|
|
1fa2d3460f | ||
|
|
78f1c58b4e | ||
|
|
9a7a885818 | ||
|
|
8d182f2505 | ||
|
|
f25f439bdf | ||
|
|
4b3cfae309 | ||
|
|
e6b1203be4 | ||
|
|
8694d36ee8 | ||
|
|
618baf0662 | ||
|
|
f1f5a97859 | ||
|
|
991d4aa364 | ||
|
|
789466e4ab | ||
|
|
f9a193c8d7 | ||
|
|
d1cfe299c6 | ||
|
|
7a23f6f0a3 | ||
|
|
c135877680 | ||
|
|
18f274be8e | ||
|
|
5719d03e4d | ||
|
|
d6f32c56fc | ||
|
|
9eac712626 | ||
|
|
b644a72bfc | ||
|
|
efe936500b | ||
|
|
6d8ef4247c | ||
|
|
676397f3fd | ||
|
|
74cbec067c | ||
|
|
d03df027e0 | ||
|
|
d09bdacf94 | ||
|
|
a6eb6f5af6 | ||
|
|
2ba1174678 | ||
|
|
3dd189d0f3 | ||
|
|
a5b5fdf4d6 | ||
|
|
f39e432432 | ||
|
|
36267b7a67 | ||
|
|
79b3f431c1 | ||
|
|
75fd1dc475 | ||
|
|
12049d8ffb | ||
|
|
1106cbac25 | ||
|
|
891cdf7de1 | ||
|
|
80b1b4b01e | ||
|
|
a0bf0d1d50 | ||
|
|
2471584c42 | ||
|
|
1ff19880ef | ||
|
|
89edf78e54 | ||
|
|
faf2222f4c | ||
|
|
b68f914440 | ||
|
|
c7afeab2ab | ||
|
|
ee9a704ad0 | ||
|
|
93d2c8f4aa | ||
|
|
dc0a0b1cff | ||
|
|
d99e6b2541 | ||
|
|
1ebbed5453 | ||
|
|
af6d260a1e | ||
|
|
9cff5cc314 | ||
|
|
ef0c208bfb | ||
|
|
db05c190fe | ||
|
|
3634616475 | ||
|
|
bef103e259 | ||
|
|
98f662d0c6 | ||
|
|
cb17786a86 | ||
|
|
5c13610776 | ||
|
|
2a438ce349 | ||
|
|
264c2aa550 | ||
|
|
7cf5049687 | ||
|
|
c1d932a6f1 | ||
|
|
0c425033f3 | ||
|
|
e8c3f31786 | ||
|
|
91f3a70f75 | ||
|
|
eebbebe772 | ||
|
|
5a1c7cb141 | ||
|
|
4fb3ae45d8 | ||
|
|
eafa5f42ab | ||
|
|
fc00509b9d | ||
|
|
711ef542fa | ||
|
|
c296e34b50 | ||
|
|
1bdf1ae204 | ||
|
|
53c90ad6d6 | ||
|
|
3a7dfab628 | ||
|
|
02c1835016 | ||
|
|
7c74bfcb71 | ||
|
|
300b714048 | ||
|
|
3d7f1689f3 | ||
|
|
bcc3bc069e | ||
|
|
48bc0ffb28 | ||
|
|
7b1ebd4608 | ||
|
|
1b0a7d5fca | ||
|
|
fc2247f457 | ||
|
|
47ac5e93d6 | ||
|
|
63f8ec3cbf | ||
|
|
0622aed00c | ||
|
|
dda80d535b | ||
|
|
448f970c10 | ||
|
|
83b8689b86 | ||
|
|
6362eee753 | ||
|
|
f0ee476e42 | ||
|
|
0e65f20223 | ||
|
|
af58fae1fc | ||
|
|
74ed5e1bee | ||
|
|
cf08e700fb | ||
|
|
d65a53b275 | ||
|
|
fb9d6307b3 | ||
|
|
45fb89ec73 | ||
|
|
50ba3682b5 | ||
|
|
df73f4a171 | ||
|
|
9eedfc2336 | ||
|
|
e25780a4c5 | ||
|
|
b6560c0e3f | ||
|
|
2d1a626df0 | ||
|
|
4f97dbef8c | ||
|
|
be76ca143b | ||
|
|
053254b504 | ||
|
|
486ca4bb19 | ||
|
|
104533c11d | ||
|
|
9886049429 | ||
|
|
f1131b7d00 | ||
|
|
be47c1d5c9 | ||
|
|
bb860b60e0 | ||
|
|
fed309a70b | ||
|
|
1afd4d5328 | ||
|
|
a6eb706358 | ||
|
|
957477b9b0 | ||
|
|
4387b346dc | ||
|
|
618d39d73c | ||
|
|
62a7dd4324 | ||
|
|
212ce57580 | ||
|
|
8a4ea5d1f3 | ||
|
|
0f14639e9b | ||
|
|
e63c6f523a | ||
|
|
612ccc6776 | ||
|
|
b5784c5782 | ||
|
|
867c332466 | ||
|
|
8b1763c3ba | ||
|
|
d0fdf08d13 | ||
|
|
d91f77c294 | ||
|
|
c03947e0b0 | ||
|
|
acc6c182a5 | ||
|
|
1b85808885 | ||
|
|
2cf8392691 | ||
|
|
4a016d45e5 | ||
|
|
cd43f8d269 | ||
|
|
0a26d5039a | ||
|
|
c3929cf06c | ||
|
|
fcbea5acdc | ||
|
|
3d7e93b6c2 | ||
|
|
6e9f3cb8b9 | ||
|
|
0c8efbac7a | ||
|
|
ccc60b1240 | ||
|
|
818ffc01e7 | ||
|
|
f37b30749e | ||
|
|
edc6f9cf07 | ||
|
|
064edfbbe4 | ||
|
|
b62f4e9525 | ||
|
|
57f5617fe8 | ||
|
|
6c386e6ed2 | ||
|
|
93890769e1 | ||
|
|
4039c0123b | ||
|
|
27f2d457ea | ||
|
|
c6b508b3ed | ||
|
|
67b6855370 | ||
|
|
4480618748 | ||
|
|
9fff4dbb5d | ||
|
|
6a68cf9d7c | ||
|
|
e34a81ec6c | ||
|
|
00b5a44c31 | ||
|
|
f75577d41d | ||
|
|
3838f01adf | ||
|
|
a932c309b3 | ||
|
|
9af776e3c6 | ||
|
|
39634b6caf | ||
|
|
eb3884180e | ||
|
|
d5c7d74767 | ||
|
|
d08656021c | ||
|
|
9beb7219ea | ||
|
|
deecf136bc | ||
|
|
b849de2dab | ||
|
|
b4950343ec | ||
|
|
7749e8263f | ||
|
|
79c69e3d43 | ||
|
|
7d79c9a82a | ||
|
|
e216a6366f | ||
|
|
9054e36288 | ||
|
|
1a67932351 | ||
|
|
7a6adda997 | ||
|
|
1da53c448d | ||
|
|
53dc169774 | ||
|
|
b0be48501b | ||
|
|
98c99e7550 | ||
|
|
ed41f3a228 | ||
|
|
a2eafa8bc0 | ||
|
|
2be5f9eac0 | ||
|
|
876b87b72a | ||
|
|
32cd17bfa2 | ||
|
|
393752d77b | ||
|
|
2b460b64f2 | ||
|
|
59075798ea | ||
|
|
034c05f512 | ||
|
|
01b5e59250 | ||
|
|
7d32e77860 | ||
|
|
f11149ebe2 | ||
|
|
ba1e190cdb | ||
|
|
1c9fbc79aa | ||
|
|
218a040f8b | ||
|
|
cc8dd4edb4 | ||
|
|
3982258500 | ||
|
|
2be422e7da | ||
|
|
5abe50430d | ||
|
|
97b8ed19a6 | ||
|
|
9d38357c4e | ||
|
|
64fa1d89c3 | ||
|
|
e31397b42f | ||
|
|
9f61ffb153 | ||
|
|
b2f7f86d6a | ||
|
|
4799176c14 | ||
|
|
0a89439c80 | ||
|
|
9c202aa47a | ||
|
|
6b0f942598 | ||
|
|
8db9060a40 | ||
|
|
f94221918f | ||
|
|
cc47f4b488 | ||
|
|
5c027e2649 | ||
|
|
4156f28b93 | ||
|
|
c271d4e74b | ||
|
|
97464ef1d2 | ||
|
|
518b5d91dd | ||
|
|
e25c7d7824 | ||
|
|
29fa9a5a21 | ||
|
|
083df1aae2 | ||
|
|
3a73c98e19 | ||
|
|
80cb2d9ba4 | ||
|
|
317b4e9b5c | ||
|
|
24143f5d20 | ||
|
|
209e1ae8cf | ||
|
|
37836ae992 | ||
|
|
d15b47fc65 | ||
|
|
58d9101ef6 | ||
|
|
ca8bfeab64 | ||
|
|
957b1c2944 | ||
|
|
92fcd0ec32 | ||
|
|
db3079271e | ||
|
|
9d6ad223cb | ||
|
|
3837bd3c26 | ||
|
|
18d5d80fba | ||
|
|
9d2e173f71 | ||
|
|
68c1e572b9 | ||
|
|
806680517b | ||
|
|
53357d20f3 | ||
|
|
a44472e559 | ||
|
|
6b152bcc8c | ||
|
|
30f1cbf710 | ||
|
|
0165d373bd | ||
|
|
6f9a975f7a | ||
|
|
21a07841f6 | ||
|
|
81495ab8a8 | ||
|
|
5ed3cafc4a | ||
|
|
0b95cfdb8f | ||
|
|
e8527ff506 | ||
|
|
ef90d24bdc | ||
|
|
a2b0548c62 | ||
|
|
611660cbc3 | ||
|
|
370d9ef423 | ||
|
|
8d2b454b1c | ||
|
|
28b168e742 | ||
|
|
98c0698097 | ||
|
|
80a5c3a85e | ||
|
|
ca3bc9cd70 | ||
|
|
2c3b5cb5a4 | ||
|
|
5f62047aff | ||
|
|
d0f24afc2e | ||
|
|
1f6b0e900f | ||
|
|
ddb9b6f0b0 | ||
|
|
45c21767d5 | ||
|
|
f01a5cfe40 | ||
|
|
36d8186458 | ||
|
|
52cf984540 | ||
|
|
082d3a561b | ||
|
|
dd9f2a34c8 | ||
|
|
49a10d192a | ||
|
|
2776270c7f | ||
|
|
a184b4ce2f | ||
|
|
76d31a68ad | ||
|
|
51929277ac | ||
|
|
07c6eab4af | ||
|
|
dc3daebb59 | ||
|
|
da6f05f8ce | ||
|
|
66b1efdaa3 | ||
|
|
aed73183d1 | ||
|
|
66978b23ee | ||
|
|
f501468ead | ||
|
|
a63867627e | ||
|
|
5d54ef56b3 | ||
|
|
acf27dada5 | ||
|
|
73102d8f79 | ||
|
|
158cf41fd3 | ||
|
|
cdead88473 | ||
|
|
5d21ab74c0 | ||
|
|
782a70a582 | ||
|
|
38a580a431 | ||
|
|
4c736e5aef | ||
|
|
0dcdc84f79 | ||
|
|
6deadc6f90 | ||
|
|
50eb295fda | ||
|
|
24b314426e | ||
|
|
a342f91156 | ||
|
|
64b40fbcf4 | ||
|
|
0ade8bdf02 | ||
|
|
68cf133955 | ||
|
|
7190c3eda7 | ||
|
|
ee9d386bc9 | ||
|
|
2da47d8353 | ||
|
|
5c977c0522 | ||
|
|
2948d58934 | ||
|
|
cde2dcc93f | ||
|
|
4ae1448800 | ||
|
|
b1e6c9fe8c | ||
|
|
a7516f2d6e | ||
|
|
1d4d380e93 | ||
|
|
3b967791a4 | ||
|
|
c96fa24999 | ||
|
|
bbfa1bb1e7 | ||
|
|
675f0c1e37 | ||
|
|
b8a887b319 | ||
|
|
a1fc0ba7cc | ||
|
|
a11b783c39 | ||
|
|
b22c6057a3 | ||
|
|
6e9183ea8f | ||
|
|
ed47883bea | ||
|
|
60e6049971 | ||
|
|
06038dbbdc | ||
|
|
ca53059131 | ||
|
|
6cb4f118ea | ||
|
|
6856d75d88 | ||
|
|
8729f93d01 | ||
|
|
dbbcf5601e | ||
|
|
d9355ec85f | ||
|
|
43c8f43c49 | ||
|
|
28b7a75538 | ||
|
|
0158d753f0 | ||
|
|
3df5097442 | ||
|
|
866372ad54 | ||
|
|
9ca9f01ca3 | ||
|
|
2714448c61 | ||
|
|
98ee184652 | ||
|
|
6b9a06d175 | ||
|
|
9068874556 | ||
|
|
4f5d753104 | ||
|
|
ae53116fee | ||
|
|
9e5a7aefc8 | ||
|
|
6e2f8c6f30 | ||
|
|
affb2e58e9 | ||
|
|
fff1476714 | ||
|
|
08241eb1db | ||
|
|
1d12dd741f | ||
|
|
38c50c465d | ||
|
|
7804dfe791 | ||
|
|
37a874f471 | ||
|
|
b33517632e | ||
|
|
ed199e1478 | ||
|
|
435ec3b1b6 | ||
|
|
451fa73e3e | ||
|
|
2255238554 | ||
|
|
9a5f1e85e2 | ||
|
|
020d5a9c05 | ||
|
|
a7b5e77318 | ||
|
|
66445f61a5 | ||
|
|
13e5bf1666 | ||
|
|
dff56510da | ||
|
|
2449bfe241 | ||
|
|
4ec0f4aa27 | ||
|
|
0f9e264788 | ||
|
|
86973b6d36 | ||
|
|
6763758196 | ||
|
|
4fc5e088ad | ||
|
|
12daa614bb | ||
|
|
9b484d337c | ||
|
|
a13b38d6c1 | ||
|
|
1218ee000f | ||
|
|
0a6b607700 | ||
|
|
279cfb8b42 | ||
|
|
ee88bfe3f0 | ||
|
|
04ce0879c8 | ||
|
|
85ee81a42a | ||
|
|
81fd565b4f | ||
|
|
ece16af7ab | ||
|
|
9d19ce2355 | ||
|
|
cecb937145 | ||
|
|
0cad82029d | ||
|
|
25e9104375 | ||
|
|
6c28a82ebb | ||
|
|
7a4c2159a4 | ||
|
|
ae22b99888 | ||
|
|
7fb90f5afe | ||
|
|
d3f1914117 | ||
|
|
c70c292943 | ||
|
|
8f7683aee4 | ||
|
|
26245dfb10 | ||
|
|
b2eb9cfdc9 | ||
|
|
2dce4fe98c | ||
|
|
6d0ca0d6fc | ||
|
|
cd4d0ec20b | ||
|
|
8ef5d8bce4 | ||
|
|
098d947d87 | ||
|
|
5a6a148cfc | ||
|
|
18fa8357a8 | ||
|
|
e1b7eeaf22 | ||
|
|
b834ff7404 | ||
|
|
a04c36f5cd | ||
|
|
04882136f8 | ||
|
|
d08882cf58 | ||
|
|
f28076f3a4 | ||
|
|
978d70ad0c | ||
|
|
af4a316fa1 | ||
|
|
dbb8b5a133 | ||
|
|
0eecab4057 | ||
|
|
8316a492c9 | ||
|
|
2ab3c34402 | ||
|
|
70a47aeb5d | ||
|
|
7d1a16f7f7 | ||
|
|
eb18fef53d | ||
|
|
b7851e7671 | ||
|
|
fee56ae528 | ||
|
|
a74583b13b | ||
|
|
4942ae0079 | ||
|
|
9445a2bae5 | ||
|
|
3c9dea2830 | ||
|
|
1f2bd0f9fc | ||
|
|
ae0b384e44 | ||
|
|
b640ab7373 | ||
|
|
48e09a3f8a | ||
|
|
5f4450c7d2 | ||
|
|
3b150660b1 | ||
|
|
2bcb05ee6c | ||
|
|
e2a13465b6 | ||
|
|
0779a550a3 | ||
|
|
c03fa76ea1 | ||
|
|
874c3883e6 | ||
|
|
a190544519 | ||
|
|
102cc65fd2 | ||
|
|
0e6b4ad816 | ||
|
|
5237051e71 | ||
|
|
0eaa6000e0 | ||
|
|
4e1ddaeec5 | ||
|
|
b308e488f9 | ||
|
|
264f78eb11 | ||
|
|
9989ee9905 | ||
|
|
1913d0c83f | ||
|
|
0f083bcaaa | ||
|
|
150e0619c1 | ||
|
|
663558cc8c | ||
|
|
44f7c7bd78 | ||
|
|
3638cf60f7 | ||
|
|
d429d3023b | ||
|
|
ba1807c76f | ||
|
|
aaebd7478d | ||
|
|
6325ffefbb | ||
|
|
25e944f37c | ||
|
|
7f9617554a | ||
|
|
7ced5ae031 | ||
|
|
0e87138789 | ||
|
|
ee42a4b82d | ||
|
|
4d3d6e59e1 | ||
|
|
5b1e6de903 | ||
|
|
94a55190ee | ||
|
|
708d5bb507 | ||
|
|
e9fd74b379 | ||
|
|
b87a3821dd | ||
|
|
7c38339e16 | ||
|
|
e5afeed6db | ||
|
|
cc989d5844 | ||
|
|
3a72aadbab | ||
|
|
db396893f2 | ||
|
|
d9c0c58bbb | ||
|
|
dd16588c13 | ||
|
|
96039978aa | ||
|
|
0f1f4dec96 | ||
|
|
dfdc9dc6a5 | ||
|
|
f6e83eb28f | ||
|
|
3c57be80e1 | ||
|
|
b477a62a7d | ||
|
|
73ed09b6ba | ||
|
|
e3dd47431e | ||
|
|
25082c2bb2 | ||
|
|
470105ae36 | ||
|
|
e12658ade9 | ||
|
|
7320bcfd0b | ||
|
|
5e6f750cee | ||
|
|
0b6be66cfd | ||
|
|
4e9f932cfb | ||
|
|
56b195bd9e | ||
|
|
608ffcfd90 | ||
|
|
bff955d629 | ||
|
|
e264ae8eee | ||
|
|
9ea32d07eb | ||
|
|
e67ca4948b | ||
|
|
f4163e733a | ||
|
|
5baa876a55 | ||
|
|
bb46e3f37f | ||
|
|
8a87fa488d | ||
|
|
8148a453d0 | ||
|
|
aa37cd4688 | ||
|
|
ff21a3948d | ||
|
|
c99dfe7031 | ||
|
|
e60eecc6bf | ||
|
|
0028be9cda | ||
|
|
4520a05636 | ||
|
|
b80c98acd6 | ||
|
|
c269949986 | ||
|
|
cbeb422411 | ||
|
|
ac5c31747f | ||
|
|
99e83a57e3 | ||
|
|
7383454728 | ||
|
|
42f0b7c3b2 | ||
|
|
6cd35dc482 | ||
|
|
a26c886586 | ||
|
|
ee94ba03c2 | ||
|
|
049920b3fc | ||
|
|
895c41756a | ||
|
|
d4e62c0e96 | ||
|
|
544487218a | ||
|
|
fa45bcfe70 | ||
|
|
1ab6773910 | ||
|
|
72853d225d | ||
|
|
12eaa1e05a | ||
|
|
3b0360eb01 | ||
|
|
abe55aa7f3 | ||
|
|
0c6b6540f4 | ||
|
|
9e4f94867e | ||
|
|
081f14b5e8 | ||
|
|
2747eb61ec | ||
|
|
8116cae7df | ||
|
|
a0435fb890 | ||
|
|
4276ed731d | ||
|
|
93082bc94a | ||
|
|
1d775bd2d3 | ||
|
|
032cb2e900 | ||
|
|
ad8f77c33e | ||
|
|
50dce880c1 | ||
|
|
e9fa9d0d41 | ||
|
|
e84192d985 | ||
|
|
10a6a19e9e | ||
|
|
0200ff058e | ||
|
|
c52e02936d | ||
|
|
00af62e449 | ||
|
|
9290d67000 | ||
|
|
9cee4dd38a | ||
|
|
3d9a3615f8 | ||
|
|
a105821427 | ||
|
|
7a585796be | ||
|
|
f8cdb5cff5 | ||
|
|
e424478a1c | ||
|
|
5cb9ef8511 | ||
|
|
1b4e0aafaa | ||
|
|
0eca9521bc | ||
|
|
d666317a68 | ||
|
|
162cfe3d6b | ||
|
|
11ebc0c0c4 | ||
|
|
dd017c85d2 | ||
|
|
3d2c0f2baa | ||
|
|
232cae454a | ||
|
|
86a25dd76f | ||
|
|
678d25dacd | ||
|
|
a3e6df109d | ||
|
|
bb21ad533b | ||
|
|
6112abf673 | ||
|
|
95012b9ca5 | ||
|
|
35f9a92aef | ||
|
|
2e70a9714a | ||
|
|
418f239261 | ||
|
|
98a5b95407 | ||
|
|
6a3e91f13c | ||
|
|
1be9335815 | ||
|
|
0f908a1544 | ||
|
|
8b6678d4ee | ||
|
|
d14b2c7d09 | ||
|
|
dd6909908c | ||
|
|
ab17ef11a1 | ||
|
|
c6cd12703f | ||
|
|
1b996b9b82 | ||
|
|
c23051db93 | ||
|
|
604925f513 | ||
|
|
31e865759e | ||
|
|
16a7640e56 | ||
|
|
6cf0e03177 | ||
|
|
b34e99d156 | ||
|
|
cf8b56c0f4 | ||
|
|
0ca2b8d99c | ||
|
|
4098f2bf0b | ||
|
|
255fc9eca6 | ||
|
|
9f7e633c2b | ||
|
|
e7fa5b576d | ||
|
|
fd5998453d | ||
|
|
6d23ec5234 | ||
|
|
105f7d5b86 | ||
|
|
ee79b0750c | ||
|
|
ac0da92a58 | ||
|
|
6147293431 | ||
|
|
bf26faf2a2 | ||
|
|
aa038882e8 | ||
|
|
d76b99c77a | ||
|
|
3cf73ba09a | ||
|
|
9b08f2175b | ||
|
|
32e1111fc7 | ||
|
|
686a2c9141 | ||
|
|
421c419f69 | ||
|
|
661390e66f | ||
|
|
bda000f220 | ||
|
|
af3ee7fe09 | ||
|
|
cf07fc3787 | ||
|
|
cb34966f38 | ||
|
|
defe780c39 | ||
|
|
36dc23ae38 | ||
|
|
58fff59f1b | ||
|
|
2e6eed69e6 | ||
|
|
942fd2876e | ||
|
|
6de25bd7e1 | ||
|
|
845d8b383b | ||
|
|
0372937353 | ||
|
|
ab552ce387 | ||
|
|
fa1f7296f2 | ||
|
|
ca242c056c | ||
|
|
c9e3ad4335 | ||
|
|
d58d4857b0 | ||
|
|
6d96611d69 | ||
|
|
caad0ceaf9 | ||
|
|
417db14d5c | ||
|
|
a6d5961226 | ||
|
|
45bedcf1cb | ||
|
|
2f74cdaff8 | ||
|
|
788a9ca405 | ||
|
|
1ab2b9db01 | ||
|
|
cb16fe4305 | ||
|
|
9b822d1dff | ||
|
|
e7eec2ebf7 | ||
|
|
64aae6ca6b | ||
|
|
06e8279f2a | ||
|
|
da33c89a70 | ||
|
|
e965b8bb41 | ||
|
|
2f4781e4ce | ||
|
|
c7e8c54068 | ||
|
|
a09a35ed5c | ||
|
|
89cbbe2765 | ||
|
|
e9a373e328 | ||
|
|
02e06a9591 | ||
|
|
e0f99de75b | ||
|
|
cef956722a | ||
|
|
1672646e87 | ||
|
|
30c9a752bf | ||
|
|
2a3ac5ffab | ||
|
|
eb65c4c78b | ||
|
|
3d8857e01c | ||
|
|
f26a4660ea | ||
|
|
2f234cc589 | ||
|
|
aab37414c3 | ||
|
|
d04302c99f | ||
|
|
22776e7bb3 | ||
|
|
51ab17e3aa | ||
|
|
7997fbb0b0 | ||
|
|
4bd97d002f | ||
|
|
330d66918a | ||
|
|
c58309e685 | ||
|
|
7ca0493190 | ||
|
|
74380b039b | ||
|
|
33064660cf | ||
|
|
bd12800cca | ||
|
|
f613fb13cd | ||
|
|
c20770fcb3 | ||
|
|
f6cd646205 | ||
|
|
f5711fcf8f | ||
|
|
3d20bb97d0 | ||
|
|
c1b2fdf597 | ||
|
|
b6d02cce17 | ||
|
|
810528dfb4 | ||
|
|
37fe071041 | ||
|
|
df5b260f5f | ||
|
|
c3d48ff36e | ||
|
|
3d8a6c6e5a | ||
|
|
048a745371 | ||
|
|
c1007683a5 | ||
|
|
047a2b818a | ||
|
|
bf91e47ddc | ||
|
|
8bbe8cf57d | ||
|
|
d492500812 | ||
|
|
fc9f23385f | ||
|
|
d5222bad1e | ||
|
|
0a41704490 | ||
|
|
48cc5048af | ||
|
|
aec9476438 | ||
|
|
c266e9ecaa | ||
|
|
a313c227d5 | ||
|
|
9a25c2a87d | ||
|
|
817d2f0ec2 | ||
|
|
0c54348f69 | ||
|
|
cb4c94f3ab | ||
|
|
9150137c47 | ||
|
|
7b0c1b0b9b | ||
|
|
47576b63f0 | ||
|
|
cb630e7043 | ||
|
|
5404ef849d | ||
|
|
c3c836de4d | ||
|
|
6dcec3c42f | ||
|
|
f7941f80ab | ||
|
|
f9657b75f6 | ||
|
|
2cb8d82648 | ||
|
|
9329d9d008 | ||
|
|
47d9c6c4b1 | ||
|
|
6eed461162 | ||
|
|
b995436ea4 | ||
|
|
f7b707c3da | ||
|
|
c04ee0f821 | ||
|
|
767117f54e | ||
|
|
a04191b11e | ||
|
|
9f6e7b49be | ||
|
|
2ee8e19668 | ||
|
|
e7ccab2ad9 | ||
|
|
52633544ff | ||
|
|
69f4f11bc7 | ||
|
|
c885ebb7e8 | ||
|
|
6bebd1d53a | ||
|
|
d0ae674155 | ||
|
|
ce7f249880 | ||
|
|
2fc98ad0df | ||
|
|
bb41f61263 | ||
|
|
130d2c5af0 | ||
|
|
1f270ae8f0 | ||
|
|
9854e207ae | ||
|
|
572ebeef84 | ||
|
|
a9a6c07c1a | ||
|
|
b43d84295c | ||
|
|
1f38c8fc8c | ||
|
|
05da44aa52 | ||
|
|
0af42c77c8 | ||
|
|
068b252db6 | ||
|
|
35d3b371d2 | ||
|
|
f9fb929b45 | ||
|
|
0fe5de8206 | ||
|
|
323c653275 | ||
|
|
4b20cdd001 | ||
|
|
5aded2b349 | ||
|
|
24ff23b148 | ||
|
|
99425f0991 | ||
|
|
9619f5b3a7 | ||
|
|
f92fde2800 | ||
|
|
f6096e3020 | ||
|
|
41c970efd4 | ||
|
|
1323684153 | ||
|
|
642d946c17 | ||
|
|
d4565fd728 | ||
|
|
75d99e17f0 | ||
|
|
cb92ad0577 | ||
|
|
4ded3b90de | ||
|
|
957540c362 | ||
|
|
2025949265 | ||
|
|
7a4fdfb410 | ||
|
|
fed72384ba | ||
|
|
034cc75a61 | ||
|
|
dd3c957f8b | ||
|
|
fc28c97400 | ||
|
|
dcdeefe85e | ||
|
|
c0ffe59d47 | ||
|
|
af99895168 | ||
|
|
2273550fea | ||
|
|
d4af3421ba | ||
|
|
d431fec1ed | ||
|
|
ebebb05af3 | ||
|
|
8d0493bf9d | ||
|
|
b1ed4461af | ||
|
|
757b13544a | ||
|
|
91ec97220b | ||
|
|
9f85619334 | ||
|
|
374ad2f2e5 | ||
|
|
a52af89cad | ||
|
|
b9050c0e3c | ||
|
|
ffb7486a01 | ||
|
|
3c2b852473 | ||
|
|
a9214486cf | ||
|
|
76f128343e | ||
|
|
c342baa138 | ||
|
|
353bbbd61a | ||
|
|
27661f711f | ||
|
|
0cb814d26e | ||
|
|
7ec901297b | ||
|
|
48805eea66 | ||
|
|
ed708b5fb8 | ||
|
|
d9245b8aee | ||
|
|
459b360897 | ||
|
|
ab2842af14 | ||
|
|
8b62e42323 | ||
|
|
c3cfecb5fa | ||
|
|
55c619bf87 | ||
|
|
ff18f69dd0 | ||
|
|
c2cb359bf7 | ||
|
|
e03187920b | ||
|
|
eeedafe637 | ||
|
|
f1e2083506 | ||
|
|
b6fa73d94c | ||
|
|
0546d7e8b9 | ||
|
|
d91f569aff | ||
|
|
17d1a9619c | ||
|
|
72204740df | ||
|
|
745f8b63b0 | ||
|
|
97f4fa91ca | ||
|
|
35e1477c24 | ||
|
|
c42daa5dba | ||
|
|
214ba50ecc | ||
|
|
64a12fe5c8 | ||
|
|
276cb0f7c6 | ||
|
|
9020d1e474 | ||
|
|
bcb2a9386d | ||
|
|
adcdf9bd6a | ||
|
|
88a2f354b4 | ||
|
|
e1faa64af7 | ||
|
|
6d182a5984 | ||
|
|
8202d44051 | ||
|
|
9a4b933976 | ||
|
|
f0d7b82bf9 | ||
|
|
a5f94d736a | ||
|
|
81321e44e1 | ||
|
|
716fcb7209 | ||
|
|
09f553d998 | ||
|
|
f00fd246b9 | ||
|
|
35a97946ac | ||
|
|
3445b792c8 | ||
|
|
124eeab893 | ||
|
|
5206c99151 | ||
|
|
dcaa980822 | ||
|
|
50a9580505 | ||
|
|
06632a6918 | ||
|
|
f9dbfe9a77 | ||
|
|
4d652e7f02 | ||
|
|
cc2e5f8775 | ||
|
|
aa0632d274 | ||
|
|
e8522b1e62 | ||
|
|
7ade40ace2 | ||
|
|
73cbc9f11e | ||
|
|
6c9458cdac | ||
|
|
0fa8a1c87e | ||
|
|
a88fde30ed | ||
|
|
675d576c58 | ||
|
|
86405d89f4 | ||
|
|
4ee6f3f752 | ||
|
|
7600ac8b49 | ||
|
|
8bad573568 | ||
|
|
c4ef6401a4 | ||
|
|
7a42de63dc | ||
|
|
4f600b2a59 | ||
|
|
097615cc7d | ||
|
|
cecd6f1947 | ||
|
|
d75e40b98c | ||
|
|
17db0f27ef | ||
|
|
52b8100c09 | ||
|
|
e016d55630 | ||
|
|
254089d34e | ||
|
|
7f6752ba8a | ||
|
|
6b90e17f1c | ||
|
|
34f8db2557 | ||
|
|
f243293e8c | ||
|
|
79696dfdde | ||
|
|
0d127b109a | ||
|
|
d608f9aeb6 | ||
|
|
5962459ca1 | ||
|
|
0ee77026ba | ||
|
|
39251fc75f | ||
|
|
69f950eb57 | ||
|
|
0236874a2e | ||
|
|
c85400b3e2 | ||
|
|
e091a45931 | ||
|
|
e5336f4438 | ||
|
|
4971985d44 | ||
|
|
8dadaa5089 | ||
|
|
97c7e7e3d4 | ||
|
|
7646bbaccd | ||
|
|
e1fa33b4dd | ||
|
|
9fc92f52f4 | ||
|
|
c112794ede | ||
|
|
710671eb99 | ||
|
|
df345d782f | ||
|
|
406552fae4 | ||
|
|
c54f03d8cc | ||
|
|
798c357291 | ||
|
|
05b414fdf6 | ||
|
|
3940f3bd47 | ||
|
|
cc1eca5237 | ||
|
|
e8c22249a2 | ||
|
|
4008f78433 | ||
|
|
1a1da2b71b | ||
|
|
b2f90d3dcc | ||
|
|
a100affda2 | ||
|
|
e4b799c44a | ||
|
|
4fe916990e | ||
|
|
2eb7a19546 | ||
|
|
6cfcefb13a | ||
|
|
c39b1c18ff | ||
|
|
5635e9235e | ||
|
|
ce2a95fa51 | ||
|
|
b4a17f6710 | ||
|
|
4e6e2e678d | ||
|
|
dd5e63a409 | ||
|
|
86efa69213 | ||
|
|
2306efbbe4 | ||
|
|
463a0900d7 | ||
|
|
cb753f2a12 | ||
|
|
f124e27f33 | ||
|
|
5adaf1a422 | ||
|
|
a88c98bc9a | ||
|
|
bdb014711c | ||
|
|
9060a5bb2a | ||
|
|
c479960b7a | ||
|
|
73bee78d31 | ||
|
|
be10a69325 | ||
|
|
2fc558b585 | ||
|
|
9b6a817c9d | ||
|
|
5011b8648b | ||
|
|
c9a6bf2f61 | ||
|
|
c1b1bcc80d | ||
|
|
40e3cef387 | ||
|
|
69b706c3f3 | ||
|
|
55f736b711 | ||
|
|
5816423628 | ||
|
|
d808dd1137 | ||
|
|
94b94cb5a3 | ||
|
|
4848d465e3 | ||
|
|
b96a1e370b | ||
|
|
b387e993bb | ||
|
|
7750471015 | ||
|
|
99e416d66e | ||
|
|
ffe5b6d2d3 | ||
|
|
dbb0939441 | ||
|
|
1e3e43ab2d | ||
|
|
8188c72417 | ||
|
|
9866afbd5d | ||
|
|
2fa08e38c6 | ||
|
|
89bcf30746 | ||
|
|
760653067a | ||
|
|
0f4f17577f | ||
|
|
e8ea397b6b | ||
|
|
00d460d2ba | ||
|
|
43a03b9b66 | ||
|
|
6b5758ed7a | ||
|
|
12f2c308aa | ||
|
|
412e364a31 | ||
|
|
c050c294e5 | ||
|
|
6fe6f25a01 | ||
|
|
e447a45c56 | ||
|
|
09771312fc | ||
|
|
97e74320fb | ||
|
|
4193e6131c | ||
|
|
7f9656d40a | ||
|
|
5f6bbf4d63 | ||
|
|
0a446933aa | ||
|
|
d8818f1f69 | ||
|
|
59f263d386 | ||
|
|
1b046e702c | ||
|
|
97e5f76b47 | ||
|
|
3502a51708 | ||
|
|
8c21c8669d | ||
|
|
eee6868eb9 | ||
|
|
dc71c07473 | ||
|
|
8b64a713e4 | ||
|
|
e29d8a9789 | ||
|
|
ea63c401f6 | ||
|
|
c61f1d825c | ||
|
|
f5fa84bc9d | ||
|
|
6723301504 | ||
|
|
e76432c25a | ||
|
|
1fe55fc848 | ||
|
|
729a587efc | ||
|
|
eadbdfd71f | ||
|
|
60cf2472b6 | ||
|
|
41f1b7f3a7 | ||
|
|
d9994eda3f | ||
|
|
26aa6cc759 | ||
|
|
14c972fcc4 | ||
|
|
f87dc65d97 | ||
|
|
bef5c8e07e | ||
|
|
c71b0635ff | ||
|
|
175669af15 | ||
|
|
a608f1ab3a | ||
|
|
c7fd4a218f | ||
|
|
aa084de65b | ||
|
|
f884e7712c | ||
|
|
aa935855c9 | ||
|
|
9145fd038c | ||
|
|
9830863a09 | ||
|
|
ff666178b9 | ||
|
|
1d953ebc9f | ||
|
|
a0e1c8007d | ||
|
|
78a7a34cae | ||
|
|
7e0bc62b1e | ||
|
|
c9950d6f16 | ||
|
|
d855bca684 | ||
|
|
1e3cf4f6fa | ||
|
|
c5e5dfa78f | ||
|
|
712b44f008 | ||
|
|
b64a595562 | ||
|
|
5b6dc9978e | ||
|
|
660eaf1a61 | ||
|
|
32931ef85c | ||
|
|
7b1a9f1efa | ||
|
|
e92a02a603 | ||
|
|
4f7e07436b | ||
|
|
3d6c91b487 | ||
|
|
5baa488301 | ||
|
|
6096fca708 | ||
|
|
82f7d0663b | ||
|
|
0bdd8326d9 | ||
|
|
d3efb5cecd | ||
|
|
c7ff6a147a | ||
|
|
29b76c0c4c | ||
|
|
47647ec1af | ||
|
|
7462266756 | ||
|
|
bb0ae3ad8d | ||
|
|
ac0ba2ece9 | ||
|
|
90d47eb75e | ||
|
|
7233c968f6 | ||
|
|
c74048425c | ||
|
|
eae259d2ec | ||
|
|
22b7b7ab98 | ||
|
|
50150337cb | ||
|
|
6a2edfcbd0 | ||
|
|
4213bbc53e | ||
|
|
06f64564d8 | ||
|
|
4fc8c0ac23 | ||
|
|
4a239d107f | ||
|
|
ce5c2b5182 | ||
|
|
d7e90822a3 | ||
|
|
63e5c9a6b8 | ||
|
|
0a014e86f3 | ||
|
|
121f8d2723 | ||
|
|
3c2810b539 | ||
|
|
924e9bd2a6 | ||
|
|
e0b9c0ab50 | ||
|
|
f4d0754ed7 | ||
|
|
1f078ed0f4 | ||
|
|
39cf1f60ca | ||
|
|
30f43e1a18 | ||
|
|
f76d32c203 | ||
|
|
066422e7cd | ||
|
|
82fa035c69 | ||
|
|
4f70c89104 | ||
|
|
fe6d04c620 | ||
|
|
c4901fa4b8 | ||
|
|
6c340aa96b | ||
|
|
5af39b5b21 | ||
|
|
6edc2eb81c | ||
|
|
fd457a9cea | ||
|
|
0e945a26a4 | ||
|
|
c917c0c1dd | ||
|
|
840ea1f5ed | ||
|
|
386ab2eb61 | ||
|
|
2115f1cb31 | ||
|
|
18a0d83fbb | ||
|
|
bd3a30c209 | ||
|
|
e0c68ef7ef | ||
|
|
0fcf442ec5 | ||
|
|
c8bf7b5342 | ||
|
|
a8751eaa3c | ||
|
|
7a91aca78f | ||
|
|
2586c4b66a | ||
|
|
506bbf35f8 | ||
|
|
563d7094e6 | ||
|
|
7cb5485b1b | ||
|
|
7159e56c4d | ||
|
|
b47141aa84 | ||
|
|
6ab68b008f | ||
|
|
37d1ef8ab3 | ||
|
|
3a02203605 | ||
|
|
dbf34fbd4a | ||
|
|
5fd66e50ba | ||
|
|
d2283e6716 | ||
|
|
f406b8aa98 | ||
|
|
95bd5ab4b7 | ||
|
|
003f7eb5e8 | ||
|
|
a9fd970e06 | ||
|
|
338bf3ab70 | ||
|
|
7c4fd7ea36 | ||
|
|
135dcb136c | ||
|
|
5c4134e2e3 | ||
|
|
7824836c7d | ||
|
|
c8f1fd1253 | ||
|
|
854b8cdc6b | ||
|
|
0db90b60f1 | ||
|
|
bcb493a94d | ||
|
|
5aee1e7d9c | ||
|
|
de3cf3e856 | ||
|
|
a2819f81e6 | ||
|
|
6e6f60ee27 | ||
|
|
49db1538f6 | ||
|
|
f295f90f47 | ||
|
|
93f00462b9 | ||
|
|
17ec82d852 | ||
|
|
fee99b2f82 | ||
|
|
a1e9e4b2a1 | ||
|
|
455c7b355c | ||
|
|
15feadf344 | ||
|
|
500c65d436 | ||
|
|
3c06fa4f87 | ||
|
|
c32f5dfa93 | ||
|
|
2d871e5000 | ||
|
|
71fb54fa5a | ||
|
|
54887ace0c | ||
|
|
c3b91b2240 | ||
|
|
785f72215f | ||
|
|
4ecdbbac7e | ||
|
|
5c5e034db6 | ||
|
|
47bd650864 | ||
|
|
6d412048c8 | ||
|
|
9cfa635f0a | ||
|
|
edb9c6ace0 | ||
|
|
f9a34b06e6 | ||
|
|
0ea1438a33 | ||
|
|
2de2f9607d | ||
|
|
131a123eeb | ||
|
|
05e969762e | ||
|
|
65d585a026 | ||
|
|
950074125e | ||
|
|
e76969dc16 | ||
|
|
d22d3c6439 | ||
|
|
7d662d8ab0 | ||
|
|
c8f6f9cb59 | ||
|
|
dff8bf5c14 | ||
|
|
df236d29c9 | ||
|
|
288902d809 | ||
|
|
de8c3f695b | ||
|
|
556efda5c1 | ||
|
|
3e6b156bba | ||
|
|
77b0fc4eb6 | ||
|
|
c3250acce1 | ||
|
|
4930740b6f | ||
|
|
744ee81124 | ||
|
|
ed29db1cb4 | ||
|
|
69aa7a7557 | ||
|
|
e7804fdd42 | ||
|
|
a69253d3d2 | ||
|
|
50e0fe9400 | ||
|
|
21d334a989 | ||
|
|
7690aad9fb | ||
|
|
a52b1abf85 | ||
|
|
41baad6487 | ||
|
|
644bdbfebd | ||
|
|
31734cb540 | ||
|
|
1d9165e874 | ||
|
|
0b15f03174 | ||
|
|
d545b2a119 | ||
|
|
edb9dfe955 | ||
|
|
a2dd8a1f09 | ||
|
|
9226541f4c | ||
|
|
e8adda080f | ||
|
|
b56b1da8cf | ||
|
|
4a27bf689a | ||
|
|
9b9dac25b7 |
4650 changed files with 475577 additions and 645590 deletions
30
.dockerignore
Normal file
30
.dockerignore
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Local volumes
|
||||
/config
|
||||
/data
|
||||
/db
|
||||
|
||||
# Updated through volumes
|
||||
Server/data
|
||||
Server/worldprops
|
||||
|
||||
# Env files containing secrets
|
||||
/.env
|
||||
/*.env
|
||||
|
||||
# Log files
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Git files
|
||||
.git
|
||||
.gitattributes
|
||||
.gitignore
|
||||
|
||||
# Basic stuff
|
||||
*.md
|
||||
LICENSE
|
||||
.gitlab-ci.yml
|
||||
|
||||
# Docker files
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -16,8 +16,10 @@ Server/data/eco/grandexchange.db
|
|||
Server/data/serverstore/
|
||||
Server/data/global_kill_stats.json
|
||||
Server/ge_test.db
|
||||
Server/latestdump.txt
|
||||
Management-Server/managementprops/
|
||||
Server/worldprops/
|
||||
Server/worldprops/*
|
||||
!Server/worldprops/default.conf
|
||||
|
||||
**/.idea/workspace.xml
|
||||
**/.idea/tasks.xml
|
||||
|
|
@ -30,3 +32,13 @@ gradle
|
|||
**/*.swo
|
||||
build/kotlin/sessions/
|
||||
**/*.iml
|
||||
Server/hasRan.txt
|
||||
|
||||
# Local volumes
|
||||
/config
|
||||
/data
|
||||
/db
|
||||
|
||||
# Env files containing secrets
|
||||
/.env
|
||||
/*.env
|
||||
|
|
|
|||
41
.gitlab-ci.yml
Normal file
41
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
variables:
|
||||
# This will suppress any download for dependencies and plugins or upload messages which would clutter the console log.
|
||||
# `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
|
||||
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true -Xmx3g"
|
||||
# As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used
|
||||
# when running from the command line.
|
||||
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-fast --show-version"
|
||||
|
||||
image: maven:3-openjdk-11-slim
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
|
||||
before_script:
|
||||
- 'free -mh'
|
||||
- 'apt-get update -q'
|
||||
|
||||
# Cache downloaded dependencies and plugins between builds.
|
||||
# To keep cache across branches add 'key: "$CI_JOB_NAME"'
|
||||
cache:
|
||||
paths:
|
||||
- .m2/repository
|
||||
|
||||
verify:jdk11:
|
||||
stage: build
|
||||
script:
|
||||
- 'cd Server'
|
||||
- 'mvn $MAVEN_CLI_OPTS verify'
|
||||
except:
|
||||
variables:
|
||||
- $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
|
||||
test:json:
|
||||
stage: test
|
||||
script:
|
||||
- 'apt-get install -q -y --no-install-recommends jq'
|
||||
- 'find . -name \*.json -type f -print0 | xargs -0 -n1 -P8 jq empty'
|
||||
except:
|
||||
variables:
|
||||
- $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
17
.gitlab/issue_templates/Default.md
Normal file
17
.gitlab/issue_templates/Default.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
What I did:
|
||||
|
||||
What I expected to happen:
|
||||
|
||||
What actually happened:
|
||||
|
||||
IDs of related NPCs/items:
|
||||
|
||||
2009-era source (if relevant):
|
||||
|
||||
Screenshots or video:
|
||||
|
||||
LIVE SERVER username affected by this issue:
|
||||
|
||||
**Bug reports are not accepted by SP users. SP is often out of date and results in invalid bug reports.**
|
||||
|
||||
**If the bug is exploitable make sure you tick the confidential checkbox below**
|
||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Starting out with the openjdk-11-slim image
|
||||
FROM maven:3-openjdk-11-slim
|
||||
|
||||
# Set working directory to /app
|
||||
WORKDIR /app
|
||||
|
||||
# Copy all sources etc
|
||||
COPY . .
|
||||
|
||||
# Make sure ./run has permissions
|
||||
RUN chmod +x run
|
||||
|
||||
# Run it
|
||||
CMD ["./run"]
|
||||
BIN
Management-Server/.mvn/wrapper/maven-wrapper.jar
vendored
BIN
Management-Server/.mvn/wrapper/maven-wrapper.jar
vendored
Binary file not shown.
|
|
@ -1,18 +0,0 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="[Linux] Run MS" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/run-ms.sh" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="/bin/bash" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="[Windows] Run MS" type="BatchConfigurationType" factoryName="Batch">
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<module name="" />
|
||||
<option name="SCRIPT_NAME" value="./run-ms.bat" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"DatabaseInformation": {
|
||||
"database_name": "global",
|
||||
"database_username": "root",
|
||||
"database_password": "",
|
||||
"database_host": "127.0.0.1",
|
||||
"database_port": "3306"
|
||||
},
|
||||
|
||||
"WorldTechnicalInformation": {
|
||||
"world_limit": "10",
|
||||
"worldhop_delay": "20000"
|
||||
},
|
||||
"secret_key": "2009scape_development"
|
||||
}
|
||||
287
Management-Server/mvnw
vendored
287
Management-Server/mvnw
vendored
|
|
@ -1,287 +0,0 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.1.1
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`\\unset -f command; \\command -v java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(cd "$basedir"; pwd)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname $0)")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $wrapperUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
QUIET="--quiet"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
QUIET=""
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
[ $? -eq 0 ] || rm -f "$wrapperJarPath"
|
||||
elif command -v curl > /dev/null; then
|
||||
QUIET="--silent"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
QUIET=""
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L
|
||||
fi
|
||||
[ $? -eq 0 ] || rm -f "$wrapperJarPath"
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=`cygpath --path --windows "$javaSource"`
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
187
Management-Server/mvnw.cmd
vendored
187
Management-Server/mvnw.cmd
vendored
|
|
@ -1,187 +0,0 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.1.1
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %WRAPPER_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% ^
|
||||
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||
%MAVEN_OPTS% ^
|
||||
%MAVEN_DEBUG_OPTS% ^
|
||||
-classpath %WRAPPER_JAR% ^
|
||||
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||
|
||||
cmd /C exit /B %ERROR_CODE%
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.rs09</groupId>
|
||||
<artifactId>managementserver</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<properties>
|
||||
<project.mainClassName>ms.Management</project.mainClassName>
|
||||
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
|
||||
<kotlin.version>1.6.21</kotlin.version>
|
||||
<kotlin.comipler.jvmTarget>1.6</kotlin.comipler.jvmTarget>
|
||||
<junit.version>5.7.0</junit.version>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.json-simple</groupId>
|
||||
<artifactId>json-simple</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ajalt.mordant</groupId>
|
||||
<artifactId>mordant-jvm</artifactId>
|
||||
<version>2.0.0-beta6</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.21</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<archive>
|
||||
<manifest><mainClass>${project.mainClassName}</mainClass></manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
|
||||
<sourceDir>${project.basedir}/src/main/java</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals> <goal>test-compile</goal> </goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<useIncrementalCompilation>false</useIncrementalCompilation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<!-- Replacing default-compile as it is treated specially by maven -->
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<!-- Replacing default-testCompile as it is treated specially by maven -->
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.22.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
package ms;
|
||||
|
||||
import ms.net.NioReactor;
|
||||
import ms.net.packet.IoBuffer;
|
||||
import ms.net.packet.PacketHeader;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.ShutdownSequence;
|
||||
import ms.system.mysql.SQLManager;
|
||||
import ms.system.util.Command;
|
||||
import ms.system.util.ManagementConfigParser;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* The main class.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class Management {
|
||||
|
||||
/**
|
||||
* If the shutdown hook is active.
|
||||
*/
|
||||
public static boolean active = true;
|
||||
|
||||
/**
|
||||
* The commands.
|
||||
*/
|
||||
private static final Command[] COMMANDS = {
|
||||
new Command("-commands", "Print a list of all commands.") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
for (Command c : COMMANDS) {
|
||||
System.out.println("Command " + c.getName() + ": " + c.getInfo());
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("-s", "Safely shuts down the server.") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
System.out.println("Shutting down Management server...");
|
||||
ShutdownSequence.shutdown();
|
||||
}
|
||||
},
|
||||
new Command("-debug", "Debug world info.") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
System.out.println("---------------------------------------------");
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null) {
|
||||
System.out.println("World [id=" + server.getInfo().getWorldId() + ", IP=" + server.getInfo().getAddress() + ", country=" + server.getInfo().getCountry() + ", members=" + server.getInfo().isMembers() + ", players=" + server.getPlayers().size() + ", active=" + server.isActive() + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("-pinfo", "Debugs player information (usage: -pinfo emperor).") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
String name = args[1];
|
||||
PlayerSession player = WorldDatabase.getPlayer(name);
|
||||
if (player == null) {
|
||||
System.out.println("Player " + name + " was not registered!");
|
||||
return;
|
||||
}
|
||||
System.out.println("Player [name=" + name + ", world=" + player.getWorldId() + ", active=" + player.isActive() + "].");
|
||||
}
|
||||
},
|
||||
new Command("-update", "Calls an update on all the game servers (-update -1 to cancel).") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
int ticks = Integer.parseInt(args[1]);
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.sendUpdate(server, ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("-reloadconfig", "Reloads the configurations of all worlds.") {
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if(server == null) {
|
||||
continue;
|
||||
}
|
||||
WorldPacketRepository.sendConfigReload(server);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
new Command("-rlcache", "Reloads launcher/client resource cache") {
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
System.out.println("Reloaded resource cache!");
|
||||
}
|
||||
},
|
||||
|
||||
new Command("-kick", "Kicks a player from the MS (not ingame).") {
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
String name = args[1];
|
||||
PlayerSession player = WorldDatabase.getPlayer(name);
|
||||
if (player == null) {
|
||||
System.out.println("Player " + name + " was not registered!");
|
||||
return;
|
||||
}
|
||||
player.getWorld().getPlayers().remove(name);
|
||||
player.setWorldId(0);
|
||||
System.out.println("Kicked player " + name + "!");
|
||||
}
|
||||
},
|
||||
|
||||
new Command("-say", "Send a message to all worlds") {
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
String message = String.join(" ", args);
|
||||
message = message.substring(4);
|
||||
for(GameServer server : WorldDatabase.getWorlds()){
|
||||
if(server == null) continue;
|
||||
String finalMessage = message;
|
||||
server.getPlayers().forEach((String uname, PlayerSession p) -> {
|
||||
IoBuffer buffer = new IoBuffer(5, PacketHeader.BYTE);
|
||||
buffer.putString(p.getUsername());
|
||||
buffer.putString("Server");
|
||||
buffer.put(2);
|
||||
buffer.put(2);
|
||||
buffer.putString(finalMessage);
|
||||
p.getWorld().getSession().write(buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* @param args The arguments cast on runtime.
|
||||
* @throws Throwable When an exception occurs.
|
||||
*/
|
||||
public static void main(String...args) throws Throwable {
|
||||
if (!isLocallyHosted(ServerConstants.HOST_ADDRESS)) {
|
||||
System.err.println("WARNING: Configure host address in server constants!");
|
||||
}
|
||||
System.out.println("-------- 530 Management server --------");
|
||||
System.out.println("Starting up...");
|
||||
new ManagementConfigParser("managementprops" + File.separator + "properties.json");
|
||||
SQLManager.init();
|
||||
//NioReactor.configure(ServerConstants.PORT).start();
|
||||
NioReactor.configure(5555).start();
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownSequence());
|
||||
System.out.println("Status: ready.");
|
||||
System.out.println("Use -commands for a list of commands!");
|
||||
Scanner s = new Scanner(new InputStreamReader(System.in, StandardCharsets.UTF_8));
|
||||
while (s.hasNext()) {
|
||||
try {
|
||||
String command = s.nextLine();
|
||||
if (!command.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
String[] arguments = command.split(" ");
|
||||
command = arguments[0];
|
||||
for (Command c : COMMANDS) {
|
||||
if (c.getName().equals(command)) {
|
||||
System.out.println("Handling command \"" + command + "\"!");
|
||||
c.run(arguments);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
s.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the Management server is locally hosted.
|
||||
* @return {@code True} if so.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
private static boolean isLocallyHosted(String ip) throws IOException {
|
||||
InetAddress address = InetAddress.getByName(ip);
|
||||
if (address.isAnyLocalAddress() || address.isLoopbackAddress()) {
|
||||
return true;
|
||||
}
|
||||
return NetworkInterface.getByInetAddress(address) != null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package ms;
|
||||
|
||||
import ms.system.OperatingSystem;
|
||||
|
||||
/**
|
||||
* Holds constants for the management server.
|
||||
* @author v4rg
|
||||
*
|
||||
*/
|
||||
public final class ServerConstants {
|
||||
|
||||
/**
|
||||
* The maximum amount of worlds.
|
||||
*/
|
||||
public static final int WORLD_LIMIT = 10;
|
||||
|
||||
/**
|
||||
* The world switching delay in milliseconds.
|
||||
*/
|
||||
public static final long WORLD_SWITCH_DELAY = 20_000L;
|
||||
|
||||
/**
|
||||
* The address of the Management server.
|
||||
*/
|
||||
public static final String HOST_ADDRESS = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* The operating system of the management server
|
||||
*/
|
||||
public static final OperatingSystem OS = System.getProperty("os.name").toUpperCase().contains("WIN") ? OperatingSystem.WINDOWS : OperatingSystem.UNIX;
|
||||
|
||||
/**
|
||||
* Stops from instantiating.
|
||||
*/
|
||||
private ServerConstants() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes a path to a specified operating system
|
||||
* @param operatingSystem The os type.
|
||||
* @param path The path.
|
||||
* @return The fixed path.
|
||||
*/
|
||||
public static String fixPath(OperatingSystem operatingSystem, String path) {
|
||||
if (operatingSystem == null)
|
||||
operatingSystem = OS;
|
||||
return operatingSystem == OperatingSystem.WINDOWS ? path.replace("/","\\") : path.replace("\\","/");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package ms.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Used for producing I/O events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public interface EventProducer {
|
||||
|
||||
/**
|
||||
* Produces a new read event.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read.
|
||||
* @return The read event handler.
|
||||
*/
|
||||
IoReadEvent produceReader(IoSession session, ByteBuffer buffer);
|
||||
|
||||
/**
|
||||
* Produces a new writing event.
|
||||
* @param session The session.
|
||||
* @param context The context.
|
||||
* @return The write event handler.
|
||||
*/
|
||||
IoWriteEvent produceWriter(IoSession session, Object context);
|
||||
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
package ms.net;
|
||||
|
||||
import ms.world.WorldDatabase;
|
||||
import ms09.MSLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* I/O event handling.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class IoEventHandler {
|
||||
|
||||
/**
|
||||
* The executor service.
|
||||
*/
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoEventHandler}.
|
||||
* @param service The executor service used for handling events.
|
||||
*/
|
||||
public IoEventHandler(ExecutorService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when making a new connection.
|
||||
* @param key The selection key.
|
||||
*/
|
||||
public void connect(SelectionKey key) {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for accepting a new connection.
|
||||
* @param key The selection key.
|
||||
* @param selector The selector.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public void accept(SelectionKey key, Selector selector) throws IOException {
|
||||
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
|
||||
sc.configureBlocking(false);
|
||||
sc.socket().setTcpNoDelay(true);
|
||||
sc.register(selector, SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the incoming packet data.
|
||||
* @param key The selection key.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public void read(SelectionKey key) throws IOException {
|
||||
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(100_000);
|
||||
IoSession session = (IoSession) key.attachment();
|
||||
if (channel.read(buffer) == -1) {
|
||||
if(session == null){
|
||||
key.cancel();
|
||||
return;
|
||||
}
|
||||
if(session.getGameServer() != null){
|
||||
WorldDatabase.unRegister(session.getGameServer());
|
||||
}
|
||||
session.disconnect();
|
||||
key.cancel();
|
||||
return;
|
||||
}
|
||||
buffer.flip();
|
||||
if (session == null) {
|
||||
key.attach(session = new IoSession(key, service));
|
||||
}
|
||||
service.execute(session.getProducer().produceReader(session, buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the outgoing packet data.
|
||||
* @param key The selection key.
|
||||
*/
|
||||
public void write(SelectionKey key) {
|
||||
IoSession session = (IoSession) key.attachment();
|
||||
if(session != null) {
|
||||
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
|
||||
session.write();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects a connection.
|
||||
* @param key The selection key.
|
||||
* @param t The occurred exception (if any).
|
||||
*/
|
||||
public void disconnect(SelectionKey key, Throwable t) {
|
||||
try {
|
||||
IoSession session = (IoSession) key.attachment();
|
||||
String cause = "" + t;
|
||||
if (t != null && !(t instanceof ClosedChannelException || cause.contains("De externe host") || cause.contains("De software op uw") || cause.contains("An established connection was aborted") || cause.contains("An existing connection") || cause.contains("AsynchronousClose"))) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
if (session != null) {
|
||||
session.disconnect();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package ms.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Handles a reading event.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public abstract class IoReadEvent implements Runnable {
|
||||
|
||||
/**
|
||||
* The I/O session.
|
||||
*/
|
||||
private final IoSession session;
|
||||
|
||||
/**
|
||||
* The buffer.
|
||||
*/
|
||||
private ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* If the queued reading buffer was used (debugging purposes).
|
||||
*/
|
||||
protected boolean usedQueuedBuffer;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoReadEvent}.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read from.
|
||||
*/
|
||||
public IoReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
this.session = session;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (session.getReadingQueue() != null) {
|
||||
buffer = session.getReadingQueue().put(buffer);
|
||||
buffer.flip();
|
||||
session.setReadingQueue(null);
|
||||
usedQueuedBuffer = true;
|
||||
}
|
||||
read(session, buffer);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues the buffer until more data has been received.
|
||||
* @param data The data that has been read already.
|
||||
*/
|
||||
public void queueBuffer(int...data) {
|
||||
ByteBuffer queue = ByteBuffer.allocate(data.length + buffer.remaining() + 100_000);
|
||||
for (int value : data) {
|
||||
queue.put((byte) value);
|
||||
}
|
||||
queue.put(buffer);
|
||||
session.setReadingQueue(queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data from the buffer.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read from.
|
||||
*/
|
||||
public abstract void read(IoSession session, ByteBuffer buffer);
|
||||
|
||||
}
|
||||
|
|
@ -1,354 +0,0 @@
|
|||
package ms.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.producer.HSEventProducer;
|
||||
import ms.world.GameServer;
|
||||
|
||||
/**
|
||||
* Represents a connected I/O session.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class IoSession {
|
||||
|
||||
/**
|
||||
* The handshake event producer.
|
||||
*/
|
||||
private static final EventProducer HANDSHAKE_PRODUCER = new HSEventProducer();
|
||||
|
||||
/**
|
||||
* The selection key.
|
||||
*/
|
||||
private final SelectionKey key;
|
||||
|
||||
/**
|
||||
* The executor service.
|
||||
*/
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* The event producer.
|
||||
*/
|
||||
private EventProducer producer = HANDSHAKE_PRODUCER;
|
||||
|
||||
/**
|
||||
* The currently queued writing data.
|
||||
*/
|
||||
private List<ByteBuffer> writingQueue = new ArrayList<>(20);
|
||||
|
||||
/**
|
||||
* The currently queued reading data.
|
||||
*/
|
||||
private ByteBuffer readingQueue;
|
||||
|
||||
/**
|
||||
* The writing lock.
|
||||
*/
|
||||
private final Lock writingLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The name hash.
|
||||
*/
|
||||
private int nameHash;
|
||||
|
||||
/**
|
||||
* The server key.
|
||||
*/
|
||||
private long serverKey;
|
||||
|
||||
/**
|
||||
* The JS-5 encryption value.
|
||||
*/
|
||||
private int js5Encryption;
|
||||
|
||||
/**
|
||||
* If the session is active.
|
||||
*/
|
||||
private boolean active = true;
|
||||
|
||||
/**
|
||||
* The last ping time stamp.
|
||||
*/
|
||||
private long lastPing;
|
||||
|
||||
/**
|
||||
* The address.
|
||||
*/
|
||||
private final String address;
|
||||
|
||||
/**
|
||||
* The game server object for this session.
|
||||
*/
|
||||
private GameServer gameServer;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoSession}.
|
||||
* @param key The selection key.
|
||||
* @param service The executor service.
|
||||
*/
|
||||
public IoSession(SelectionKey key, ExecutorService service) {
|
||||
this.key = key;
|
||||
this.service = service;
|
||||
String address = getRemoteAddress().replaceAll("/", "").split(":")[0];
|
||||
if (address.equals("127.0.0.1")) {
|
||||
address = ServerConstants.HOST_ADDRESS;
|
||||
}
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a write event created using the current event producer.
|
||||
* @param context The event context.
|
||||
*/
|
||||
public void write(Object context) {
|
||||
write(context, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a write event created using the current event producer.
|
||||
* @param context The event context.
|
||||
* @param instant If the event should be instantly executed on this thread.
|
||||
*/
|
||||
public void write(Object context, boolean instant) {
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Invalid writing context!");
|
||||
}
|
||||
if (instant) {
|
||||
producer.produceWriter(this, context).run();
|
||||
return;
|
||||
}
|
||||
service.execute(producer.produceWriter(this, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet data (without write event encoding).
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void queue(ByteBuffer buffer) {
|
||||
try {
|
||||
if(writingLock.tryLock(1000L, TimeUnit.MILLISECONDS)){
|
||||
writingQueue.add(buffer);
|
||||
writingLock.unlock();
|
||||
write();
|
||||
}
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
writingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the writing of all buffers in the queue.
|
||||
*/
|
||||
public void write() {
|
||||
|
||||
if (!key.isValid()) {
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
writingLock.lock();
|
||||
SocketChannel channel = (SocketChannel) key.channel();
|
||||
try {
|
||||
while (!writingQueue.isEmpty()) {
|
||||
ByteBuffer buffer = writingQueue.get(0);
|
||||
channel.write(buffer);
|
||||
if (buffer.hasRemaining()) {
|
||||
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
|
||||
break;
|
||||
}
|
||||
writingQueue.remove(0);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
disconnect();
|
||||
} finally {
|
||||
writingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*/
|
||||
public void disconnect() {
|
||||
try {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
active = false;
|
||||
key.cancel();
|
||||
SocketChannel channel = (SocketChannel) key.channel();
|
||||
channel.socket().close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IP-address (without the port).
|
||||
* @return The address.
|
||||
*/
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remote address of this session.
|
||||
* @return The remote address, as a String.
|
||||
*/
|
||||
public String getRemoteAddress() {
|
||||
try {
|
||||
return ((SocketChannel) key.channel()).getRemoteAddress().toString();
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current event producer.
|
||||
* @return The producer.
|
||||
*/
|
||||
public EventProducer getProducer() {
|
||||
return producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event producer.
|
||||
* @param producer The producer to set.
|
||||
*/
|
||||
public void setProducer(EventProducer producer) {
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queued reading data.
|
||||
* @return The readingQueue.
|
||||
*/
|
||||
public ByteBuffer getReadingQueue() {
|
||||
synchronized (this) {
|
||||
return readingQueue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues reading data.
|
||||
* @param readingQueue The readingQueue to set.
|
||||
*/
|
||||
public void setReadingQueue(ByteBuffer readingQueue) {
|
||||
synchronized (this) {
|
||||
this.readingQueue = readingQueue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the writing lock.
|
||||
* @return The writing lock.
|
||||
*/
|
||||
public Lock getWritingLock() {
|
||||
return writingLock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selection key.
|
||||
* @return The selection key.
|
||||
*/
|
||||
public SelectionKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The js5Encryption.
|
||||
*/
|
||||
public int getJs5Encryption() {
|
||||
return js5Encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param js5Encryption The js5Encryption to set.
|
||||
*/
|
||||
public void setJs5Encryption(int js5Encryption) {
|
||||
this.js5Encryption = js5Encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lastPing.
|
||||
* @return The lastPing.
|
||||
*/
|
||||
public long getLastPing() {
|
||||
return lastPing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lastPing.
|
||||
* @param lastPing The lastPing to set.
|
||||
*/
|
||||
public void setLastPing(long lastPing) {
|
||||
this.lastPing = lastPing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nameHash.
|
||||
* @return The nameHash.
|
||||
*/
|
||||
public int getNameHash() {
|
||||
return nameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the nameHash.
|
||||
* @param nameHash The nameHash to set.
|
||||
*/
|
||||
public void setNameHash(int nameHash) {
|
||||
this.nameHash = nameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serverKey.
|
||||
* @return The serverKey.
|
||||
*/
|
||||
public long getServerKey() {
|
||||
return serverKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serverKey.
|
||||
* @param serverKey The serverKey to set.
|
||||
*/
|
||||
public void setServerKey(long serverKey) {
|
||||
this.serverKey = serverKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gameServer value.
|
||||
* @return The gameServer.
|
||||
*/
|
||||
public GameServer getGameServer() {
|
||||
return gameServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gameServer value.
|
||||
* @param gameServer The gameServer to set.
|
||||
*/
|
||||
public void setGameServer(GameServer gameServer) {
|
||||
this.gameServer = gameServer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package ms.net;
|
||||
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
|
||||
/**
|
||||
* Handles a writing event.
|
||||
* @author Emperor
|
||||
*/
|
||||
public abstract class IoWriteEvent implements Runnable {
|
||||
|
||||
/**
|
||||
* The I/O session.
|
||||
*/
|
||||
private final IoSession session;
|
||||
|
||||
/**
|
||||
* The buffer.
|
||||
*/
|
||||
private final Object context;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoWriteEvent}.
|
||||
* @param session The session.
|
||||
* @param context The write event context.
|
||||
*/
|
||||
public IoWriteEvent(IoSession session, Object context) {
|
||||
this.session = session;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
write(session, context);
|
||||
} catch (Throwable t) {
|
||||
if (!(t instanceof CancelledKeyException)) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data.
|
||||
* @param session The session.
|
||||
* @param context The write event context.
|
||||
*/
|
||||
public abstract void write(IoSession session, Object context);
|
||||
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
package ms.net;
|
||||
|
||||
import ms.Management;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Handles (NIO-based) networking events using the reactor pattern.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class NioReactor implements Runnable {
|
||||
|
||||
/**
|
||||
* The executor service.
|
||||
*/
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* The selector
|
||||
*/
|
||||
private Selector selector;
|
||||
|
||||
/**
|
||||
* The socket channel.
|
||||
*/
|
||||
private ServerSocketChannel channel;
|
||||
|
||||
/**
|
||||
* The I/O event handling instance.
|
||||
*/
|
||||
private final IoEventHandler eventHandler;
|
||||
|
||||
/**
|
||||
* If the reactor is running.
|
||||
*/
|
||||
private boolean running;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code NioReactor}.
|
||||
* @param poolSize The pool size.
|
||||
*/
|
||||
private NioReactor(int poolSize) {
|
||||
this.service = Executors.newSingleThreadScheduledExecutor();
|
||||
this.eventHandler = new IoEventHandler(Executors.newFixedThreadPool(poolSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a new {@code NioReactor} with a pool size of 1.
|
||||
* @param port The port.
|
||||
* @return The {@code NioReactor} {@code Object}.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public static NioReactor configure(int port) throws IOException {
|
||||
return configure(port, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a new {@code NioReactor}.
|
||||
* @param port The port.
|
||||
* @param poolSize The amount of threads in the thread pool.
|
||||
* @return The {@code NioReactor} {@code Object}.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public static NioReactor configure(int port, int poolSize) throws IOException {
|
||||
NioReactor reactor = new NioReactor(poolSize);
|
||||
reactor.channel = ServerSocketChannel.open();
|
||||
reactor.selector = Selector.open();
|
||||
reactor.channel.bind(new InetSocketAddress(port));
|
||||
reactor.channel.configureBlocking(false);
|
||||
reactor.channel.register(reactor.selector, SelectionKey.OP_ACCEPT);
|
||||
return reactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the reactor.
|
||||
*/
|
||||
public void start() {
|
||||
running = true;
|
||||
service.execute(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (running && Management.active) {
|
||||
try {
|
||||
if(selector.select() > 0){
|
||||
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
|
||||
while (keys.hasNext()) {
|
||||
SelectionKey key = keys.next();
|
||||
keys.remove();
|
||||
try {
|
||||
if(key == null) continue;
|
||||
if (!key.isValid() || !key.channel().isOpen()) {
|
||||
key.cancel();
|
||||
continue;
|
||||
}
|
||||
if (key.isAcceptable()) {
|
||||
eventHandler.accept(key, selector);
|
||||
}
|
||||
if (key.isReadable()) {
|
||||
eventHandler.read(key);
|
||||
}
|
||||
else if (key.isWritable()) {
|
||||
eventHandler.write(key);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
eventHandler.disconnect(key, t);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("SLEEPING");
|
||||
Thread.sleep(200);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the reactor (once it's done processing current I/O events).
|
||||
*/
|
||||
public void terminate() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.Locale;
|
||||
|
||||
import ms.Management;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.packet.IoBuffer;
|
||||
import ms.system.mysql.SQLManager;
|
||||
import ms.system.util.ManagementConstants;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
|
||||
/**
|
||||
* Handles handshake read events.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class HSReadEvent extends IoReadEvent {
|
||||
|
||||
/**
|
||||
* Constructs a new {@code HSReadEvent}.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public HSReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
super(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(IoSession session, ByteBuffer buffer) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
switch (opcode) {
|
||||
case 88:
|
||||
String password = ByteBufferUtils.getString(buffer);
|
||||
if (!password.equals(ManagementConstants.getSECRET_KEY())) {
|
||||
System.out.println("Password mismatch (attempt=" + password + ")!");
|
||||
session.disconnect();
|
||||
break;
|
||||
}
|
||||
session.write(opcode);
|
||||
break;
|
||||
case 255: // World list
|
||||
int updateStamp = buffer.getInt();
|
||||
WorldDatabase.sendUpdate(session, updateStamp);
|
||||
break;
|
||||
case 35:
|
||||
IoBuffer buf = new IoBuffer();
|
||||
String username = ByteBufferUtils.getString(buffer).toLowerCase();
|
||||
password = ByteBufferUtils.getString(buffer);
|
||||
if (!password.equals(ManagementConstants.getSECRET_KEY())){
|
||||
System.out.println("Password mismatch (attempt=" + password + ")!");
|
||||
buf.put(1);
|
||||
ByteBuffer buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSession player = WorldDatabase.getPlayer(username);
|
||||
if (player == null) {
|
||||
System.out.println("Player " + username + " was not registered!");
|
||||
buf.put(2);
|
||||
ByteBuffer buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
return;
|
||||
}
|
||||
buf.put(0);
|
||||
ByteBuffer buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
player.getWorld().getPlayers().remove(username);
|
||||
player.setWorldId(0);
|
||||
break;
|
||||
case 36:
|
||||
buf = new IoBuffer();
|
||||
username = ByteBufferUtils.getString(buffer).toLowerCase();
|
||||
password = ByteBufferUtils.getString(buffer);
|
||||
int credits = buffer.getInt();
|
||||
if (!password.equals(ManagementConstants.getSECRET_KEY())){
|
||||
System.out.println("Password mismatch (attempt=" + password + ")!");
|
||||
buf.put(1);
|
||||
buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
return;
|
||||
}
|
||||
try (Connection con = SQLManager.getConnection()) {
|
||||
Statement stmt = con.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("SELECT credits FROM members WHERE username = \"" + username + "\";");
|
||||
int original;
|
||||
if (rs.next()) original = rs.getInt(1);
|
||||
else {
|
||||
buf.put(2);
|
||||
buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
return;
|
||||
}
|
||||
stmt.execute("UPDATE members SET credits = " + (original + credits) + " WHERE username = \"" + username + "\";");
|
||||
buf.put(0);
|
||||
buf.putInt(original + credits);
|
||||
buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
} catch (Exception e) {
|
||||
buf.put(3);
|
||||
buf.putString(e.toString());
|
||||
buff = buf.toByteBuffer();
|
||||
buff.flip();
|
||||
session.queue(buff);
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("Unhandled handshake opcode: " + opcode + ".");
|
||||
session.disconnect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.producer.RegistryEventProducer;
|
||||
|
||||
/**
|
||||
* Handles Handshake write events.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class HSWriteEvent extends IoWriteEvent {
|
||||
|
||||
/**
|
||||
* The login event producer.
|
||||
*/
|
||||
private static final RegistryEventProducer REGISTRY_PRODUCER = new RegistryEventProducer();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code HSWriteEvent} {@code Object}.
|
||||
* @param session The session.
|
||||
* @param context The context.
|
||||
*/
|
||||
public HSWriteEvent(IoSession session, Object context) {
|
||||
super(session, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IoSession session, Object context) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(9);
|
||||
buffer.put((byte) 14);
|
||||
session.setProducer( REGISTRY_PRODUCER);
|
||||
buffer.flip();
|
||||
session.queue(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
|
||||
/**
|
||||
* Handles world packet reading events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PacketReadEvent extends IoReadEvent {
|
||||
|
||||
/**
|
||||
* The packet sizes.
|
||||
*/
|
||||
private static final int[] PACKET_SIZE = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PacketReadEvent} {@code Object}.
|
||||
* @param session The I/O session.
|
||||
* @param buffer The buffer to read from.
|
||||
*/
|
||||
public PacketReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
super(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(IoSession session, ByteBuffer buffer) {
|
||||
int last = -1;
|
||||
while (buffer.hasRemaining()) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
if (opcode >= PACKET_SIZE.length) {
|
||||
break;
|
||||
}
|
||||
int header = PACKET_SIZE[opcode];
|
||||
int size = header;
|
||||
if (header < 0) {
|
||||
size = getPacketSize(buffer, opcode, header, last);
|
||||
}
|
||||
if (size == -1) {
|
||||
break;
|
||||
}
|
||||
if (buffer.remaining() < size) {
|
||||
switch (header) {
|
||||
case -2:
|
||||
queueBuffer(opcode, size >> 8, size);
|
||||
break;
|
||||
case -1:
|
||||
queueBuffer(opcode, size);
|
||||
break;
|
||||
default:
|
||||
queueBuffer(opcode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
byte[] data = new byte[size];
|
||||
buffer.get(data);
|
||||
last = opcode;
|
||||
try {
|
||||
WorldPacketRepository.handleIncoming(session, opcode, ByteBuffer.wrap(data));
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet size for the given opcode.
|
||||
* @param buffer The buffer.
|
||||
* @param opcode The opcode.
|
||||
* @param header The packet header.
|
||||
* @param last The last opcode.
|
||||
* @return The packet size.
|
||||
*/
|
||||
private int getPacketSize(ByteBuffer buffer, int opcode, int header, int last) {
|
||||
if (header == -1) {
|
||||
if (buffer.remaining() < 1) {
|
||||
queueBuffer(opcode);
|
||||
return -1;
|
||||
}
|
||||
return buffer.get() & 0xFF;
|
||||
}
|
||||
if (header == -2) {
|
||||
if (buffer.remaining() < 2) {
|
||||
queueBuffer(opcode);
|
||||
return -1;
|
||||
}
|
||||
return buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
System.err.println("Invalid packet [opcode=" + opcode + ", last=" + last + ", queued=" + usedQueuedBuffer + "]!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.packet.IoBuffer;
|
||||
|
||||
/**
|
||||
* Handles world packet writing events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PacketWriteEvent extends IoWriteEvent {
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PacketWriteEvent} {@code Object}.
|
||||
* @param session The I/O session.
|
||||
* @param context The packet context.
|
||||
*/
|
||||
public PacketWriteEvent(IoSession session, Object context) {
|
||||
super(session, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IoSession session, Object context) {
|
||||
IoBuffer b = (IoBuffer) context;
|
||||
int size = b.toByteBuffer().position();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1 + size + b.getHeader().ordinal());
|
||||
buffer.put((byte) b.opcode());
|
||||
switch (b.getHeader()) {
|
||||
case NORMAL:
|
||||
break;
|
||||
case BYTE:
|
||||
buffer.put((byte) size);
|
||||
break;
|
||||
case SHORT:
|
||||
buffer.putShort((short) size);
|
||||
break;
|
||||
}
|
||||
buffer.put((ByteBuffer) b.toByteBuffer().flip());
|
||||
session.queue((ByteBuffer) buffer.flip());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
import ms.world.info.CountryFlag;
|
||||
import ms.world.info.WorldInfo;
|
||||
|
||||
/**
|
||||
* Handles world registry read events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegistryReadEvent extends IoReadEvent {
|
||||
|
||||
/**
|
||||
* The string check.
|
||||
*/
|
||||
private static final String CHECK = "12x4578f5g45hrdjiofed59898";
|
||||
//kratos = 666x14x88x28shhhwpwwb&h
|
||||
//12x4578f5g45hrdjiofed59898
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RegistryReadEvent} {@code Object}.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read.
|
||||
*/
|
||||
public RegistryReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
super(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(IoSession session, ByteBuffer buffer) {
|
||||
int worldId = buffer.get() & 0xFF;
|
||||
if (buffer.remaining() < 2) {
|
||||
queueBuffer(worldId);
|
||||
return;
|
||||
}
|
||||
int revision = buffer.getInt();
|
||||
int country = buffer.get() & 0xFF;
|
||||
boolean members = buffer.get() == 1;
|
||||
boolean pvp = buffer.get() == 1;
|
||||
boolean quickChat = buffer.get() == 1;
|
||||
boolean lootshare = buffer.get() == 1;
|
||||
String activity = ByteBufferUtils.getString(buffer);
|
||||
for (int i = 0; i < CHECK.length(); i++) {
|
||||
if ((char) buffer.get() != CHECK.charAt(i)) {
|
||||
session.write(3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (worldId >= ServerConstants.WORLD_LIMIT) {
|
||||
session.write(0);
|
||||
return;
|
||||
}
|
||||
if (WorldDatabase.isActive(worldId)) {
|
||||
session.write(2);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
WorldInfo info = new WorldInfo(worldId, session.getAddress(), revision, CountryFlag.values()[country], activity, members, pvp, quickChat, lootshare);
|
||||
WorldDatabase.register(info).configure(session);
|
||||
session.write(1);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
session.write(3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.producer.PacketEventProducer;
|
||||
|
||||
/**
|
||||
* Handles game world registry writing events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegistryWriteEvent extends IoWriteEvent {
|
||||
|
||||
/**
|
||||
* The event producer.
|
||||
*/
|
||||
public static final EventProducer PRODUCER = new PacketEventProducer();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RegistryWriteEvent} {@code Object}.
|
||||
* @param session The I/O session.
|
||||
* @param context The writing context.
|
||||
*/
|
||||
public RegistryWriteEvent(IoSession session, Object context) {
|
||||
super(session, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IoSession session, Object context) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1);
|
||||
int opcode = (int) context;
|
||||
buffer.put((byte) opcode);
|
||||
buffer.flip();
|
||||
if (opcode == 1) {
|
||||
session.setProducer(PRODUCER);
|
||||
}
|
||||
session.queue(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,666 +0,0 @@
|
|||
package ms.net.packet;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
|
||||
/**
|
||||
* Represents the buffer used for reading/writing packets.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class IoBuffer {
|
||||
|
||||
/**
|
||||
* The bit masks.
|
||||
*/
|
||||
private static final int[] BIT_MASK = new int[32];
|
||||
|
||||
/**
|
||||
* The packet size.
|
||||
*/
|
||||
private int packetSize;
|
||||
|
||||
/**
|
||||
* The opcode.
|
||||
*/
|
||||
private final int opcode;
|
||||
|
||||
/**
|
||||
* The packet header.
|
||||
*/
|
||||
private final PacketHeader header;
|
||||
|
||||
/**
|
||||
* The byte buffer.
|
||||
*/
|
||||
private ByteBuffer buf;
|
||||
|
||||
/**
|
||||
* The bit position.
|
||||
*/
|
||||
private int bitPosition = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
*/
|
||||
public IoBuffer() {
|
||||
this(-1, PacketHeader.NORMAL, ByteBuffer.allocate(2048));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
* @param opcode The opcode.
|
||||
*/
|
||||
public IoBuffer(int opcode) {
|
||||
this(opcode, PacketHeader.NORMAL, ByteBuffer.allocate(2048));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
* @param opcode The opcode.
|
||||
* @param header The packet header.
|
||||
*/
|
||||
public IoBuffer(int opcode, PacketHeader header) {
|
||||
this(opcode, header, ByteBuffer.allocate((1 << 16) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
* @param opcode The opcode.
|
||||
* @param header The packet header.
|
||||
* @param buf The byte buffer.
|
||||
*/
|
||||
public IoBuffer(int opcode, PacketHeader header, ByteBuffer buf) {
|
||||
this.opcode = opcode;
|
||||
this.header = header;
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
static {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
BIT_MASK[i] = (1 << i) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer clear() {
|
||||
buf.clear();
|
||||
bitPosition = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(int val) {
|
||||
buf.put((byte) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param datas
|
||||
* @param offset
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putBytes(byte[] datas, int offset, int len) {
|
||||
for (int i = offset; i < len; i++) {
|
||||
put(datas[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public final void getBytes(byte data[], int off, int len) {
|
||||
for (int k = off; k < len + off; k++) {
|
||||
data[k] = data[off++];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putA(int val) {
|
||||
buf.put((byte) (val + 128));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putC(int val) {
|
||||
buf.put((byte) -val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putS(int val) {
|
||||
buf.put((byte) (128 - val));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putTri(int val) {
|
||||
buf.put((byte) (val >> 16));
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putShort(int val) {
|
||||
buf.putShort((short) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLEShort(int val) {
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putShortA(int val) {
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) (val + 128));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLEShortA(int val) {
|
||||
buf.put((byte) (val + 128));
|
||||
buf.put((byte) (val >> 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putInt(int val) {
|
||||
buf.putInt(val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLEInt(int val) {
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) (val >> 16));
|
||||
buf.put((byte) (val >> 24));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putIntA(int val) {
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 24));
|
||||
buf.put((byte) (val >> 16));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putIntB(int val) {
|
||||
buf.put((byte) (val >> 16));
|
||||
buf.put((byte) (val >> 24));
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLong(long val) {
|
||||
buf.putLong(val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putSmart(int val) {
|
||||
if (val > Byte.MAX_VALUE) {
|
||||
buf.putShort((short) (val + 32768));
|
||||
} else {
|
||||
buf.put((byte) val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putIntSmart(int val) {
|
||||
if (val > Short.MAX_VALUE) {
|
||||
buf.putInt(val + 32768);
|
||||
} else {
|
||||
buf.putShort((short) val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putString(String val) {
|
||||
buf.put(val.getBytes(StandardCharsets.UTF_8));
|
||||
buf.put((byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putJagString(String val) {
|
||||
buf.put((byte) 0);
|
||||
buf.put(val.getBytes(StandardCharsets.UTF_8));
|
||||
buf.put((byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putJagString2(String val) {
|
||||
byte[] packed = new byte[256];
|
||||
int length = ByteBufferUtils.packGJString2(0, packed, val);
|
||||
buf.put((byte) 0).put(packed, 0, length).put((byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(byte[] val) {
|
||||
buf.put(val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte array as byte A in reverse.
|
||||
* @param data The data to put.
|
||||
* @param start The start index.
|
||||
* @param offset The offset.
|
||||
*/
|
||||
public void putReverseA(byte[] data, int start, int offset) {
|
||||
for (int i = offset + start; i >= start; i--) {
|
||||
putA(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param numBits
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putBits(int numBits, int value) {
|
||||
int bytePos = getBitPosition() >> 3;
|
||||
int bitOffset = 8 - (getBitPosition() & 7);
|
||||
bitPosition += numBits;
|
||||
for (; numBits > bitOffset; bitOffset = 8) {
|
||||
byte b = buf.get(bytePos);
|
||||
buf.put(bytePos, b &= ~BIT_MASK[bitOffset]);
|
||||
buf.put(bytePos++, b |= value >> numBits - bitOffset & BIT_MASK[bitOffset]);
|
||||
numBits -= bitOffset;
|
||||
}
|
||||
byte b = buf.get(bytePos);
|
||||
if (numBits == bitOffset) {
|
||||
buf.put(bytePos, b &= ~BIT_MASK[bitOffset]);
|
||||
buf.put(bytePos, b |= value & BIT_MASK[bitOffset]);
|
||||
} else {
|
||||
buf.put(bytePos, b &= ~(BIT_MASK[numBits] << bitOffset - numBits));
|
||||
buf.put(bytePos, b |= (value & BIT_MASK[numBits]) << bitOffset - numBits);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(IoBuffer buffer) {
|
||||
buffer.toByteBuffer().flip();
|
||||
buf.put(buffer.toByteBuffer());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putA(IoBuffer buffer) {
|
||||
buffer.toByteBuffer().flip();
|
||||
while (buffer.toByteBuffer().hasRemaining()) {
|
||||
putA(buffer.toByteBuffer().get());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(ByteBuffer buffer) {
|
||||
buf.put(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer setBitAccess() {
|
||||
bitPosition = buf.position() * 8;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer setByteAccess() {
|
||||
buf.position((getBitPosition() + 7) / 8);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int get() {
|
||||
return buf.get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getA() {
|
||||
return (buf.get() & 0xFF) - 128;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getC() {
|
||||
return -buf.get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getS() {
|
||||
return 128 - buf.get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getTri() {
|
||||
return ((buf.get() << 16) & 0xFF) | ((buf.get() << 8) & 0xFF) | (buf.get() & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getShort() {
|
||||
return buf.getShort();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getLEShort() {
|
||||
return (buf.get() & 0xFF) | ((buf.get() & 0xFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getShortA() {
|
||||
return ((buf.get() & 0xFF) << 8) | (buf.get() - 128 & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getLEShortA() {
|
||||
return (buf.get() - 128 & 0xFF) | ((buf.get() & 0xFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getInt() {
|
||||
return buf.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getLEInt() {
|
||||
return (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8)
|
||||
+ ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIntA() {
|
||||
return ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF)+ ((buf.get() & 0xFF) << 24) + ((buf.get() & 0xFF) << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIntB() {
|
||||
return ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24)
|
||||
+ (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getLongL() {
|
||||
long first = getIntB();
|
||||
long second = getIntB();
|
||||
if (second < 0)
|
||||
second = second & 0xffffffffL;
|
||||
return (first << 32) + second;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getLong() {
|
||||
return buf.getLong();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIntSmart() {
|
||||
int peek = buf.getShort(buf.position());
|
||||
if (peek <= Short.MAX_VALUE) {
|
||||
return buf.getShort() & 0xFFFF;
|
||||
}
|
||||
return buf.getInt() - 32768;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getString() {
|
||||
return ByteBufferUtils.getString(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getJagString() {
|
||||
buf.get();
|
||||
return ByteBufferUtils.getString(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param is
|
||||
* @param offset
|
||||
* @param length
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer getReverseA(byte[] is, int offset, int length) {
|
||||
for (int i = (offset + length - 1); i >= offset; i--) {
|
||||
is[i] = (byte) (buf.get() - 128);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ByteBuffer toByteBuffer() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int opcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int readableBytes() {
|
||||
return buf.capacity() - buf.remaining();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PacketHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] array() {
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the packetSize.
|
||||
*/
|
||||
public int getPacketSize() {
|
||||
return packetSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param packetSize the packetSize to set.
|
||||
*/
|
||||
public void setPacketSize(int packetSize) {
|
||||
this.packetSize = packetSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bitPosition.
|
||||
* @return The bitPosition.
|
||||
*/
|
||||
public int getBitPosition() {
|
||||
return bitPosition;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package ms.net.packet
|
||||
|
||||
/**
|
||||
* Represents the types of packet headers.
|
||||
* @author Emperor
|
||||
*/
|
||||
enum class PacketHeader {
|
||||
|
||||
/**
|
||||
* The normal packet header.
|
||||
*/
|
||||
NORMAL,
|
||||
|
||||
/**
|
||||
* The byte packet header.
|
||||
*/
|
||||
BYTE,
|
||||
|
||||
/**
|
||||
* The short packet header.
|
||||
*/
|
||||
SHORT
|
||||
}
|
||||
|
|
@ -1,555 +0,0 @@
|
|||
package ms.net.packet
|
||||
|
||||
import ms.net.IoSession
|
||||
import ms.system.PunishmentStorage
|
||||
import ms.system.communication.ClanRank
|
||||
import ms.system.communication.ClanRepository
|
||||
import ms.system.communication.CommunicationInfo
|
||||
import ms.system.util.ManagementConstants.WORLD_HOP_DELAY
|
||||
import ms.world.GameServer
|
||||
import ms.world.PlayerSession
|
||||
import ms.world.WorldDatabase
|
||||
import ms.world.info.Response
|
||||
import ms.world.info.UIDInfo
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
/**
|
||||
* Repository class for world packets.
|
||||
* @author Emperor
|
||||
*/
|
||||
object WorldPacketRepository {
|
||||
/**
|
||||
* Sends the player registry response.
|
||||
* @param server The game server.
|
||||
* @param player The player session.
|
||||
* @param response The registry response.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendRegistryResponse(server: GameServer, player: PlayerSession, response: Response) {
|
||||
val buffer = IoBuffer(0, PacketHeader.BYTE)
|
||||
buffer.putString(player.username)
|
||||
buffer.put(response.opcode())//byte
|
||||
if (response == Response.MOVING_WORLD) {
|
||||
val delay: Long = WORLD_HOP_DELAY - (System.currentTimeMillis() - player.disconnectionTime)
|
||||
buffer.put((delay / 1000).toInt())
|
||||
}
|
||||
server.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the player.
|
||||
* @param player The player.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendPlayerMessage(player: PlayerSession?, message: String) {
|
||||
if (player == null) {
|
||||
return
|
||||
}
|
||||
val buffer = IoBuffer(2, PacketHeader.BYTE)
|
||||
buffer.putString(player.username)
|
||||
buffer.putString(message)
|
||||
player.world.session.write(buffer)
|
||||
}
|
||||
|
||||
fun sendPlayerMessage(player: PlayerSession?, messages: Array<String>) {
|
||||
if (player == null) {
|
||||
return
|
||||
}
|
||||
for (message in messages) sendPlayerMessage(player, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the contact information.
|
||||
* @param player The player.
|
||||
*/
|
||||
fun sendContactInformation(player: PlayerSession) {
|
||||
val info = player.communication
|
||||
val buffer = IoBuffer(3, PacketHeader.SHORT)
|
||||
buffer.putString(player.username)
|
||||
buffer.put(info.contacts.size)
|
||||
for (contact in info.contacts.keys) {
|
||||
buffer.putString(contact)
|
||||
buffer.put(info.getRank(contact).ordinal)
|
||||
buffer.put(CommunicationInfo.getWorldId(player, contact))
|
||||
}
|
||||
buffer.put(info.blocked.size)
|
||||
for (contact in info.blocked) {
|
||||
buffer.putString(contact)
|
||||
}
|
||||
if (info.currentClan == null) {
|
||||
buffer.put(0)
|
||||
} else {
|
||||
buffer.put(1)
|
||||
buffer.putString(info.currentClan)
|
||||
}
|
||||
player.world.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a contact update.
|
||||
* @param player The player who's contacts we're changing.
|
||||
* @param contact The contact to update.
|
||||
* @param block If we're updating the blocked list.
|
||||
* @param remove If the contact should be removed.
|
||||
* @param worldId The world id of the contact.
|
||||
* @param rank The clan rank.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendContactUpdate(
|
||||
player: PlayerSession,
|
||||
contact: String,
|
||||
block: Boolean,
|
||||
remove: Boolean,
|
||||
worldId: Int,
|
||||
rank: ClanRank?
|
||||
) {
|
||||
val buffer = IoBuffer(4, PacketHeader.BYTE)
|
||||
buffer.putString(player.username)
|
||||
buffer.putString(contact)
|
||||
buffer.put((if (block) 1 else 0))
|
||||
if (rank != null) {
|
||||
buffer.put((2 + rank.ordinal))
|
||||
} else {
|
||||
buffer.put((if (remove) 1 else 0))
|
||||
if (!block && !remove) {
|
||||
buffer.put(worldId)
|
||||
}
|
||||
}
|
||||
player.world.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a clan message.
|
||||
* @param player The player to send the message to.
|
||||
* @param p The player sending the message.
|
||||
* @param message The message to send.
|
||||
* @param type The message type.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendMessage(player: PlayerSession, p: PlayerSession, type: Int, message: String) {
|
||||
val buffer = IoBuffer(5, PacketHeader.BYTE)
|
||||
buffer.putString(player.username)
|
||||
buffer.putString(p.username)
|
||||
buffer.put(type)
|
||||
buffer.put(p.chatIcon)
|
||||
buffer.putString(message)
|
||||
println("Send Message: ${player.username} -> ${p.username} T: $type ICO: ${p.chatIcon} $message")
|
||||
player.world.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends clan information to the server.
|
||||
* @param server The server.
|
||||
* @param clan The clan.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendClanInformation(server: GameServer, clan: ClanRepository) {
|
||||
val buffer = IoBuffer(6, PacketHeader.SHORT)
|
||||
buffer.putString(clan.owner.username)
|
||||
buffer.putString(clan.name)
|
||||
var length = clan.players.size
|
||||
if (length > ClanRepository.MAX_MEMBERS) {
|
||||
length = ClanRepository.MAX_MEMBERS
|
||||
}
|
||||
buffer.put(length)
|
||||
for (i in 0 until length) {
|
||||
val player = clan.players[i]
|
||||
buffer.putString(player.username)
|
||||
buffer.put(player.worldId)
|
||||
buffer.put(clan.getRank(player).ordinal)
|
||||
}
|
||||
buffer.put(clan.joinRequirement.ordinal)
|
||||
buffer.put(clan.kickRequirement.ordinal)
|
||||
buffer.put(clan.messageRequirement.ordinal)
|
||||
buffer.put(clan.lootRequirement.ordinal)
|
||||
server.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the leave clan packet.
|
||||
* @param player The player leaving the clan.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendLeaveClan(player: PlayerSession) {
|
||||
val buffer = IoBuffer(7, PacketHeader.BYTE)
|
||||
buffer.putString(player.username)
|
||||
player.world.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the player login notification.
|
||||
* @param server The server.
|
||||
* @param player The player logging in.
|
||||
* @param names The names.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun notifyPlayers(server: GameServer, player: PlayerSession, names: List<String>) {
|
||||
val buffer = IoBuffer(8, PacketHeader.SHORT)
|
||||
buffer.putString(player.username)
|
||||
buffer.put(player.worldId)
|
||||
buffer.put(names.size)
|
||||
for (name in names) {
|
||||
buffer.putString(name)
|
||||
}
|
||||
server.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the game server a player logged out.
|
||||
* @param server The game server to notify.
|
||||
* @param player The player logging out.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun notifyLogout(server: GameServer, player: PlayerSession) {
|
||||
val buffer = IoBuffer(9, PacketHeader.BYTE)
|
||||
buffer.putString(player.username)
|
||||
server.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the update countdown to the server.
|
||||
* @param server The server.
|
||||
* @param ticks The amount of ticks left.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendUpdate(server: GameServer, ticks: Int) {
|
||||
val buffer = IoBuffer(10)
|
||||
buffer.putInt(ticks)
|
||||
server.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the punishment update packet.
|
||||
* @param world The world to send the packet to.
|
||||
* @param key The punishment key.
|
||||
* @param type The punishment type.
|
||||
* @param duration The duration of the punishment.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendPunishUpdate(world: GameServer, key: String, type: Int, duration: Long) {
|
||||
val buffer = IoBuffer(11, PacketHeader.BYTE)
|
||||
buffer.putString(key)
|
||||
buffer.put(type)
|
||||
buffer.putLong(duration)
|
||||
world.session.write(buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a configuration reload.
|
||||
* @param world the world.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sendConfigReload(world: GameServer) {
|
||||
world.session.write(IoBuffer(15, PacketHeader.BYTE))
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming world packets.
|
||||
* @param session The I/O session.
|
||||
* @param opcode The opcode.
|
||||
* @param b The buffer to read from.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun handleIncoming(session: IoSession, opcode: Int, b: ByteBuffer) {
|
||||
val buffer = IoBuffer(opcode, PacketHeader.NORMAL, b)
|
||||
val server = session.gameServer
|
||||
when (opcode) {
|
||||
0 -> handlePlayerRegistration(server, buffer)
|
||||
1 -> handlePlayerRemoval(server, buffer)
|
||||
2 -> handlePunishment(server, buffer)
|
||||
3 -> handleCommunicationRequest(server, buffer)
|
||||
4, 5 -> handleContactUpdate(server, buffer, opcode == 5)
|
||||
6 -> handleJoinClan(server, buffer)
|
||||
7 -> handleClanRename(server, buffer)
|
||||
8 -> handleClanSetting(server, buffer)
|
||||
9 -> handleClanKick(server, buffer)
|
||||
10 -> handleClanMessage(server, buffer)
|
||||
11 -> handlePrivateMessage(server, buffer)
|
||||
12 -> handleClanInfoRequest(server, buffer)
|
||||
13 -> handleChatSetting(server, buffer)
|
||||
14 -> handleInfoUpdate(server, buffer)
|
||||
else -> System.err.println("Handling incoming packet [opcode=" + opcode + ", size=" + b.limit() + "].")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the info of a player update.
|
||||
* @param server the server.
|
||||
* @param buffer the buffer.
|
||||
*/
|
||||
private fun handleInfoUpdate(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val player = server.players[username]
|
||||
if (player != null) {
|
||||
player.chatIcon = buffer.get()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a player registration.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handlePlayerRegistration(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val password = buffer.string
|
||||
val ipAddress = buffer.string
|
||||
val macAddress = buffer.string
|
||||
val compName = buffer.string
|
||||
val serial = buffer.string
|
||||
val rights = buffer.int
|
||||
val chatIcon = buffer.get()
|
||||
val uid = UIDInfo(ipAddress, compName, macAddress, serial)
|
||||
val player = PlayerSession(username, password, UIDInfo(ipAddress, compName, macAddress, serial))
|
||||
if (WorldDatabase.isActivePlayer(username)) {
|
||||
sendRegistryResponse(server, player, Response.ALREADY_ONLINE)
|
||||
return
|
||||
}
|
||||
player.uid = uid
|
||||
player.rights = rights
|
||||
player.chatIcon = chatIcon
|
||||
if (PunishmentStorage.isSystemBanned(uid)) {
|
||||
sendRegistryResponse(server, player, Response.BANNED)
|
||||
return
|
||||
}
|
||||
player.parse()
|
||||
if (player.isBanned) {
|
||||
sendRegistryResponse(server, player, Response.ACCOUNT_DISABLED)
|
||||
return
|
||||
}
|
||||
if (player.lastWorld != server.info.worldId && player.hasMovedWorld()) {
|
||||
sendRegistryResponse(server, player, Response.MOVING_WORLD)
|
||||
return
|
||||
}
|
||||
server.register(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the removal of a player.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handlePlayerRemoval(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val session = server.players[username]
|
||||
if (session != null) {
|
||||
session.isActive = false
|
||||
val player = server.players.remove(username)
|
||||
if (player != null) {
|
||||
session.remove()
|
||||
}
|
||||
session.worldId = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a player registration.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handlePunishment(server: GameServer, buffer: IoBuffer) {
|
||||
val type = buffer.get() and 0xFF
|
||||
val target = buffer.string
|
||||
val duration = buffer.long
|
||||
val staff = buffer.string
|
||||
PunishmentStorage.handlePunishment(staff, target, type, duration)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the communication info request packet.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleCommunicationRequest(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val player = server.players[username] ?: return
|
||||
sendContactInformation(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a contact update packet.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer to read from.
|
||||
* @param block If the list is for blocked players.
|
||||
*/
|
||||
private fun handleContactUpdate(server: GameServer, buffer: IoBuffer, block: Boolean) {
|
||||
val username = buffer.string
|
||||
val player = server.players[username] ?: return
|
||||
val contact = buffer.string
|
||||
when (buffer.get()) {
|
||||
0 -> {
|
||||
if (block) {
|
||||
player.communication.block(contact)
|
||||
}
|
||||
player.communication.add(contact)
|
||||
}
|
||||
1 -> player.communication.remove(contact, block)
|
||||
2 -> player.communication.updateClanRank(contact, ClanRank.values()[buffer.get()])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan related packet.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleJoinClan(server: GameServer, buffer: IoBuffer) {
|
||||
val name = buffer.string
|
||||
val clanName = buffer.string
|
||||
val player = server.players[name]
|
||||
if (player == null || !player.isActive) {
|
||||
System.err.println("Invalid player specified in clan packet!")
|
||||
return
|
||||
}
|
||||
if (player.clan != null) {
|
||||
player.clan.leave(player, true)
|
||||
return
|
||||
}
|
||||
if (clanName.length < 1) {
|
||||
sendLeaveClan(player)
|
||||
return
|
||||
}
|
||||
val clan = ClanRepository.get(server, clanName)
|
||||
if (clan == null) {
|
||||
sendPlayerMessage(
|
||||
player,
|
||||
arrayOf(
|
||||
"The channel you tried to join does not exist.",
|
||||
"Try joining the main clan named '2009Scape'.:clan:"
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
clan.enter(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles renaming a clan.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleClanRename(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val name = buffer.string
|
||||
val player = server.players[username]
|
||||
if (player == null || !player.isActive) {
|
||||
return
|
||||
}
|
||||
val clan = ClanRepository.getClans()[username]
|
||||
player.communication.clanName = name
|
||||
if (clan != null) {
|
||||
if (name.isEmpty()) {
|
||||
clan.clean(true)
|
||||
} else {
|
||||
clan.rename(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changing clan settings packet.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleClanSetting(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val type = buffer.get()
|
||||
val rank = if (type < 4) ClanRank.values()[buffer.get() and 0xFF] else null
|
||||
val player = server.players[username]
|
||||
if (player == null || !player.isActive) {
|
||||
return
|
||||
}
|
||||
val clan = ClanRepository.get(server, username)
|
||||
when (type) {
|
||||
0 -> {
|
||||
player.communication.joinRequirement = rank
|
||||
clan?.clean(false)
|
||||
}
|
||||
1 -> player.communication.messageRequirement = rank
|
||||
2 -> {
|
||||
player.communication.kickRequirement = rank
|
||||
clan?.update()
|
||||
}
|
||||
3 -> player.communication.lootRequirement = rank
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles kicking a player from the clan.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleClanKick(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val playerName = buffer.string
|
||||
val player = server.players[username]
|
||||
if (player == null || !player.isActive || player.clan == null) {
|
||||
return
|
||||
}
|
||||
val target = WorldDatabase.getPlayer(playerName)
|
||||
if (target == null || !target.isActive) {
|
||||
return
|
||||
}
|
||||
player.clan.kick(player, target)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan message.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleClanMessage(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val message = buffer.string
|
||||
val player = server.players[username]
|
||||
if (player == null || !player.isActive || player.clan == null) {
|
||||
return
|
||||
}
|
||||
player.clan.message(player, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan message.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handlePrivateMessage(server: GameServer, buffer: IoBuffer) {
|
||||
val username = buffer.string
|
||||
val receiver = buffer.string
|
||||
val message = buffer.string
|
||||
val player = server.players[username]
|
||||
if (player == null || !player.isActive) {
|
||||
return
|
||||
}
|
||||
player.communication.sendMessage(receiver, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan information request packet.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleClanInfoRequest(server: GameServer, buffer: IoBuffer) {
|
||||
val name = buffer.string
|
||||
val clan = ClanRepository.get(server, name) ?: return
|
||||
sendClanInformation(server, clan)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a chat setting update packet.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private fun handleChatSetting(server: GameServer, buffer: IoBuffer) {
|
||||
val name = buffer.string
|
||||
val publicSetting = buffer.get()
|
||||
val privateSetting = buffer.get()
|
||||
val tradeSetting = buffer.get()
|
||||
val player = server.players[name]
|
||||
if (player == null || !player.isActive) {
|
||||
return
|
||||
}
|
||||
player.communication.updateSettings(publicSetting, privateSetting, tradeSetting)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package ms.net.producer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.event.HSReadEvent;
|
||||
import ms.net.event.HSWriteEvent;
|
||||
|
||||
/**
|
||||
* Produces I/O events for the handshake protocol.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class HSEventProducer implements EventProducer {
|
||||
|
||||
@Override
|
||||
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
|
||||
return new HSReadEvent(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoWriteEvent produceWriter(IoSession session, Object context) {
|
||||
return new HSWriteEvent(session, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package ms.net.producer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.event.PacketReadEvent;
|
||||
import ms.net.event.PacketWriteEvent;
|
||||
|
||||
/**
|
||||
* The packet event producer.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PacketEventProducer implements EventProducer {
|
||||
|
||||
@Override
|
||||
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
|
||||
return new PacketReadEvent(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoWriteEvent produceWriter(IoSession session, Object context) {
|
||||
return new PacketWriteEvent(session, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package ms.net.producer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.event.RegistryReadEvent;
|
||||
import ms.net.event.RegistryWriteEvent;
|
||||
|
||||
/**
|
||||
* Handles world server registry.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegistryEventProducer implements EventProducer {
|
||||
|
||||
@Override
|
||||
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
|
||||
return new RegistryReadEvent(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoWriteEvent produceWriter(IoSession session, Object context) {
|
||||
return new RegistryWriteEvent(session, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package ms.system
|
||||
|
||||
/**
|
||||
* The operating systems
|
||||
* @author Clayton Williams
|
||||
*/
|
||||
enum class OperatingSystem {
|
||||
UNIX, WINDOWS
|
||||
}
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
package ms.system;
|
||||
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.mysql.SQLManager;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.world.info.UIDInfo;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Used for storing and handling punishment data.
|
||||
* @author Emperor
|
||||
* @author Vexia
|
||||
*
|
||||
*/
|
||||
public final class PunishmentStorage {
|
||||
|
||||
/**
|
||||
* The type ids for IP, MAC and SERIAL bans.
|
||||
*/
|
||||
public static final int IP = 2, MAC = 3, SERIAL = 4;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PunishmentStorage} {@code Object}.
|
||||
*/
|
||||
public PunishmentStorage() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a punishment.
|
||||
* @param staff The name of the staff member dealing the punishment.
|
||||
* @param target The target.
|
||||
* @param type The punishment type.
|
||||
* @param duration The duration of the punishment (in milliseconds).
|
||||
*/
|
||||
public static void handlePunishment(String name, String target, int type, long duration) {
|
||||
PlayerSession staff = WorldDatabase.getPlayer(name);
|
||||
PlayerSession player = WorldDatabase.getPlayer(target, true);
|
||||
if (player == null) {
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Player " + target + " is invalid!");
|
||||
return;
|
||||
}
|
||||
long end = Long.MAX_VALUE;
|
||||
if (duration != -1L && duration != 0L) {
|
||||
end = System.currentTimeMillis() + duration;
|
||||
} else if (duration == 0L) {
|
||||
end = 0L;
|
||||
}
|
||||
String key = "null";
|
||||
switch (type) {
|
||||
case 0: //Mute
|
||||
case 1: //Ban
|
||||
if (type == 1 && end == 0L) {
|
||||
unban(player.getIpAddress());
|
||||
unban(player.getMacAddress());
|
||||
unban(player.getSerialKey());
|
||||
}
|
||||
if (player.isActive()) {
|
||||
WorldPacketRepository.sendPunishUpdate(player.getWorld(), player.getUsername(), type, end);
|
||||
}
|
||||
notify(staff, type == 0 ? "mute" : "ban", target, end);
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("UPDATE members SET " + (type == 0 ? "muteTime" : "banTime") + "='" + end + "' WHERE username ='" + target + "'");
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return;
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
return;
|
||||
case 2:
|
||||
ban(player.getIpAddress(), type);
|
||||
notify(staff, "IP-ban", target, end);
|
||||
notifyServers(key = player.getIpAddress(), type, end);
|
||||
break;
|
||||
case 3:
|
||||
ban(player.getMacAddress(), type);
|
||||
notify(staff, "MAC-ban", target, end);
|
||||
notifyServers(key = player.getMacAddress(), type, end);
|
||||
break;
|
||||
case 4:
|
||||
ban(player.getSerialKey(), type);
|
||||
notify(staff, "UID-ban", target, end);
|
||||
notifyServers(key = player.getSerialKey(), type, end);
|
||||
break;
|
||||
case 5:
|
||||
ban(player.getIpAddress(), 2);
|
||||
notifyServers(key = player.getIpAddress(), 2, end);
|
||||
ban(player.getMacAddress(), 3);
|
||||
notifyServers(key = player.getMacAddress(), 3, end);
|
||||
ban(player.getSerialKey(), 4);
|
||||
notifyServers(key = player.getSerialKey(), 4, end);
|
||||
notify(staff, "full ban", target, end);
|
||||
return;
|
||||
case 6: //Kick
|
||||
if (player.isActive()) {
|
||||
WorldPacketRepository.sendPunishUpdate(player.getWorld(), player.getUsername(), 6, end);
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Successfully kicked player " + target + " from world " + player.getWorldId() + ".");
|
||||
} else {
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Player " + target + " was already inactive.");
|
||||
}
|
||||
break;
|
||||
case 7: //Request info
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "[----------Player info----------]");
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Name: " + player.getUsername());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "IP address: " + player.getIpAddress());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "MAC address: " + player.getMacAddress());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Serial key: " + player.getSerialKey());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Computer name: " + player.getComputerName());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "[-------------------------------]");
|
||||
return;
|
||||
}
|
||||
notifyServers(key, type, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bans an address.
|
||||
* @param address the address.
|
||||
* @return {@code True} if banned.
|
||||
*/
|
||||
public static boolean ban(String address, int type) {
|
||||
if (address == null || address.length() == 0 || address.equals("To be filled by O.E.M.") || address.equals("To be filled by O.E.M") || address.equals("Base Board Serial Number")) {
|
||||
System.out.println("Error! Can't ban address " + address + " type = " + type + "!");
|
||||
return false;
|
||||
}
|
||||
if (isBanned(address)) {
|
||||
return false;
|
||||
}
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("INSERT INTO punishments VALUES('" + address + "','" + type + "')");
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbans an address.
|
||||
* @param address the address.
|
||||
* @return {@code True} if unbanned.
|
||||
*/
|
||||
public static boolean unban(String address) {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("DELETE from punishments WHERE address ='" + address + "'");
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the punishing player of success.
|
||||
* @param staff The punishing player.
|
||||
* @param type The punishment type.
|
||||
* @param target The target name.
|
||||
* @param end The end time stamp of the punishment.
|
||||
*/
|
||||
private static void notify(PlayerSession staff, String type, String target, long end) {
|
||||
if (end <= System.currentTimeMillis()) {
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Successfully removed punishment [type=" + type + ", player=" + target + "].");
|
||||
return;
|
||||
}
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Successfully punished player " + target + " [type=" + type + ", duration=" + getDuration(end) + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the game servers of a punishment update.
|
||||
* @param key The punishment key.
|
||||
* @param type The type.
|
||||
* @param duration The duration.
|
||||
*/
|
||||
public static void notifyServers(String key, int type, long duration) {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.sendPunishUpdate(server, key, type, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the UID Info is banned.
|
||||
* @param info the info.
|
||||
* @return {@code True} if banned.
|
||||
*/
|
||||
public static boolean isSystemBanned(UIDInfo info) {
|
||||
return isBanned(info.getIp()) || isBanned(info.getMac()) || isBanned(info.getSerial());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checked if an address is banned.
|
||||
* @param address the address.
|
||||
* @param type the type.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean isBanned(String address) {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ResultSet set = connection.createStatement().executeQuery("SELECT * FROM punishments WHERE address ='" + address +"'");
|
||||
if (set == null || !set.next()) {
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration string representation.
|
||||
* @param end The end time.
|
||||
* @return The string.
|
||||
*/
|
||||
private static String getDuration(long end) {
|
||||
String time = "indefinite time";
|
||||
if (end != Long.MAX_VALUE) {
|
||||
int days = (int) ((System.currentTimeMillis()) / (24 * 60 * 60_000));
|
||||
int hours = (int) (((24L * days * 60 * 60_000)) / (60 * 60_000));
|
||||
int minutes = (int) (((hours * (60 * 60_000))) / 60_000);
|
||||
time = days + "d, " + hours + "h, " + minutes + "m";
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package ms.system;
|
||||
|
||||
|
||||
import ms.Management;
|
||||
|
||||
/**
|
||||
* The shutdown sequence used for safely turning off the Management server.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ShutdownSequence extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (Management.active) {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely shuts down the Management server.
|
||||
*/
|
||||
public static void shutdown() {
|
||||
System.out.println("Management server successfully shut down!");
|
||||
Management.active = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
package ms.system.communication;
|
||||
|
||||
/**
|
||||
* Represents the rank of a clan member.
|
||||
* @author Emperor
|
||||
*/
|
||||
public enum ClanRank {
|
||||
NONE(-1, "Anyone"),
|
||||
FRIEND(0, "Any friends"),
|
||||
RECRUIT(1, "Recruit+"),
|
||||
CORPORAL(2, "Corporal+"),
|
||||
SERGEANT(3, "Sergeant+"),
|
||||
LIEUTENANT(4, "Lieutenant+"),
|
||||
CAPTAIN(5, "Captain+"),
|
||||
GENERAL(6, "General+"),
|
||||
OWNER(7, "Only me"),
|
||||
ADMINISTRATOR(127, "No-one");
|
||||
|
||||
/**
|
||||
* The value of the rank.
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* The requirement info.
|
||||
*/
|
||||
private final String info;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ClanRank} {@code Object}.
|
||||
* @param value The rank value.
|
||||
* @param info The requirement info.
|
||||
*/
|
||||
private ClanRank(int value, String info) {
|
||||
this.value = value;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
* @return The value.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the info.
|
||||
* @return The info.
|
||||
*/
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
package ms.system.communication;
|
||||
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.util.StringUtils;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.world.info.UIDInfo;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Holds clan related information.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ClanRepository {
|
||||
|
||||
/**
|
||||
* The mapping of active clans.
|
||||
*/
|
||||
private static final Map<String, ClanRepository> CLANS = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The maximum amount of members to be in a clan chat.
|
||||
*/
|
||||
public static final int MAX_MEMBERS = 100;
|
||||
|
||||
/**
|
||||
* The owner's details.
|
||||
*/
|
||||
private PlayerSession owner;
|
||||
|
||||
/**
|
||||
* The list of players currently in the chat.
|
||||
*/
|
||||
private final List<PlayerSession> players = new ArrayList<>(MAX_MEMBERS);
|
||||
|
||||
/**
|
||||
* The banned players.
|
||||
*/
|
||||
private final Map<String, Long> banned = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ClanRepository} {@code Object}.
|
||||
*/
|
||||
private ClanRepository() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan repository for the given username.
|
||||
* @param ownerName The clan owner's name.
|
||||
* @return The clan repository.
|
||||
*/
|
||||
public static ClanRepository get(GameServer server, String ownerName) {
|
||||
ClanRepository clan = CLANS.get(ownerName);
|
||||
if (clan != null) {
|
||||
return clan;
|
||||
}
|
||||
PlayerSession owner = WorldDatabase.getPlayer(ownerName);
|
||||
if (owner == null) {
|
||||
owner = new PlayerSession(ownerName, ownerName, new UIDInfo());
|
||||
owner.parse();
|
||||
}
|
||||
if (owner.getCommunication().getClanName().equals("")) {
|
||||
return null;
|
||||
}
|
||||
clan = new ClanRepository();
|
||||
clan.owner = owner;
|
||||
CLANS.put(ownerName, clan);
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters the clan chat.
|
||||
* @param player The player.
|
||||
*/
|
||||
public void enter(PlayerSession player) {
|
||||
if (players.size() >= MAX_MEMBERS && !owner.getUsername().equals("2009scape")) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "The channel you tried to join is full.:clan:");
|
||||
return;
|
||||
}
|
||||
if (player != owner && player.getRights() != 2) {
|
||||
if (isBanned(player.getUsername()) || owner.getCommunication().getBlocked().contains(player.getUsername())) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You are temporarily banned from this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
ClanRank rank = getRank(player);
|
||||
if (rank.ordinal() < getJoinRequirement().ordinal()) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You do not have a high enough rank to join this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!players.contains(player)) {
|
||||
players.add(player);
|
||||
}
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Now talking in clan channel " + owner.getCommunication().getClanName() + ".:clan:");
|
||||
WorldPacketRepository.sendPlayerMessage(player, "To talk, start each line of chat with the / symbol.:clan:");
|
||||
player.getCommunication().setCurrentClan(owner.getUsername());
|
||||
player.setClan(this);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the clan chat.
|
||||
* @param player The player to leave.
|
||||
* @param remove If the player should be removed from the list.
|
||||
*/
|
||||
public void leave(PlayerSession player, boolean remove) {
|
||||
if (remove) {
|
||||
players.remove(player);
|
||||
update();
|
||||
if (players.size() < 1) {
|
||||
banned.clear();
|
||||
}
|
||||
}
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You have left the channel.:clan:");
|
||||
player.setClan(null);
|
||||
player.getCommunication().setCurrentClan(null);
|
||||
if (player.isActive()) {
|
||||
WorldPacketRepository.sendLeaveClan(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to all players in the chat.
|
||||
* @param player The player sending the message.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public void message(PlayerSession player, String message) {
|
||||
if (player != owner && player.getRights() != 2) {
|
||||
ClanRank rank = getRank(player);
|
||||
if (rank.ordinal() < getMessageRequirement().ordinal()) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You do not have a high enough rank to talk in this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (Iterator<PlayerSession> it = players.iterator(); it.hasNext();) {
|
||||
PlayerSession p = it.next();
|
||||
if (p != null) {
|
||||
WorldPacketRepository.sendMessage(p, player, 2, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the clan chat.
|
||||
*/
|
||||
public void update() {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.sendClanInformation(server, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks a player from the clan chat.
|
||||
* @param player The player.
|
||||
*/
|
||||
public void kick(PlayerSession player, PlayerSession target) {
|
||||
ClanRank rank = getRank(target);
|
||||
if (target.getRights() == 2) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You can't kick an administrator.:clan:");
|
||||
return;
|
||||
}
|
||||
System.out.println(rank + ", " + player.getUsername());
|
||||
if (player.getRights() < 1/*!= 2 && rank.ordinal() < getKickRequirement().ordinal()*/) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You do not have a high enough rank to kick in this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
if (target == owner) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You can't kick the owner of this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
if (target == player) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You can't kick yourself.:clan:");
|
||||
return;
|
||||
}
|
||||
for (PlayerSession p : players) {
|
||||
WorldPacketRepository.sendMessage(p, player, 2, "[Attempting to kick/ban " + StringUtils.formatDisplayName(target.getUsername()) + " from this Clan Chat.]");
|
||||
}
|
||||
leave(target, true);
|
||||
banned.put(target.getUsername(), System.currentTimeMillis() + (3_600_000));
|
||||
WorldPacketRepository.sendPlayerMessage(target, "You have been kicked from the channel.:clan:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank for the given player.
|
||||
* @param player The player.
|
||||
* @return The rank.
|
||||
*/
|
||||
public ClanRank getRank(PlayerSession player) {
|
||||
ClanRank rank = owner.getCommunication().getContacts().get(player.getUsername());
|
||||
if (player.getRights() == 2 && player != owner) {
|
||||
return ClanRank.ADMINISTRATOR;
|
||||
}
|
||||
if (rank == null) {
|
||||
if (player == owner) {
|
||||
return ClanRank.OWNER;
|
||||
}
|
||||
return ClanRank.NONE;
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player is banned.
|
||||
* @param username The username of the player.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
private boolean isBanned(String username) {
|
||||
Long time = banned.get(username);
|
||||
if (time == null) {
|
||||
return false;
|
||||
}
|
||||
if (time < System.currentTimeMillis()) {
|
||||
banned.remove(username);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the clan chat.
|
||||
* @param disable If the clan chat is getting disabled.
|
||||
*/
|
||||
public void clean(boolean disable) {
|
||||
for (Iterator<PlayerSession> it = players.iterator(); it.hasNext();) {
|
||||
PlayerSession player = it.next();
|
||||
boolean remove = disable;
|
||||
if (!remove) {
|
||||
remove = getRank(player).ordinal() < getJoinRequirement().getValue();
|
||||
}
|
||||
if (remove) {
|
||||
leave(player, false);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
if (players.isEmpty()) {
|
||||
banned.clear();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the clan chat.
|
||||
* @param name The new clan name.
|
||||
*/
|
||||
public void rename(String name) {
|
||||
owner.getCommunication().setClanName(name);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan name.
|
||||
* @return The clan name.
|
||||
*/
|
||||
public String getName() {
|
||||
return owner.getCommunication().getClanName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the owner value.
|
||||
* @return The owner.
|
||||
*/
|
||||
public PlayerSession getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the owner value.
|
||||
* @param owner The owner to set.
|
||||
*/
|
||||
public void setOwner(PlayerSession owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the players value.
|
||||
* @return The players.
|
||||
*/
|
||||
public List<PlayerSession> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clans value.
|
||||
* @return The clans.
|
||||
*/
|
||||
public static Map<String, ClanRepository> getClans() {
|
||||
return CLANS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joinRequirement value.
|
||||
* @return The joinRequirement.
|
||||
*/
|
||||
public ClanRank getJoinRequirement() {
|
||||
return owner.getCommunication().getJoinRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the messageRequirement value.
|
||||
* @return The messageRequirement.
|
||||
*/
|
||||
public ClanRank getMessageRequirement() {
|
||||
return owner.getCommunication().getMessageRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kickRequirement value.
|
||||
* @return The kickRequirement.
|
||||
*/
|
||||
public ClanRank getKickRequirement() {
|
||||
return owner.getCommunication().getKickRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lootRequirement value.
|
||||
* @return The lootRequirement.
|
||||
*/
|
||||
public ClanRank getLootRequirement() {
|
||||
return owner.getCommunication().getLootRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the banned value.
|
||||
* @return The banned.
|
||||
*/
|
||||
public Map<String, Long> getBanned() {
|
||||
return banned;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,656 +0,0 @@
|
|||
package ms.system.communication;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
import ms.system.util.StringUtils;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Holds communication information.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class CommunicationInfo {
|
||||
|
||||
/**
|
||||
* The maximum list size.
|
||||
*/
|
||||
public static final int MAX_LIST_SIZE = 200;
|
||||
|
||||
/**
|
||||
* The clan ranks.
|
||||
*/
|
||||
private final Map<String, ClanRank> contacts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The list of blocked players.
|
||||
*/
|
||||
private final List<String> blocked = new ArrayList<>(20);
|
||||
|
||||
/**
|
||||
* The player's clan name.
|
||||
*/
|
||||
private String clanName = "";
|
||||
|
||||
/**
|
||||
* The current clan this player is in.
|
||||
*/
|
||||
private String currentClan = "2009scape";
|
||||
|
||||
/**
|
||||
* The rank required for joining.
|
||||
*/
|
||||
private ClanRank joinRequirement = ClanRank.FRIEND;
|
||||
|
||||
/**
|
||||
* The rank required for messaging.
|
||||
*/
|
||||
private ClanRank messageRequirement = ClanRank.NONE;
|
||||
|
||||
/**
|
||||
* The rank required for kicking members.
|
||||
*/
|
||||
private ClanRank kickRequirement = ClanRank.OWNER;
|
||||
|
||||
/**
|
||||
* The rank required for loot-share.
|
||||
*/
|
||||
private ClanRank lootRequirement = ClanRank.ADMINISTRATOR;
|
||||
|
||||
/**
|
||||
* The public chat setting.
|
||||
*/
|
||||
private int publicChatSetting = 0;
|
||||
|
||||
/**
|
||||
* The private chat setting.
|
||||
*/
|
||||
private int privateChatSetting = 0;
|
||||
|
||||
/**
|
||||
* The trade setting.
|
||||
*/
|
||||
private int tradeSetting = 0;
|
||||
|
||||
/**
|
||||
* The player session.
|
||||
*/
|
||||
private PlayerSession player;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code CommunicationInfo} {@code Object}.
|
||||
* @param player The player.
|
||||
*/
|
||||
public CommunicationInfo(PlayerSession player) {
|
||||
this.setPlayer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the player logs in.
|
||||
*/
|
||||
public void sync() {
|
||||
if (privateChatSetting != 2) {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
List<String> names = new ArrayList<>(20);
|
||||
for (PlayerSession p : server.getPlayers().values()) {
|
||||
if (p.isActive() && p.getCommunication().contacts.containsKey(player.getUsername())) {
|
||||
if (privateChatSetting == 0 || contacts.containsKey(p.getUsername())) {
|
||||
names.add(p.getUsername());
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldPacketRepository.notifyPlayers(server, player, names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the player logs out.
|
||||
*/
|
||||
public void clear() {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.notifyLogout(server, player);
|
||||
}
|
||||
}
|
||||
if (player.getClan() != null) {
|
||||
player.getClan().leave(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the communication info.
|
||||
* @param statement The buffer.
|
||||
* @throws SQLException The exception if thrown.
|
||||
*/
|
||||
public void save(PreparedStatement statement) throws SQLException {
|
||||
String contacts = "";
|
||||
String blocked = "";
|
||||
StringBuilder blockedBuilder = new StringBuilder();
|
||||
for (int i = 0; i < this.blocked.size(); i++) {
|
||||
String blockline = (i == 0 ? "" : ",") + this.blocked.get(i);
|
||||
blockedBuilder.append(blockline);
|
||||
}
|
||||
blocked = blockedBuilder.toString();
|
||||
int count = 0;
|
||||
StringBuilder contactBuilder = new StringBuilder();
|
||||
for (Entry<String, ClanRank> entry : this.contacts.entrySet()) {
|
||||
String contactLine = "{" + entry.getKey() + "," + entry.getValue().ordinal() + "}" + (count == this.contacts.size() - 1 ? "" : "~");
|
||||
contactBuilder.append(contactLine);
|
||||
count++;
|
||||
}
|
||||
contacts = contactBuilder.toString();
|
||||
statement.setString(3, contacts);
|
||||
statement.setString(4, blocked);
|
||||
statement.setString(5, clanName);
|
||||
statement.setString(6, currentClan);
|
||||
statement.setString(7, joinRequirement.ordinal() + "," + messageRequirement.ordinal() + "," + kickRequirement.ordinal() + "," + lootRequirement.ordinal());
|
||||
statement.setString(8, publicChatSetting + "," + privateChatSetting + "," + tradeSetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the communication info from the database.
|
||||
* @param set The result set.
|
||||
* @throws SQLException The exception if thrown.
|
||||
*/
|
||||
public void parse(ResultSet set) throws SQLException {
|
||||
String contacts = set.getString("contacts");
|
||||
String[] tokens;
|
||||
if (contacts != null && !contacts.isEmpty()) {
|
||||
String[] datas = contacts.split("~");
|
||||
for (String d : datas) {
|
||||
tokens = d.replace("{", "").replace("}", "").split(",");
|
||||
if (tokens.length < 2) {
|
||||
continue;
|
||||
}
|
||||
this.contacts.put(tokens[0], ClanRank.values()[Integer.parseInt(tokens[1])]);
|
||||
}
|
||||
}
|
||||
String bl = set.getString("blocked");
|
||||
if (bl != null && !bl.isEmpty()) {
|
||||
tokens = bl.split(",");
|
||||
blocked.addAll(Arrays.asList(tokens));
|
||||
}
|
||||
clanName = set.getString("clanName");
|
||||
currentClan = set.getString("currentClan");
|
||||
String clanReqs = set.getString("clanReqs");
|
||||
if (!clanReqs.isEmpty()) {
|
||||
tokens = clanReqs.split(",");
|
||||
ClanRank rank = null;
|
||||
int ordinal = 0;
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
ordinal = Integer.parseInt(tokens[i]);
|
||||
if (ordinal < 0 || ordinal > ClanRank.values().length -1) {
|
||||
continue;
|
||||
}
|
||||
rank = ClanRank.values()[ordinal];
|
||||
switch (i) {
|
||||
case 0:
|
||||
joinRequirement = rank;
|
||||
break;
|
||||
case 1:
|
||||
messageRequirement = rank;
|
||||
break;
|
||||
case 2:
|
||||
if (ordinal < 3 || ordinal > 8) {
|
||||
break;
|
||||
}
|
||||
kickRequirement = rank;
|
||||
break;
|
||||
case 3:
|
||||
lootRequirement = rank;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String chatSettings = set.getString("chatSettings");
|
||||
if (!chatSettings.isEmpty()) {
|
||||
tokens = chatSettings.split(",");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
publicChatSetting = Integer.parseInt(tokens[0]);
|
||||
break;
|
||||
case 1:
|
||||
privateChatSetting = Integer.parseInt(tokens[1]);
|
||||
break;
|
||||
case 2:
|
||||
tradeSetting = Integer.parseInt(tokens[2]);
|
||||
break;
|
||||
default:
|
||||
System.out.println("Illegal arg count in chatsetting string: " + chatSettings);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the communication info.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void save(ByteBuffer buffer) {
|
||||
buffer.put((byte) contacts.size());
|
||||
for(Entry<String,ClanRank> contact : contacts.entrySet()){
|
||||
ByteBufferUtils.putString(contact.getKey(), buffer);
|
||||
buffer.put((byte) contact.getValue().ordinal());
|
||||
}
|
||||
buffer.put((byte) blocked.size());
|
||||
for (String name : blocked) {
|
||||
ByteBufferUtils.putString(name, buffer);
|
||||
}
|
||||
ByteBufferUtils.putString(clanName, buffer);
|
||||
if (currentClan != null) {
|
||||
ByteBufferUtils.putString(currentClan, buffer.put((byte) 1));
|
||||
} else {
|
||||
buffer.put((byte) 0);
|
||||
}
|
||||
buffer.put((byte) joinRequirement.ordinal());
|
||||
buffer.put((byte) messageRequirement.ordinal());
|
||||
buffer.put((byte) kickRequirement.ordinal());
|
||||
buffer.put((byte) lootRequirement.ordinal());
|
||||
buffer.put((byte) publicChatSetting);
|
||||
buffer.put((byte) privateChatSetting);
|
||||
buffer.put((byte) tradeSetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the communication info from the buffer.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void parse(ByteBuffer buffer) {
|
||||
int length = buffer.get() & 0xFF;
|
||||
for (int i = 0; i < length; i++) {
|
||||
contacts.put(ByteBufferUtils.getString(buffer), ClanRank.values()[buffer.get() & 0xFF]);
|
||||
}
|
||||
length = buffer.get() & 0xFF;
|
||||
for (int i = 0; i < length; i++) {
|
||||
blocked.add(ByteBufferUtils.getString(buffer));
|
||||
}
|
||||
clanName = ByteBufferUtils.getString(buffer);
|
||||
if (buffer.get() == 1) {
|
||||
currentClan = ByteBufferUtils.getString(buffer);
|
||||
}
|
||||
joinRequirement = ClanRank.values()[buffer.get()];
|
||||
messageRequirement = ClanRank.values()[buffer.get()];
|
||||
kickRequirement = ClanRank.values()[buffer.get()];
|
||||
lootRequirement = ClanRank.values()[buffer.get()];
|
||||
publicChatSetting = buffer.get();
|
||||
privateChatSetting = buffer.get();
|
||||
tradeSetting = buffer.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the target.
|
||||
* @param target The target.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public void sendMessage(String target, String message) {
|
||||
PlayerSession receiver = WorldDatabase.getPlayer(target);
|
||||
if (receiver == null || !receiver.isActive()) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "That player is currently offline.");
|
||||
return;
|
||||
}
|
||||
WorldPacketRepository.sendMessage(player, receiver, 0, message);
|
||||
WorldPacketRepository.sendMessage(receiver, player, 1, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a contact.
|
||||
* @param contact The contact to add.
|
||||
*/
|
||||
public void add(String contact) {
|
||||
if (contacts.size() >= MAX_LIST_SIZE) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Your friend list is full.");
|
||||
return;
|
||||
}
|
||||
if (blocked.contains(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Please remove " + StringUtils.formatDisplayName(contact) + " from your ignored list first.");
|
||||
return;
|
||||
}
|
||||
if (contacts.containsKey(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, StringUtils.formatDisplayName(contact) + " is already on your friend list.");
|
||||
return;
|
||||
}
|
||||
contacts.put(contact, ClanRank.FRIEND);
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, false, false, getWorldId(player, contact), null);
|
||||
ClanRepository clan = ClanRepository.getClans().get(player.getUsername());
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
if (privateChatSetting == 1) {
|
||||
PlayerSession other = WorldDatabase.getPlayer(contact);
|
||||
if (other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, getWorldId(other, player.getUsername()), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world id for the given contact.
|
||||
* @param player The player.
|
||||
* @param contact The contact.
|
||||
* @return The world id to display.
|
||||
*/
|
||||
public static int getWorldId(PlayerSession player, String contact) {
|
||||
PlayerSession p = WorldDatabase.getPlayer(contact);
|
||||
if (p == null || !p.isActive() || p.getCommunication().getPrivateChatSetting() == 2) {
|
||||
return 0;
|
||||
}
|
||||
if (p.getCommunication().getBlocked().contains(player.getUsername())) {
|
||||
return 0;
|
||||
}
|
||||
if (p.getCommunication().getPrivateChatSetting() == 1) {
|
||||
if (p.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
return p.getWorldId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return p.getWorldId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a contact.
|
||||
* @param contact The contact to remove.
|
||||
* @param block If the contact should be removed from the block list.
|
||||
*/
|
||||
public void remove(String contact, boolean block) {
|
||||
PlayerSession other = WorldDatabase.getPlayer(contact);
|
||||
if (block) {
|
||||
blocked.remove(contact);
|
||||
if (other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, getWorldId(other, player.getUsername()), null);
|
||||
}
|
||||
} else {
|
||||
contacts.remove(contact);
|
||||
ClanRepository clan = ClanRepository.getClans().get(player.getUsername());
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
if (privateChatSetting == 1 && other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, getWorldId(other, player.getUsername()), null);
|
||||
}
|
||||
}
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, block, true, 0, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a blocked contact.
|
||||
* @param contact The contact to block.
|
||||
*/
|
||||
public void block(String contact) {
|
||||
if (blocked.size() >= MAX_LIST_SIZE) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Your ignore list is full.");
|
||||
return;
|
||||
}
|
||||
if (contacts.containsKey(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Please remove " + StringUtils.formatDisplayName(contact) + " from your friends list first.");
|
||||
return;
|
||||
}
|
||||
if (blocked.contains(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, StringUtils.formatDisplayName(contact) + " is already on your friend list.");
|
||||
return;
|
||||
}
|
||||
blocked.add(contact);
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, true, false, 0, null);
|
||||
PlayerSession other = WorldDatabase.getPlayer(contact);
|
||||
if (other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the clan rank of a certain contact.
|
||||
* @param contact The contact.
|
||||
* @param clanRank The clan rank to set.
|
||||
*/
|
||||
public void updateClanRank(String contact, ClanRank clanRank) {
|
||||
if (!contacts.containsKey(contact)) {
|
||||
System.err.println("Could not find contact " + contact + " to update clan rank!");
|
||||
return;
|
||||
}
|
||||
contacts.put(contact, clanRank);
|
||||
ClanRepository clan = ClanRepository.getClans().get(player.getUsername());
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, false, false, 0, clanRank);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the settings.
|
||||
* @param publicSetting The public chat setting.
|
||||
* @param privateSetting The private chat setting.
|
||||
* @param tradeSetting The trade setting.
|
||||
*/
|
||||
public void updateSettings(int publicSetting, int privateSetting, int tradeSetting) {
|
||||
this.publicChatSetting = publicSetting;
|
||||
this.tradeSetting = tradeSetting;
|
||||
if (this.privateChatSetting != privateSetting) {
|
||||
updatePrivateSetting(privateSetting);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the private chat setting.
|
||||
* @param privateSetting The private chat setting.
|
||||
*/
|
||||
private void updatePrivateSetting(int privateSetting) {
|
||||
this.privateChatSetting = privateSetting;
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
if (privateSetting == 2) {
|
||||
WorldPacketRepository.notifyLogout(server, player);
|
||||
continue;
|
||||
}
|
||||
for (PlayerSession p : server.getPlayers().values()) {
|
||||
if (p.isActive() && p.getCommunication().contacts.containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(p, player.getUsername(), false, false, getWorldId(p, player.getUsername()), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contacts value.
|
||||
* @return The contacts.
|
||||
*/
|
||||
public Map<String, ClanRank> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan rank for the given contact.
|
||||
* @param contact The contact.
|
||||
* @return The rank.
|
||||
*/
|
||||
public ClanRank getRank(String contact) {
|
||||
return contacts.get(contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blocked value.
|
||||
* @return The blocked.
|
||||
*/
|
||||
public List<String> getBlocked() {
|
||||
return blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clanName value.
|
||||
* @return The clanName.
|
||||
*/
|
||||
public String getClanName() {
|
||||
return clanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clanName value.
|
||||
* @param clanName The clanName to set.
|
||||
*/
|
||||
public void setClanName(String clanName) {
|
||||
this.clanName = clanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currentClan value.
|
||||
* @return The currentClan.
|
||||
*/
|
||||
public String getCurrentClan() {
|
||||
return currentClan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currentClan value.
|
||||
* @param currentClan The currentClan to set.
|
||||
*/
|
||||
public void setCurrentClan(String currentClan) {
|
||||
this.currentClan = currentClan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player value.
|
||||
* @return The player.
|
||||
*/
|
||||
public PlayerSession getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player value.
|
||||
* @param player The player to set.
|
||||
*/
|
||||
public void setPlayer(PlayerSession player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joinRequirement value.
|
||||
* @return The joinRequirement.
|
||||
*/
|
||||
public ClanRank getJoinRequirement() {
|
||||
return joinRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the joinRequirement value.
|
||||
* @param joinRequirement The joinRequirement to set.
|
||||
*/
|
||||
public void setJoinRequirement(ClanRank joinRequirement) {
|
||||
this.joinRequirement = joinRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the messageRequirement value.
|
||||
* @return The messageRequirement.
|
||||
*/
|
||||
public ClanRank getMessageRequirement() {
|
||||
return messageRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the messageRequirement value.
|
||||
* @param messageRequirement The messageRequirement to set.
|
||||
*/
|
||||
public void setMessageRequirement(ClanRank messageRequirement) {
|
||||
this.messageRequirement = messageRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kickRequirement value.
|
||||
* @return The kickRequirement.
|
||||
*/
|
||||
public ClanRank getKickRequirement() {
|
||||
return kickRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the kickRequirement value.
|
||||
* @param kickRequirement The kickRequirement to set.
|
||||
*/
|
||||
public void setKickRequirement(ClanRank kickRequirement) {
|
||||
this.kickRequirement = kickRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lootRequirement value.
|
||||
* @return The lootRequirement.
|
||||
*/
|
||||
public ClanRank getLootRequirement() {
|
||||
return lootRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lootRequirement value.
|
||||
* @param lootRequirement The lootRequirement to set.
|
||||
*/
|
||||
public void setLootRequirement(ClanRank lootRequirement) {
|
||||
this.lootRequirement = lootRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the publicChatSetting value.
|
||||
* @return The publicChatSetting.
|
||||
*/
|
||||
public int getPublicChatSetting() {
|
||||
return publicChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the publicChatSetting value.
|
||||
* @param publicChatSetting The publicChatSetting to set.
|
||||
*/
|
||||
public void setPublicChatSetting(int publicChatSetting) {
|
||||
this.publicChatSetting = publicChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the privateChatSetting value.
|
||||
* @return The privateChatSetting.
|
||||
*/
|
||||
public int getPrivateChatSetting() {
|
||||
return privateChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the privateChatSetting value.
|
||||
* @param privateChatSetting The privateChatSetting to set.
|
||||
*/
|
||||
public void setPrivateChatSetting(int privateChatSetting) {
|
||||
this.privateChatSetting = privateChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tradeSetting value.
|
||||
* @return The tradeSetting.
|
||||
*/
|
||||
public int getTradeSetting() {
|
||||
return tradeSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tradeSetting value.
|
||||
* @param tradeSetting The tradeSetting to set.
|
||||
*/
|
||||
public void setTradeSetting(int tradeSetting) {
|
||||
this.tradeSetting = tradeSetting;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
/**
|
||||
* Represents a column used in an SQL table.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class SQLColumn {
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The data type.
|
||||
*/
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
* If this column should never be updated in the database.
|
||||
*/
|
||||
private final boolean neverUpdate;
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* If the column value changed.
|
||||
*/
|
||||
private boolean changed;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLColumn} {@code Object}.
|
||||
* @param name The column name.
|
||||
* @param type The data type.
|
||||
*/
|
||||
public SQLColumn(String name, Class<?> type) {
|
||||
this(name, type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLColumn} {@code Object}.
|
||||
* @param name The column name.
|
||||
* @param type The data type.
|
||||
* @param neverUpdate If this column should never be updated in the database.
|
||||
*/
|
||||
public SQLColumn(String name, Class<?> type, boolean neverUpdate) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.neverUpdate = neverUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value.
|
||||
* @param value The value.
|
||||
*/
|
||||
public void updateValue(Object value) {
|
||||
this.changed = value != this.value;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
* @return The value.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
this.changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the changed.
|
||||
* @return The changed.
|
||||
*/
|
||||
public boolean isChanged() {
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the changed.
|
||||
* @param changed The changed to set.
|
||||
*/
|
||||
public void setChanged(boolean changed) {
|
||||
this.changed = changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type.
|
||||
* @return The type.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the neverUpdate.
|
||||
* @return The neverUpdate.
|
||||
*/
|
||||
public boolean isNeverUpdate() {
|
||||
return neverUpdate;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Handles an SQL entry.
|
||||
* @author Emperor
|
||||
* @param <T> The entry type.
|
||||
*/
|
||||
public abstract class SQLEntryHandler<T> {
|
||||
|
||||
/**
|
||||
* The connection.
|
||||
*/
|
||||
protected Connection connection;
|
||||
|
||||
/**
|
||||
* The entry.
|
||||
*/
|
||||
protected T entry;
|
||||
|
||||
/**
|
||||
* The result set.
|
||||
*/
|
||||
protected ResultSet result;
|
||||
|
||||
/**
|
||||
* The table name.
|
||||
*/
|
||||
protected String table;
|
||||
|
||||
/**
|
||||
* The column name.
|
||||
*/
|
||||
private String column;
|
||||
|
||||
/**
|
||||
* The value to use.
|
||||
*/
|
||||
protected String value;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLEntryHandler} {@code Object}.
|
||||
* @param entry The entry.
|
||||
* @param table The table name.
|
||||
* @param column column name.
|
||||
* @param value The column value.
|
||||
*/
|
||||
public SQLEntryHandler(T entry, String table, String column, String value) {
|
||||
this.entry = entry;
|
||||
this.table = table;
|
||||
this.column = column;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the SQL entry.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
public static void read(SQLEntryHandler<?> entry) {
|
||||
entry.connection = entry.getConnection();
|
||||
if (entry.connection == null) {
|
||||
//System.err.println("Could not read SQL data: connection is null!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
entry.read();
|
||||
if (entry.result == null || !entry.result.next()) {
|
||||
entry.create();
|
||||
} else {
|
||||
entry.parse();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
SQLManager.close(entry.connection);
|
||||
entry.connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the entry data on the SQL database.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
public static void write(SQLEntryHandler<?> entry) {
|
||||
write(entry, entry.getConnection(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the SQL entry.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
public static void write(SQLEntryHandler<?> entry, Connection connection, boolean commit) {
|
||||
if (connection == null) {
|
||||
//System.err.println("Could not write SQL data: connection is null!");
|
||||
return;
|
||||
}
|
||||
entry.connection = connection;
|
||||
try {
|
||||
if (!commit) {
|
||||
entry.connection.setAutoCommit(false);
|
||||
}
|
||||
entry.save();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (commit) {
|
||||
SQLManager.close(entry.connection);
|
||||
}
|
||||
entry.connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the table from the SQL database.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public void read() throws SQLException {
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT " + getReadSelection() + " FROM " + table + " WHERE " + column + " = ?");
|
||||
statement.setString(1, value);
|
||||
result = statement.executeQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result.
|
||||
* @return the result.
|
||||
*/
|
||||
public ResultSet getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selection.
|
||||
* @return The selection.
|
||||
*/
|
||||
public String getReadSelection() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the writing statement.
|
||||
* @param create If we are creating a new row.
|
||||
* @param columns The columns to update.
|
||||
*/
|
||||
public PreparedStatement getWritingStatement(boolean create, String...columns) {
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (create) {
|
||||
sb.append("INSERT INTO ").append(table).append(" (").append(column);
|
||||
for (String name : columns) {
|
||||
sb.append(",").append(name);
|
||||
}
|
||||
sb.append(") VALUES (?");
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(",?");
|
||||
}
|
||||
sb.append(")");
|
||||
} else {
|
||||
sb.append("UPDATE ").append(table).append(" SET ");
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(columns[i]).append("=?");
|
||||
if (i < columns.length - 1) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append(" WHERE ").append(column).append("=?");
|
||||
}
|
||||
statement = connection.prepareStatement(sb.toString());
|
||||
statement.setString(create ? 1 : columns.length + 1, value);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the entry.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public abstract void parse() throws SQLException;
|
||||
|
||||
/**
|
||||
* Creates a new row in the database.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public abstract void create() throws SQLException;
|
||||
|
||||
/**
|
||||
* Saves the entry.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public abstract void save() throws SQLException;
|
||||
|
||||
/**
|
||||
* Gets the connection.
|
||||
* @return The connection.
|
||||
*/
|
||||
public abstract Connection getConnection();
|
||||
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package ms.system.mysql
|
||||
|
||||
import ms.system.util.ManagementConstants
|
||||
import ms.system.util.ManagementConstants.DATABASE_HOST_ADDRESS
|
||||
import ms.system.util.ManagementConstants.DATABASE_NAME
|
||||
import ms.system.util.ManagementConstants.DATABASE_PASSWORD
|
||||
import ms.system.util.ManagementConstants.DATABASE_PORT
|
||||
import ms.system.util.ManagementConstants.DATABASE_USERNAME
|
||||
import java.sql.Connection
|
||||
import java.sql.DriverManager
|
||||
import java.sql.SQLException
|
||||
|
||||
/**
|
||||
* Manages the sql connections.
|
||||
* @author Vexia
|
||||
*/
|
||||
object SQLManager {
|
||||
|
||||
/**
|
||||
* IF the sql manager is initialized.
|
||||
*/
|
||||
var isInitialized = false
|
||||
|
||||
/**
|
||||
* Initializes the sql manager.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun init() {
|
||||
isInitialized = true
|
||||
WorldListSQLHandler.clearWorldList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a connection from the pool.
|
||||
* @return The connection.
|
||||
*/
|
||||
@JvmStatic
|
||||
val connection: Connection?
|
||||
get() {
|
||||
try {
|
||||
return DriverManager.getConnection(
|
||||
"jdbc:mysql://$DATABASE_HOST_ADDRESS:$DATABASE_PORT/$DATABASE_NAME?useTimezone=true&serverTimezone=UTC",
|
||||
DATABASE_USERNAME,
|
||||
DATABASE_PASSWORD
|
||||
)
|
||||
} catch (e: SQLException) {
|
||||
println("Error: Mysql error message=" + e.message + ".")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the connection so it's available for usage.
|
||||
* @param connection The connection.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun close(connection: Connection) {
|
||||
try {
|
||||
connection.close()
|
||||
} catch (e: SQLException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an SQL table.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class SQLTable {
|
||||
|
||||
/**
|
||||
* The columns.
|
||||
*/
|
||||
private final SQLColumn[] columns;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLTable} {@code Object}.
|
||||
* @param columns The columns.
|
||||
*/
|
||||
public SQLTable(SQLColumn...columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column for the given name.
|
||||
* @param name The column name.
|
||||
* @return The column.
|
||||
*/
|
||||
public SQLColumn getColumn(String name) {
|
||||
for (SQLColumn column : columns) {
|
||||
if (column.getName().equals(name)) {
|
||||
return column;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the changed columns.
|
||||
* @return The columns.
|
||||
*/
|
||||
public List<SQLColumn> getChanged() {
|
||||
List<SQLColumn> updated = new ArrayList<>(20);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
SQLColumn column = columns[i];
|
||||
if (column.isChanged()) {
|
||||
updated.add(column);
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import ms.world.GameServer;
|
||||
import ms.world.info.WorldInfo;
|
||||
|
||||
/**
|
||||
* Handles the world list SQL database.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class WorldListSQLHandler extends SQLEntryHandler<GameServer> {
|
||||
|
||||
/**
|
||||
* The table for this sql entry.
|
||||
*/
|
||||
private static final String TABLE = "worlds";
|
||||
|
||||
/**
|
||||
* Constructs a new {@code WorldListSQLHandler} {@code Object}.
|
||||
* @param entry The game server entry.
|
||||
*/
|
||||
public WorldListSQLHandler(GameServer entry) {
|
||||
super(entry, TABLE, "world", "" + entry.getInfo().getWorldId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the world list.
|
||||
*/
|
||||
public static void clearWorldList() {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if(connection == null) return;
|
||||
try {
|
||||
PreparedStatement statement = connection.prepareStatement("DELETE FROM " + TABLE);
|
||||
statement.executeUpdate();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse() throws SQLException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() throws SQLException {
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT "+ table + "(world, ip, players, country, member, revision) VALUES('" + value + "', '" + entry.getInfo().getAddress() + "', '" + entry.getPlayerAmount() + "', '" + entry.getInfo().getCountry().getId() + "', '" + (entry.getInfo().isMembers() ? 1 : 0) + "', '" + entry.getInfo().getRevision() + "')");
|
||||
statement.executeUpdate();
|
||||
SQLManager.close(statement.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws SQLException {
|
||||
super.read();
|
||||
if (result == null || !result.next()) {
|
||||
create();
|
||||
return;
|
||||
}
|
||||
int players = entry.getPlayerAmount();
|
||||
WorldInfo info = entry.getInfo();
|
||||
if (!entry.isActive()) {
|
||||
players = -1;
|
||||
}
|
||||
if (players <= 0) {
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE members SET online='0' WHERE lastWorld='" + value + "'");
|
||||
statement.executeUpdate();
|
||||
}
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE " + table + " SET players='" + players + "', ip='" + info.getAddress() + "', country='" + info.getCountry().getId() + "', member='" + (info.isMembers() ? 1 : 0) + "', revision='" + info.getRevision() + "' WHERE world='" + value + "'");
|
||||
statement.executeUpdate();
|
||||
SQLManager.close(statement.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return SQLManager.getConnection();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package ms.system.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
/**
|
||||
* Holds utility methods for reading/writing a byte buffer.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ByteBufferUtils {
|
||||
|
||||
/**
|
||||
* Gets a string from the byte buffer.
|
||||
* @param buffer The byte buffer.
|
||||
* @return The string.
|
||||
*/
|
||||
public static String getString(ByteBuffer buffer) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte b;
|
||||
while ((b = buffer.get()) != 0) {
|
||||
sb.append((char) b);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a string on the byte buffer.
|
||||
* @param s The string to put.
|
||||
* @param buffer The byte buffer.
|
||||
*/
|
||||
public static void putString(String s, ByteBuffer buffer) {
|
||||
buffer.put(s.getBytes(StandardCharsets.UTF_8)).put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string from the byte buffer.
|
||||
* @param s The string.
|
||||
* @param buffer The byte buffer.
|
||||
* @return The string.
|
||||
*/
|
||||
public static ByteBuffer putGJ2String(String s, ByteBuffer buffer) {
|
||||
byte[] packed = new byte[256];
|
||||
int length = packGJString2(0, packed, s);
|
||||
return buffer.put((byte) 0).put(packed, 0, length).put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the XTEA encryption.
|
||||
* @param keys The keys.
|
||||
* @param start The start index.
|
||||
* @param end The end index.
|
||||
* @param buffer The byte buffer.
|
||||
*/
|
||||
public static void decodeXTEA(int[] keys, int start, int end, ByteBuffer buffer) {
|
||||
int l = buffer.position();
|
||||
buffer.position(start);
|
||||
int length = (end - start) / 8;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int firstInt = buffer.getInt();
|
||||
int secondInt = buffer.getInt();
|
||||
int sum = 0xc6ef3720;
|
||||
int delta = 0x9e3779b9;
|
||||
for (int j = 32; j-- > 0;) {
|
||||
secondInt -= keys[(sum & 0x1c84) >>> 11] + sum ^ (firstInt >>> 5 ^ firstInt << 4) + firstInt;
|
||||
sum -= delta;
|
||||
firstInt -= (secondInt >>> 5 ^ secondInt << 4) + secondInt ^ keys[sum & 3] + sum;
|
||||
}
|
||||
buffer.position(buffer.position() - 8);
|
||||
buffer.putInt(firstInt);
|
||||
buffer.putInt(secondInt);
|
||||
}
|
||||
buffer.position(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String to an Integer?
|
||||
*
|
||||
* @param position
|
||||
* The position.
|
||||
* @param buffer
|
||||
* The buffer used.
|
||||
* @param string
|
||||
* The String to convert.
|
||||
* @return The Integer.
|
||||
*/
|
||||
public static int packGJString2(int position, byte[] buffer, String string) {
|
||||
int length = string.length();
|
||||
int offset = position;
|
||||
for (int i = 0; length > i; i++) {
|
||||
int character = string.charAt(i);
|
||||
if (character > 127) {
|
||||
if (character > 2047) {
|
||||
buffer[offset++] = (byte) ((character | 919275) >> 12);
|
||||
buffer[offset++] = (byte) (128 | ((character >> 6) & 63));
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
} else {
|
||||
buffer[offset++] = (byte) ((character | 12309) >> 6);
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
}
|
||||
} else
|
||||
buffer[offset++] = (byte) character;
|
||||
}
|
||||
return offset - position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a tri-byte from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getTriByte(ByteBuffer buffer) {
|
||||
return ((buffer.get() & 0xFF) << 16) + ((buffer.get() & 0xFF) << 8) + (buffer.get() & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a smart from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getSmart(ByteBuffer buffer) {
|
||||
int peek = buffer.get() & 0xFF;
|
||||
if (peek <= Byte.MAX_VALUE) {
|
||||
return peek;
|
||||
}
|
||||
return ((peek << 8) | (buffer.get() & 0xFF)) - 32768;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a smart from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getBigSmart(ByteBuffer buffer) {
|
||||
int value = 0;
|
||||
int current = getSmart(buffer);
|
||||
while (current == 32767) {
|
||||
current = getSmart(buffer);
|
||||
value += 32767;
|
||||
}
|
||||
value += current;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ByteBufferUtils} {@code Object}.
|
||||
*/
|
||||
private ByteBufferUtils() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package ms.system.util;
|
||||
|
||||
/**
|
||||
* Represents a command.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public abstract class Command {
|
||||
|
||||
/**
|
||||
* The command name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The command info.
|
||||
*/
|
||||
private final String info;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Command} {@code Object}.
|
||||
* @param name The command name.
|
||||
* @param info The command info.
|
||||
*/
|
||||
public Command(String name, String info) {
|
||||
this.name = name;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command.
|
||||
* @param args The arguments.
|
||||
*/
|
||||
public abstract void run(String...args);
|
||||
|
||||
/**
|
||||
* Gets the name value.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the info value.
|
||||
* @return The info.
|
||||
*/
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,815 +0,0 @@
|
|||
package ms.system.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* Represents the class of simple encryption functions.
|
||||
* @author Unknown
|
||||
*/
|
||||
public class EncryptionManager {
|
||||
|
||||
// Define the BCrypt workload to use when generating password hashes. 10-31 is a valid value.
|
||||
private static int workload = 12;
|
||||
|
||||
/**
|
||||
* Singleton instance.
|
||||
*/
|
||||
private static final EncryptionManager INSTANCE = new EncryptionManager();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code EncryptionManager} {@code Object}.
|
||||
*/
|
||||
private EncryptionManager() {
|
||||
//empty.
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to generate a string representing an account password
|
||||
* suitable for storing in a database. It will be an OpenBSD-style crypt(3) formatted
|
||||
* hash string of length=60
|
||||
* The bcrypt workload is specified in the above static variable, a value from 10 to 31.
|
||||
* A workload of 12 is a very reasonable safe default as of 2013.
|
||||
* This automatically handles secure 128-bit salt generation and storage within the hash.
|
||||
* @param password_plaintext The account's plaintext password as provided during account creation,
|
||||
* or when changing an account's password.
|
||||
* @return String - a string of length 60 that is the bcrypt hashed password in crypt(3) format.
|
||||
*/
|
||||
public String hashPassword(String password_plaintext) {
|
||||
String salt = BCrypt.gensalt(workload);
|
||||
String hashed_password = BCrypt.hashpw(password_plaintext, salt);
|
||||
return(hashed_password);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to verify a computed hash from a plaintext (e.g. during a login
|
||||
* request) with that of a stored hash from a database. The password hash from the database
|
||||
* must be passed as the second variable.
|
||||
* @param password_plaintext The account's plaintext password, as provided during a login request
|
||||
* @param stored_hash The account's stored password hash, retrieved from the authorization database
|
||||
* @return boolean - true if the password matches the password of the stored hash, false otherwise
|
||||
*/
|
||||
public boolean checkPassword(String password_plaintext, String stored_hash) {
|
||||
boolean password_verified = false;
|
||||
if(null == stored_hash || !stored_hash.startsWith("$2a$"))
|
||||
throw new java.lang.IllegalArgumentException("Invalid hash provided for comparison");
|
||||
password_verified = BCrypt.checkpw(password_plaintext, stored_hash);
|
||||
return(password_verified);
|
||||
}
|
||||
|
||||
// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
/**
|
||||
* Gets the instance value.
|
||||
* @return The instance.
|
||||
*/
|
||||
public static EncryptionManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* BCrypt implements OpenBSD-style Blowfish password hashing using
|
||||
* the scheme described in "A Future-Adaptable Password Scheme" by
|
||||
* Niels Provos and David Mazieres.
|
||||
* <p>
|
||||
* This password hashing system tries to thwart off-line password
|
||||
* cracking using a computationally-intensive hashing algorithm,
|
||||
* based on Bruce Schneier's Blowfish cipher. The work factor of
|
||||
* the algorithm is parameterised, so it can be increased as
|
||||
* computers get faster.
|
||||
* <p>
|
||||
* Usage is really simple. To hash a password for the first time,
|
||||
* call the hashpw method with a random salt, like this:
|
||||
* <p>
|
||||
* <code>
|
||||
* String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt()); <br />
|
||||
* </code>
|
||||
* <p>
|
||||
* To check whether a plaintext password matches one that has been
|
||||
* hashed previously, use the checkpw method:
|
||||
* <p>
|
||||
* <code>
|
||||
* if (BCrypt.checkpw(candidate_password, stored_hash))<br />
|
||||
* System.out.println("It matches");<br />
|
||||
* else<br />
|
||||
* System.out.println("It does not match");<br />
|
||||
* </code>
|
||||
* <p>
|
||||
* The gensalt() method takes an optional parameter (log_rounds)
|
||||
* that determines the computational complexity of the hashing:
|
||||
* <p>
|
||||
* <code>
|
||||
* String strong_salt = BCrypt.gensalt(10)<br />
|
||||
* String stronger_salt = BCrypt.gensalt(12)<br />
|
||||
* </code>
|
||||
* <p>
|
||||
* The amount of work increases exponentially (2**log_rounds), so
|
||||
* each increment is twice as much work. The default log_rounds is
|
||||
* 10, and the valid range is 4 to 31.
|
||||
*
|
||||
* @author Damien Miller
|
||||
* @version 0.2
|
||||
*/
|
||||
public static class BCrypt {
|
||||
// BCrypt parameters
|
||||
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
||||
private static final int BCRYPT_SALT_LEN = 16;
|
||||
|
||||
// Blowfish parameters
|
||||
private static final int BLOWFISH_NUM_ROUNDS = 16;
|
||||
|
||||
// Initial contents of key schedule
|
||||
private static final int P_orig[] = {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
};
|
||||
private static final int S_orig[] = {
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
};
|
||||
|
||||
// bcrypt IV: "OrpheanBeholderScryDoubt"
|
||||
static private final int bf_crypt_ciphertext[] = {
|
||||
0x4f727068, 0x65616e42, 0x65686f6c,
|
||||
0x64657253, 0x63727944, 0x6f756274
|
||||
};
|
||||
|
||||
// Table for Base64 encoding
|
||||
static private final char base64_code[] = {
|
||||
'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9'
|
||||
};
|
||||
|
||||
// Table for Base64 decoding
|
||||
static private final byte index_64[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
|
||||
-1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
-1, -1, -1, -1, -1, -1, 28, 29, 30,
|
||||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
// Expanded Blowfish key
|
||||
private int P[];
|
||||
private int S[];
|
||||
|
||||
/**
|
||||
* Encode a byte array using bcrypt's slightly-modified base64
|
||||
* encoding scheme. Note that this is *not* compatible with
|
||||
* the standard MIME-base64 encoding.
|
||||
*
|
||||
* @param d the byte array to encode
|
||||
* @param len the number of bytes to encode
|
||||
* @return base64-encoded string
|
||||
* @exception IllegalArgumentException if the length is invalid
|
||||
*/
|
||||
private static String encode_base64(byte d[], int len)
|
||||
throws IllegalArgumentException {
|
||||
int off = 0;
|
||||
StringBuffer rs = new StringBuffer();
|
||||
int c1, c2;
|
||||
|
||||
if (len <= 0 || len > d.length)
|
||||
throw new IllegalArgumentException ("Invalid len");
|
||||
|
||||
while (off < len) {
|
||||
c1 = d[off++] & 0xff;
|
||||
rs.append(base64_code[(c1 >> 2) & 0x3f]);
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (off >= len) {
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
break;
|
||||
}
|
||||
c2 = d[off++] & 0xff;
|
||||
c1 |= (c2 >> 4) & 0x0f;
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (off >= len) {
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
break;
|
||||
}
|
||||
c2 = d[off++] & 0xff;
|
||||
c1 |= (c2 >> 6) & 0x03;
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
rs.append(base64_code[c2 & 0x3f]);
|
||||
}
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the 3 bits base64-encoded by the specified character,
|
||||
* range-checking againt conversion table
|
||||
* @param x the base64-encoded value
|
||||
* @return the decoded value of x
|
||||
*/
|
||||
private static byte char64(char x) {
|
||||
if ((int)x > index_64.length)
|
||||
return -1;
|
||||
return index_64[(int)x];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a string encoded using bcrypt's base64 scheme to a
|
||||
* byte array. Note that this is *not* compatible with
|
||||
* the standard MIME-base64 encoding.
|
||||
* @param s the string to decode
|
||||
* @param maxolen the maximum number of bytes to decode
|
||||
* @return an array containing the decoded bytes
|
||||
* @throws IllegalArgumentException if maxolen is invalid
|
||||
*/
|
||||
private static byte[] decode_base64(String s, int maxolen)
|
||||
throws IllegalArgumentException {
|
||||
StringBuffer rs = new StringBuffer();
|
||||
int off = 0, slen = s.length(), olen = 0;
|
||||
byte ret[];
|
||||
byte c1, c2, c3, c4, o;
|
||||
|
||||
if (maxolen <= 0)
|
||||
throw new IllegalArgumentException ("Invalid maxolen");
|
||||
|
||||
while (off < slen - 1 && olen < maxolen) {
|
||||
c1 = char64(s.charAt(off++));
|
||||
c2 = char64(s.charAt(off++));
|
||||
if (c1 == -1 || c2 == -1)
|
||||
break;
|
||||
o = (byte)(c1 << 2);
|
||||
o |= (c2 & 0x30) >> 4;
|
||||
rs.append((char)o);
|
||||
if (++olen >= maxolen || off >= slen)
|
||||
break;
|
||||
c3 = char64(s.charAt(off++));
|
||||
if (c3 == -1)
|
||||
break;
|
||||
o = (byte)((c2 & 0x0f) << 4);
|
||||
o |= (c3 & 0x3c) >> 2;
|
||||
rs.append((char)o);
|
||||
if (++olen >= maxolen || off >= slen)
|
||||
break;
|
||||
c4 = char64(s.charAt(off++));
|
||||
o = (byte)((c3 & 0x03) << 6);
|
||||
o |= c4;
|
||||
rs.append((char)o);
|
||||
++olen;
|
||||
}
|
||||
|
||||
ret = new byte[olen];
|
||||
for (off = 0; off < olen; off++)
|
||||
ret[off] = (byte)rs.charAt(off);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blowfish encipher a single 64-bit block encoded as
|
||||
* two 32-bit halves
|
||||
* @param lr an array containing the two 32-bit half blocks
|
||||
* @param off the position in the array of the blocks
|
||||
*/
|
||||
private final void encipher(int lr[], int off) {
|
||||
int i, n, l = lr[off], r = lr[off + 1];
|
||||
|
||||
l ^= P[0];
|
||||
for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) {
|
||||
// Feistel substitution on left word
|
||||
n = S[(l >> 24) & 0xff];
|
||||
n += S[0x100 | ((l >> 16) & 0xff)];
|
||||
n ^= S[0x200 | ((l >> 8) & 0xff)];
|
||||
n += S[0x300 | (l & 0xff)];
|
||||
r ^= n ^ P[++i];
|
||||
|
||||
// Feistel substitution on right word
|
||||
n = S[(r >> 24) & 0xff];
|
||||
n += S[0x100 | ((r >> 16) & 0xff)];
|
||||
n ^= S[0x200 | ((r >> 8) & 0xff)];
|
||||
n += S[0x300 | (r & 0xff)];
|
||||
l ^= n ^ P[++i];
|
||||
}
|
||||
lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
|
||||
lr[off + 1] = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycically extract a word of key material
|
||||
* @param data the string to extract the data from
|
||||
* @param offp a "pointer" (as a one-entry array) to the
|
||||
* current offset into data
|
||||
* @return the next word of material from data
|
||||
*/
|
||||
private static int streamtoword(byte data[], int offp[]) {
|
||||
int i;
|
||||
int word = 0;
|
||||
int off = offp[0];
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
word = (word << 8) | (data[off] & 0xff);
|
||||
off = (off + 1) % data.length;
|
||||
}
|
||||
|
||||
offp[0] = off;
|
||||
return word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the Blowfish key schedule
|
||||
*/
|
||||
private void init_key() {
|
||||
P = (int[])P_orig.clone();
|
||||
S = (int[])S_orig.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Key the Blowfish cipher
|
||||
* @param key an array containing the key
|
||||
*/
|
||||
private void key(byte key[]) {
|
||||
int i;
|
||||
int koffp[] = { 0 };
|
||||
int lr[] = { 0, 0 };
|
||||
int plen = P.length, slen = S.length;
|
||||
|
||||
for (i = 0; i < plen; i++)
|
||||
P[i] = P[i] ^ streamtoword(key, koffp);
|
||||
|
||||
for (i = 0; i < plen; i += 2) {
|
||||
encipher(lr, 0);
|
||||
P[i] = lr[0];
|
||||
P[i + 1] = lr[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < slen; i += 2) {
|
||||
encipher(lr, 0);
|
||||
S[i] = lr[0];
|
||||
S[i + 1] = lr[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the "enhanced key schedule" step described by
|
||||
* Provos and Mazieres in "A Future-Adaptable Password Scheme"
|
||||
* http://www.openbsd.org/papers/bcrypt-paper.ps
|
||||
* @param data salt information
|
||||
* @param key password information
|
||||
*/
|
||||
private void ekskey(byte data[], byte key[]) {
|
||||
int i;
|
||||
int koffp[] = { 0 }, doffp[] = { 0 };
|
||||
int lr[] = { 0, 0 };
|
||||
int plen = P.length, slen = S.length;
|
||||
|
||||
for (i = 0; i < plen; i++)
|
||||
P[i] = P[i] ^ streamtoword(key, koffp);
|
||||
|
||||
for (i = 0; i < plen; i += 2) {
|
||||
lr[0] ^= streamtoword(data, doffp);
|
||||
lr[1] ^= streamtoword(data, doffp);
|
||||
encipher(lr, 0);
|
||||
P[i] = lr[0];
|
||||
P[i + 1] = lr[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < slen; i += 2) {
|
||||
lr[0] ^= streamtoword(data, doffp);
|
||||
lr[1] ^= streamtoword(data, doffp);
|
||||
encipher(lr, 0);
|
||||
S[i] = lr[0];
|
||||
S[i + 1] = lr[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the central password hashing step in the
|
||||
* bcrypt scheme
|
||||
* @param password the password to hash
|
||||
* @param salt the binary salt to hash with the password
|
||||
* @param log_rounds the binary logarithm of the number
|
||||
* of rounds of hashing to apply
|
||||
* @return an array containing the binary hashed password
|
||||
*/
|
||||
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) {
|
||||
int rounds, i, j;
|
||||
int cdata[] = (int[])bf_crypt_ciphertext.clone();
|
||||
int clen = cdata.length;
|
||||
byte ret[];
|
||||
|
||||
if (log_rounds < 4 || log_rounds > 31)
|
||||
throw new IllegalArgumentException ("Bad number of rounds");
|
||||
rounds = 1 << log_rounds;
|
||||
if (salt.length != BCRYPT_SALT_LEN)
|
||||
throw new IllegalArgumentException ("Bad salt length");
|
||||
|
||||
init_key();
|
||||
ekskey(salt, password);
|
||||
for (i = 0; i < rounds; i++) {
|
||||
key(password);
|
||||
key(salt);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
for (j = 0; j < (clen >> 1); j++)
|
||||
encipher(cdata, j << 1);
|
||||
}
|
||||
|
||||
ret = new byte[clen * 4];
|
||||
for (i = 0, j = 0; i < clen; i++) {
|
||||
ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
|
||||
ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
|
||||
ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
|
||||
ret[j++] = (byte)(cdata[i] & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a password using the OpenBSD bcrypt scheme
|
||||
* @param password the password to hash
|
||||
* @param salt the salt to hash with (perhaps generated
|
||||
* using BCrypt.gensalt)
|
||||
* @return the hashed password
|
||||
*/
|
||||
public static String hashpw(String password, String salt) {
|
||||
BCrypt B;
|
||||
String real_salt;
|
||||
byte passwordb[], saltb[], hashed[];
|
||||
char minor = (char)0;
|
||||
int rounds, off = 0;
|
||||
StringBuffer rs = new StringBuffer();
|
||||
|
||||
if (salt.charAt(0) != '$' || salt.charAt(1) != '2')
|
||||
throw new IllegalArgumentException ("Invalid salt version");
|
||||
if (salt.charAt(2) == '$')
|
||||
off = 3;
|
||||
else {
|
||||
minor = salt.charAt(2);
|
||||
if (minor != 'a' || salt.charAt(3) != '$')
|
||||
throw new IllegalArgumentException ("Invalid salt revision");
|
||||
off = 4;
|
||||
}
|
||||
|
||||
// Extract number of rounds
|
||||
if (salt.charAt(off + 2) > '$')
|
||||
throw new IllegalArgumentException ("Missing salt rounds");
|
||||
rounds = Integer.parseInt(salt.substring(off, off + 2));
|
||||
|
||||
real_salt = salt.substring(off + 3, off + 25);
|
||||
try {
|
||||
passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new AssertionError("UTF-8 is not supported");
|
||||
}
|
||||
|
||||
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
|
||||
|
||||
B = new BCrypt();
|
||||
hashed = B.crypt_raw(passwordb, saltb, rounds);
|
||||
|
||||
rs.append("$2");
|
||||
if (minor >= 'a')
|
||||
rs.append(minor);
|
||||
rs.append("$");
|
||||
if (rounds < 10)
|
||||
rs.append("0");
|
||||
rs.append(Integer.toString(rounds));
|
||||
rs.append("$");
|
||||
rs.append(encode_base64(saltb, saltb.length));
|
||||
rs.append(encode_base64(hashed,
|
||||
bf_crypt_ciphertext.length * 4 - 1));
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method
|
||||
* @param log_rounds the log2 of the number of rounds of
|
||||
* hashing to apply - the work factor therefore increases as
|
||||
* 2**log_rounds.
|
||||
* @param random an instance of SecureRandom to use
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt(int log_rounds, SecureRandom random) {
|
||||
StringBuffer rs = new StringBuffer();
|
||||
byte rnd[] = new byte[BCRYPT_SALT_LEN];
|
||||
|
||||
random.nextBytes(rnd);
|
||||
|
||||
rs.append("$2a$");
|
||||
if (log_rounds < 10)
|
||||
rs.append("0");
|
||||
rs.append(Integer.toString(log_rounds));
|
||||
rs.append("$");
|
||||
rs.append(encode_base64(rnd, rnd.length));
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method
|
||||
* @param log_rounds the log2 of the number of rounds of
|
||||
* hashing to apply - the work factor therefore increases as
|
||||
* 2**log_rounds.
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt(int log_rounds) {
|
||||
return gensalt(log_rounds, new SecureRandom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method,
|
||||
* selecting a reasonable default for the number of hashing
|
||||
* rounds to apply
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt() {
|
||||
return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a plaintext password matches a previously hashed
|
||||
* one
|
||||
* @param plaintext the plaintext password to verify
|
||||
* @param hashed the previously-hashed password
|
||||
* @return true if the passwords match, false otherwise
|
||||
*/
|
||||
public static boolean checkpw(String plaintext, String hashed) {
|
||||
return (hashed.compareTo(hashpw(plaintext, hashed)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
package ms.system.util
|
||||
|
||||
import org.json.simple.JSONObject
|
||||
import org.json.simple.parser.JSONParser
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* Class for parsing the server config, I.E default.conf
|
||||
* @param path the path to the JSON file to parse.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class ManagementConfigParser(path: String) {
|
||||
val pathTo = parsePath(path)
|
||||
val confFile = File(pathTo)
|
||||
val parser = JSONParser()
|
||||
var reader: FileReader? = null
|
||||
var data: JSONObject? = null
|
||||
|
||||
init {
|
||||
if(!confFile.canonicalFile.exists()){
|
||||
println("Could not find ${confFile.canonicalFile} - Double check your working directory!")
|
||||
exitProcess(0)
|
||||
} else if(!pathTo.contains(".json")) {
|
||||
println("Config file MUST be a JSON file!!")
|
||||
println("(Got $pathTo)")
|
||||
} else {
|
||||
reader = FileReader(pathTo)
|
||||
data = parser.parse(reader) as JSONObject
|
||||
parseDatabaseInformation()
|
||||
parseWorldTechnicalSettings()
|
||||
ManagementConstants.SECRET_KEY = data!!["secret_key"].toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseDatabaseInformation(){
|
||||
data ?: return
|
||||
val dbData = data!!["DatabaseInformation"] as JSONObject
|
||||
ManagementConstants.parseDBProp(dbData)
|
||||
}
|
||||
|
||||
private fun parseWorldTechnicalSettings(){
|
||||
data ?: return
|
||||
val wtiData = data!!["WorldTechnicalInformation"] as JSONObject
|
||||
ManagementConstants.parseWTIProp(wtiData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a path string
|
||||
* @author Ceikry
|
||||
* @param pathString The string to parse
|
||||
* @return a String with the proper file separators for the current OS.
|
||||
*/
|
||||
fun parsePath(pathString: String): String {
|
||||
var pathTokens: List<String>? = null
|
||||
if(pathString.contains("/"))
|
||||
pathTokens = pathString.split("/")
|
||||
else if(pathString.contains("\\"))
|
||||
pathTokens = pathString.split("\\")
|
||||
|
||||
pathTokens ?: return pathString //return the initial pathString if path does not contain file separators.
|
||||
var pathProduct = ""
|
||||
for(token in pathTokens){
|
||||
if(token != "")
|
||||
pathProduct += "$token${File.separator}"
|
||||
}
|
||||
|
||||
return pathProduct
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
package ms.system.util
|
||||
|
||||
import org.json.simple.JSONObject
|
||||
|
||||
object ManagementConstants {
|
||||
|
||||
//MySQL main database name
|
||||
var DATABASE_NAME: String = "global"
|
||||
|
||||
//MySQL database username
|
||||
var DATABASE_USERNAME: String = "root"
|
||||
|
||||
//MySQL database password
|
||||
var DATABASE_PASSWORD: String = ""
|
||||
|
||||
//MySQL host
|
||||
var DATABASE_HOST_ADDRESS: String = "127.0.0.1"
|
||||
|
||||
//MySQL port
|
||||
var DATABASE_PORT: Int = 3306
|
||||
|
||||
//Max amount of worlds supported on the world list
|
||||
var MAX_WORLD_AMOUNT: Int = 10
|
||||
|
||||
//User world hop delay in seconds
|
||||
var WORLD_HOP_DELAY: Long = 20_000L
|
||||
|
||||
@JvmStatic
|
||||
var SECRET_KEY: String = ""
|
||||
|
||||
fun parseDBProp(data: JSONObject) {
|
||||
DATABASE_NAME = data["database_name"].toString()
|
||||
DATABASE_USERNAME = data["database_username"].toString()
|
||||
DATABASE_PASSWORD = data["database_password"].toString()
|
||||
DATABASE_HOST_ADDRESS = data["database_host"].toString()
|
||||
DATABASE_PORT = data["database_port"].toString().toInt()
|
||||
}
|
||||
|
||||
fun parseWTIProp(data: JSONObject) {
|
||||
MAX_WORLD_AMOUNT = data["world_limit"].toString().toInt()
|
||||
WORLD_HOP_DELAY = data["worldhop_delay"].toString().toLong()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package ms.system.util;
|
||||
|
||||
/**
|
||||
* Handles generating a player database.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PlayerDatabaseGen {
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* @param args The arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,640 +0,0 @@
|
|||
package ms.system.util;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import ms.net.packet.IoBuffer;
|
||||
|
||||
/**
|
||||
* The string utils.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class StringUtils {
|
||||
|
||||
/**
|
||||
* The valid characters to be used in names/messages/...
|
||||
*/
|
||||
private static final char[] VALID_CHARS = {
|
||||
'_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
|
||||
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
||||
};
|
||||
/**
|
||||
* The an int array241.
|
||||
*/
|
||||
private final static int[] anIntArray241 = { 215, 203, 83, 158, 104, 101, 93, 84,
|
||||
107, 103, 109, 95, 94, 98, 89, 86, 70, 41, 32, 27, 24, 23, -1, -2,
|
||||
26, -3, -4, 31, 30, -5, -6, -7, 37, 38, 36, -8, -9, -10, 40, -11,
|
||||
-12, 55, 48, 46, 47, -13, -14, -15, 52, 51, -16, -17, 54, -18, -19,
|
||||
63, 60, 59, -20, -21, 62, -22, -23, 67, 66, -24, -25, 69, -26, -27,
|
||||
199, 132, 80, 77, 76, -28, -29, 79, -30, -31, 87, 85, -32, -33,
|
||||
-34, -35, -36, 197, -37, 91, -38, 134, -39, -40, -41, 97, -42, -43,
|
||||
133, 106, -44, 117, -45, -46, 139, -47, -48, 110, -49, -50, 114,
|
||||
113, -51, -52, 116, -53, -54, 135, 138, 136, 129, 125, 124, -55,
|
||||
-56, 130, 128, -57, -58, -59, 183, -60, -61, -62, -63, -64, 148,
|
||||
-65, -66, 153, 149, 145, 144, -67, -68, 147, -69, -70, -71, 152,
|
||||
154, -72, -73, -74, 157, 171, -75, -76, 207, 184, 174, 167, 166,
|
||||
165, -77, -78, -79, 172, 170, -80, -81, -82, 178, -83, 177, 182,
|
||||
-84, -85, 187, 181, -86, -87, -88, -89, 206, 221, -90, 189, -91,
|
||||
198, 254, 262, 195, 196, -92, -93, -94, -95, -96, 252, 255, 250,
|
||||
-97, 211, 209, -98, -99, 212, -100, 213, -101, -102, -103, 224,
|
||||
-104, 232, 227, 220, 226, -105, -106, 246, 236, -107, 243, -108,
|
||||
-109, 231, 237, 235, -110, -111, 239, 238, -112, -113, -114, -115,
|
||||
-116, 241, -117, 244, -118, -119, 248, -120, 249, -121, -122, -123,
|
||||
253, -124, -125, -126, -127, 259, 258, -128, -129, 261, -130, -131,
|
||||
390, 327, 296, 281, 274, 271, 270, -132, -133, 273, -134, -135,
|
||||
278, 277, -136, -137, 280, -138, -139, 289, 286, 285, -140, -141,
|
||||
288, -142, -143, 293, 292, -144, -145, 295, -146, -147, 312, 305,
|
||||
302, 301, -148, -149, 304, -150, -151, 309, 308, -152, -153, 311,
|
||||
-154, -155, 320, 317, 316, -156, -157, 319, -158, -159, 324, 323,
|
||||
-160, -161, 326, -162, -163, 359, 344, 337, 334, 333, -164, -165,
|
||||
336, -166, -167, 341, 340, -168, -169, 343, -170, -171, 352, 349,
|
||||
348, -172, -173, 351, -174, -175, 356, 355, -176, -177, 358, -178,
|
||||
-179, 375, 368, 365, 364, -180, -181, 367, -182, -183, 372, 371,
|
||||
-184, -185, 374, -186, -187, 383, 380, 379, -188, -189, 382, -190,
|
||||
-191, 387, 386, -192, -193, 389, -194, -195, 454, 423, 408, 401,
|
||||
398, 397, -196, -197, 400, -198, -199, 405, 404, -200, -201, 407,
|
||||
-202, -203, 416, 413, 412, -204, -205, 415, -206, -207, 420, 419,
|
||||
-208, -209, 422, -210, -211, 439, 432, 429, 428, -212, -213, 431,
|
||||
-214, -215, 436, 435, -216, -217, 438, -218, -219, 447, 444, 443,
|
||||
-220, -221, 446, -222, -223, 451, 450, -224, -225, 453, -226, -227,
|
||||
486, 471, 464, 461, 460, -228, -229, 463, -230, -231, 468, 467,
|
||||
-232, -233, 470, -234, -235, 479, 476, 475, -236, -237, 478, -238,
|
||||
-239, 483, 482, -240, -241, 485, -242, -243, 499, 495, 492, 491,
|
||||
-244, -245, 494, -246, -247, 497, -248, 502, -249, 506, 503, -250,
|
||||
-251, 505, -252, -253, 508, -254, 510, -255, -256, 0 };
|
||||
|
||||
/**
|
||||
* Constructs a new {@code StringUtils.java} {@code Object}.
|
||||
*/
|
||||
public StringUtils() {
|
||||
/**
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
/**
|
||||
* Method used to get the formatted number as a string from the integer inputed.
|
||||
* @param amount the ammount.
|
||||
* @return the string value.
|
||||
*/
|
||||
public static String getFormattedNumber(int amount) {
|
||||
return new DecimalFormat("#,###,##0").format(amount).toString();
|
||||
}
|
||||
/**
|
||||
* Checks if the string contains an invalid character.
|
||||
* @param nameThe string.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean containsInvalidCharacter(String name) {
|
||||
for (char c : name.toCharArray()) {
|
||||
boolean pass = false;
|
||||
for (char vc : VALID_CHARS)
|
||||
if (vc == c) {
|
||||
pass = true;
|
||||
break;
|
||||
}
|
||||
if (!pass)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* If a word starts with a e i o u h for grammar = a + n.
|
||||
* @param word The word.
|
||||
* @return If the a should have +n {@code true}.
|
||||
*/
|
||||
public static boolean isPlusN(String word) {
|
||||
if (word == null)
|
||||
return false;
|
||||
String s = word.toLowerCase();
|
||||
return s.charAt(0) == 'a' || s.charAt(0) == 'e' || s.charAt(0) == 'i'
|
||||
|| s.charAt(0) == 'o' || s.charAt(0) == 'u'
|
||||
|| (s.charAt(0) == 'h' && s.length() > 1 && s.charAt(1) != 'e');
|
||||
}
|
||||
/**
|
||||
* Method used to get the player name as a long.
|
||||
* @param s the string.
|
||||
* @return the long.
|
||||
*/
|
||||
public static long getPlayerNameLong(String s) {
|
||||
long l = 0L;
|
||||
for(int i = 0; i < s.length() && i < 12; i++) {
|
||||
char c = s.charAt(i);
|
||||
l *= 37L;
|
||||
if(c >= 'A' && c <= 'Z') l += (1 + c) - 65;
|
||||
else if(c >= 'a' && c <= 'z') l += (1 + c) - 97;
|
||||
else if(c >= '0' && c <= '9') l += (27 + c) - 48;
|
||||
}
|
||||
while(l % 37L == 0L && l != 0L) l /= 37L;
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to convert the string to a long.
|
||||
* @param s the string.
|
||||
* @return the long.
|
||||
*/
|
||||
public static long convertStringToLong(String s) {
|
||||
if (s.length() > 20) {
|
||||
throw new IllegalArgumentException("String is too long: " + s);
|
||||
}
|
||||
long out = 0L;
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
long m = reducedMapping(s.codePointAt(i));
|
||||
if (m == -1) {
|
||||
throw new IllegalArgumentException("Unmapped Character in String: " + s);
|
||||
}
|
||||
m <<= ((9 - i) * 6) + 4;
|
||||
out |= m;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the string as display name.
|
||||
* @param name The string to format.
|
||||
* @return The formatted name.
|
||||
*/
|
||||
public static String formatDisplayName(String name) {
|
||||
name = name.replaceAll("_", " ");
|
||||
name = name.toLowerCase();
|
||||
StringBuilder newName = new StringBuilder();
|
||||
boolean wasSpace = true;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
if (wasSpace) {
|
||||
newName.append(("" + name.charAt(i)).toUpperCase());
|
||||
wasSpace = false;
|
||||
} else {
|
||||
newName.append(name.charAt(i));
|
||||
}
|
||||
if (name.charAt(i) == ' ') {
|
||||
wasSpace = true;
|
||||
}
|
||||
}
|
||||
return newName.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the byte for the character.
|
||||
* @param c The character.
|
||||
* @return The byte.
|
||||
*/
|
||||
private static final byte getByte(char c) {
|
||||
byte charByte;
|
||||
if (c > 0 && c < '\200' || c >= '\240' && c <= '\377')
|
||||
charByte = (byte) c;
|
||||
else if (c != '\u20AC') {
|
||||
if (c != '\u201A') {
|
||||
if (c != '\u0192') {
|
||||
if (c == '\u201E')
|
||||
charByte = -124;
|
||||
else if (c != '\u2026') {
|
||||
if (c != '\u2020') {
|
||||
if (c == '\u2021')
|
||||
charByte = -121;
|
||||
else if (c == '\u02C6')
|
||||
charByte = -120;
|
||||
else if (c == '\u2030')
|
||||
charByte = -119;
|
||||
else if (c == '\u0160')
|
||||
charByte = -118;
|
||||
else if (c == '\u2039')
|
||||
charByte = -117;
|
||||
else if (c == '\u0152')
|
||||
charByte = -116;
|
||||
else if (c != '\u017D') {
|
||||
if (c == '\u2018')
|
||||
charByte = -111;
|
||||
else if (c != '\u2019') {
|
||||
if (c != '\u201C') {
|
||||
if (c == '\u201D')
|
||||
charByte = -108;
|
||||
else if (c != '\u2022') {
|
||||
if (c == '\u2013')
|
||||
charByte = -106;
|
||||
else if (c == '\u2014')
|
||||
charByte = -105;
|
||||
else if (c == '\u02DC')
|
||||
charByte = -104;
|
||||
else if (c == '\u2122')
|
||||
charByte = -103;
|
||||
else if (c != '\u0161') {
|
||||
if (c == '\u203A')
|
||||
charByte = -101;
|
||||
else if (c != '\u0153') {
|
||||
if (c == '\u017E')
|
||||
charByte = -98;
|
||||
else if (c != '\u0178')
|
||||
charByte = 63;
|
||||
else
|
||||
charByte = -97;
|
||||
} else
|
||||
charByte = -100;
|
||||
} else
|
||||
charByte = -102;
|
||||
} else
|
||||
charByte = -107;
|
||||
} else
|
||||
charByte = -109;
|
||||
} else
|
||||
charByte = -110;
|
||||
} else
|
||||
charByte = -114;
|
||||
} else
|
||||
charByte = -122;
|
||||
} else
|
||||
charByte = -123;
|
||||
} else
|
||||
charByte = -125;
|
||||
} else
|
||||
charByte = -126;
|
||||
} else
|
||||
charByte = -128;
|
||||
return charByte;
|
||||
}
|
||||
/**
|
||||
* Gets the double value of this string
|
||||
* @param s The string.
|
||||
* @return The double value.
|
||||
*/
|
||||
public static double getDouble(String s) {
|
||||
s = s.replaceAll(", ", "").replaceAll(",", "");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char c;
|
||||
boolean foundStart = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
c = s.charAt(i);
|
||||
if (Character.isDigit(c) || c == '-' || c == '.') {
|
||||
sb.append(c);
|
||||
foundStart = true;
|
||||
} else if (foundStart)
|
||||
break;
|
||||
}
|
||||
try {
|
||||
double amount = Double.parseDouble(sb.toString());
|
||||
return amount;
|
||||
} catch (NumberFormatException e) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the hash for the string.
|
||||
* @param str The string.
|
||||
* @return The hash.
|
||||
*/
|
||||
public static final int getNameHash(String str) {
|
||||
str = str.toLowerCase();
|
||||
int hash = 0;
|
||||
for (int index = 0; index < str.length(); index++)
|
||||
hash = getByte(str.charAt(index)) + ((hash << 5) - hash);
|
||||
return hash;
|
||||
}
|
||||
/**
|
||||
* Gets the string value of this string (all html/... removed).
|
||||
* @param s The string.
|
||||
* @return The string value.
|
||||
*/
|
||||
public static String getString(String s) {
|
||||
return s.replaceAll("\\<.*?>", "").replaceAll(" ", "")
|
||||
.replaceAll("Discontinued Item:", "");
|
||||
}
|
||||
/**
|
||||
* Characters used to convert a String to a Long.
|
||||
*/
|
||||
public static char[] validChars = {
|
||||
'_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
|
||||
'3', '4', '5', '6', '7', '8', '9'
|
||||
};
|
||||
private final static int[] anIntArray233 = {
|
||||
0, 1024, 2048, 3072, 4096, 5120,
|
||||
6144, 8192, 9216, 12288, 10240, 11264, 16384, 18432, 17408, 20480,
|
||||
21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, 29696,
|
||||
30720, 31744, 32768, 33792, 34816, 35840, 36864, 536870912,
|
||||
16777216, 37888, 65536, 38912, 131072, 196608, 33554432, 524288,
|
||||
1048576, 1572864, 262144, 67108864, 4194304, 134217728, 327680,
|
||||
8388608, 2097152, 12582912, 13631488, 14680064, 15728640,
|
||||
100663296, 101187584, 101711872, 101974016, 102760448, 102236160,
|
||||
40960, 393216, 229376, 117440512, 104857600, 109051904, 201326592,
|
||||
205520896, 209715200, 213909504, 106954752, 218103808, 226492416,
|
||||
234881024, 222298112, 224395264, 268435456, 272629760, 276824064,
|
||||
285212672, 289406976, 223346688, 293601280, 301989888, 318767104,
|
||||
297795584, 298844160, 310378496, 102498304, 335544320, 299892736,
|
||||
300941312, 301006848, 300974080, 39936, 301465600, 49152,
|
||||
1073741824, 369098752, 402653184, 1342177280, 1610612736,
|
||||
469762048, 1476395008, -2147483648, -1879048192, 352321536,
|
||||
1543503872, -2013265920, -1610612736, -1342177280, -1073741824,
|
||||
-1543503872, 356515840, -1476395008, -805306368, -536870912,
|
||||
-268435456, 1577058304, -134217728, 360710144, -67108864,
|
||||
364904448, 51200, 57344, 52224, 301203456, 53248, 54272, 55296,
|
||||
56320, 301072384, 301073408, 301074432, 301075456, 301076480,
|
||||
301077504, 301078528, 301079552, 301080576, 301081600, 301082624,
|
||||
301083648, 301084672, 301085696, 301086720, 301087744, 301088768,
|
||||
301089792, 301090816, 301091840, 301092864, 301093888, 301094912,
|
||||
301095936, 301096960, 301097984, 301099008, 301100032, 301101056,
|
||||
301102080, 301103104, 301104128, 301105152, 301106176, 301107200,
|
||||
301108224, 301109248, 301110272, 301111296, 301112320, 301113344,
|
||||
301114368, 301115392, 301116416, 301117440, 301118464, 301119488,
|
||||
301120512, 301121536, 301122560, 301123584, 301124608, 301125632,
|
||||
301126656, 301127680, 301128704, 301129728, 301130752, 301131776,
|
||||
301132800, 301133824, 301134848, 301135872, 301136896, 301137920,
|
||||
301138944, 301139968, 301140992, 301142016, 301143040, 301144064,
|
||||
301145088, 301146112, 301147136, 301148160, 301149184, 301150208,
|
||||
301151232, 301152256, 301153280, 301154304, 301155328, 301156352,
|
||||
301157376, 301158400, 301159424, 301160448, 301161472, 301162496,
|
||||
301163520, 301164544, 301165568, 301166592, 301167616, 301168640,
|
||||
301169664, 301170688, 301171712, 301172736, 301173760, 301174784,
|
||||
301175808, 301176832, 301177856, 301178880, 301179904, 301180928,
|
||||
301181952, 301182976, 301184000, 301185024, 301186048, 301187072,
|
||||
301188096, 301189120, 301190144, 301191168, 301193216, 301195264,
|
||||
301194240, 301197312, 301198336, 301199360, 301201408, 301202432
|
||||
};
|
||||
private final static byte[] aByteArray235 = {
|
||||
22, 22, 22, 22, 22, 22, 21, 22, 22,
|
||||
20, 22, 22, 22, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 3, 8, 22, 16, 22, 16, 17, 7, 13, 13, 13,
|
||||
16, 7, 10, 6, 16, 10, 11, 12, 12, 12, 12, 13, 13, 14, 14, 11, 14,
|
||||
19, 15, 17, 8, 11, 9, 10, 10, 10, 10, 11, 10, 9, 7, 12, 11, 10, 10,
|
||||
9, 10, 10, 12, 10, 9, 8, 12, 12, 9, 14, 8, 12, 17, 16, 17, 22, 13,
|
||||
21, 4, 7, 6, 5, 3, 6, 6, 5, 4, 10, 7, 5, 6, 4, 4, 6, 10, 5, 4, 4,
|
||||
5, 7, 6, 10, 6, 10, 22, 19, 22, 14, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 21, 22, 21, 22, 22, 22, 21,
|
||||
22, 22
|
||||
};
|
||||
/**
|
||||
* Encrypt a string for the client.
|
||||
*/
|
||||
public static int encryptPlayerChat(byte[] is, int i_25_, int i_26_, int i_27_, byte[] is_28_) {
|
||||
try {
|
||||
i_27_ += i_25_;
|
||||
int i_29_ = 0;
|
||||
int i_30_ = i_26_ << 3;
|
||||
for (; i_27_ > i_25_; i_25_++) {
|
||||
int i_31_ = 0xff & is_28_[i_25_];
|
||||
int i_32_ = anIntArray233[i_31_];
|
||||
int i_33_ = aByteArray235[i_31_];
|
||||
int i_34_ = i_30_ >> 3;
|
||||
int i_35_ = i_30_ & 0x7;
|
||||
i_29_ &= (-i_35_ >> 31);
|
||||
i_30_ += i_33_;
|
||||
int i_36_ = ((-1 + (i_35_ - -i_33_)) >> 3) + i_34_;
|
||||
i_35_ += 24;
|
||||
is[i_34_] = (byte) (i_29_ = (i_29_ | (i_32_ >>> i_35_)));
|
||||
if ((i_36_ ^ 0xffffffff) < (i_34_ ^ 0xffffffff)) {
|
||||
i_34_++;
|
||||
i_35_ -= 8;
|
||||
is[i_34_] = (byte) (i_29_ = i_32_ >>> i_35_);
|
||||
if (i_36_ > i_34_) {
|
||||
i_34_++;
|
||||
i_35_ -= 8;
|
||||
is[i_34_] = (byte) (i_29_ = i_32_ >>> i_35_);
|
||||
if (i_36_ > i_34_) {
|
||||
i_35_ -= 8;
|
||||
i_34_++;
|
||||
is[i_34_] = (byte) (i_29_ = i_32_ >>> i_35_);
|
||||
if (i_34_ < i_36_) {
|
||||
i_35_ -= 8;
|
||||
i_34_++;
|
||||
is[i_34_] = (byte) (i_29_ = i_32_ << -i_35_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -i_26_ + ((7 + i_30_) >> 3);
|
||||
} catch (RuntimeException runtimeexception) {
|
||||
runtimeexception.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Gets an integer value from a string.
|
||||
* @param s the string.
|
||||
* @return The value;
|
||||
*/
|
||||
public static int getValue(String s) {
|
||||
s = s.replaceAll(", ", "").replaceAll(",", "");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char c;
|
||||
boolean foundStart = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
c = s.charAt(i);
|
||||
if (Character.isDigit(c) || c == '-') {
|
||||
sb.append(c);
|
||||
foundStart = true;
|
||||
} else if (foundStart)
|
||||
break;
|
||||
}
|
||||
try {
|
||||
int amount = Integer.parseInt(sb.toString());
|
||||
return amount;
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if the account name is valid.
|
||||
* @param name The account name.
|
||||
* @return {@code True} if the account name is invalid.
|
||||
*/
|
||||
public static boolean invalidAccountName(String name) {
|
||||
return name.length() < 2 || name.length() > 12 || name.startsWith("_")|| name.endsWith("_") || name.contains("__") || containsInvalidCharacter(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a long to a string.
|
||||
* @param l The long.
|
||||
* @return The string.
|
||||
*/
|
||||
public static String longToString(long l) {
|
||||
int i = 0;
|
||||
char ac[] = new char[32];
|
||||
while (l != 0L) {
|
||||
long l1 = l;
|
||||
l /= 37L;
|
||||
ac[11 - i++] = VALID_CHARS[(int) (l1 - l * 37L)];
|
||||
}
|
||||
return new String(ac, 12 - i, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packs a GJ2-String.
|
||||
* @param position The position to start.
|
||||
* @param buffer The byte-array.
|
||||
* @param str The string.
|
||||
* @return The size of the string.
|
||||
*/
|
||||
public static final int packGJString2(int position, byte[] buffer,
|
||||
String str) {
|
||||
int length = str.length();
|
||||
int offset = position;
|
||||
for (int index = 0; length > index; index++) {
|
||||
int character = str.charAt(index);
|
||||
if (character > 127) {
|
||||
if (character > 2047) {
|
||||
buffer[offset++] = (byte) ((character | 919275) >> 12);
|
||||
buffer[offset++] = (byte) (128 | ((character >> 6) & 63));
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
} else {
|
||||
buffer[offset++] = (byte) ((character | 12309) >> 6);
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
}
|
||||
} else
|
||||
buffer[offset++] = (byte) character;
|
||||
}
|
||||
return offset - position;
|
||||
}
|
||||
/**
|
||||
* Method used to...
|
||||
* @param x idk,
|
||||
* @return the idk.
|
||||
*/
|
||||
public static long reducedMapping(int x) {
|
||||
long out = -1;
|
||||
if (x >= 97 && x <= 122)
|
||||
out = x - 96;
|
||||
else if (x >= 65 && x <= 90)
|
||||
out = x - 37;
|
||||
else if (x >= 48 && x <= 57)
|
||||
out = x - +5;
|
||||
else if (x == 32)
|
||||
out = 63L;
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* Converts a string to a long.
|
||||
* @param s The string.
|
||||
* @return The long.
|
||||
*/
|
||||
public static long stringToLong(String s) {
|
||||
long l = 0L;
|
||||
for (int i = 0; i < s.length() && i < 12; i++) {
|
||||
char c = s.charAt(i);
|
||||
l *= 37L;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
l += (1 + c) - 65;
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
l += (1 + c) - 97;
|
||||
else if (c >= '0' && c <= '9')
|
||||
l += (27 + c) - 48;
|
||||
}
|
||||
while (l % 37L == 0L && l != 0L)
|
||||
l /= 37L;
|
||||
return l;
|
||||
}
|
||||
/**
|
||||
* Decrypt player chat.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer
|
||||
* @param totalChars
|
||||
* The total chars
|
||||
* @return The string
|
||||
*/
|
||||
public static String decryptPlayerChat(IoBuffer buffer, int totalChars) {
|
||||
try {
|
||||
if (totalChars == 0)
|
||||
return "";
|
||||
int charsDecoded = 0;
|
||||
int i_4_ = 0;
|
||||
String s = "";
|
||||
for (;;) {
|
||||
byte i_7_ = (byte) buffer.get();
|
||||
if (i_7_ >= 0)
|
||||
i_4_++;
|
||||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
int i_8_;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
if (((i_7_ & 0x40) ^ 0xffffffff) != -1)
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (++charsDecoded >= totalChars)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
if ((0x20 & i_7_) == 0)
|
||||
i_4_++;
|
||||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
if (((0x10 & i_7_) ^ 0xffffffff) == -1)
|
||||
i_4_++;
|
||||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
|
||||
i_4_ = 0;
|
||||
}
|
||||
if (((0x8 & i_7_) ^ 0xffffffff) != -1)
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (++charsDecoded >= totalChars)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
if ((0x4 & i_7_) == 0)
|
||||
i_4_++;
|
||||
else
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
if (((i_7_ & 0x2) ^ 0xffffffff) != -1)
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (totalChars <= ++charsDecoded)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
if (((i_7_ & 0x1) ^ 0xffffffff) != -1)
|
||||
i_4_ = anIntArray241[i_4_];
|
||||
else
|
||||
i_4_++;
|
||||
if ((i_8_ = anIntArray241[i_4_]) < 0) {
|
||||
s += (char) (byte) (i_8_ ^ 0xffffffff);
|
||||
if (++charsDecoded >= totalChars)
|
||||
break;
|
||||
i_4_ = 0;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
} catch (RuntimeException runtimeexception) {
|
||||
runtimeexception.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package ms.system.util;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
/**
|
||||
* A class holding methods to execute tasks.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class TaskExecutor {
|
||||
|
||||
/**
|
||||
* The executor to use.
|
||||
*/
|
||||
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
/**
|
||||
* The SQL task executor.
|
||||
*/
|
||||
private static final ScheduledExecutorService SQL_EXECUTOR = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TaskExecutor} {@code Object}.
|
||||
*/
|
||||
private TaskExecutor() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an SQL handling task.
|
||||
* @param task The task.
|
||||
*/
|
||||
public static void executeSQL(Runnable task) {
|
||||
SQL_EXECUTOR.execute(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the task.
|
||||
* @param task The task to execute.
|
||||
*/
|
||||
public static void execute(Runnable task) {
|
||||
EXECUTOR.execute(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the executor.
|
||||
* @return The executor.
|
||||
*/
|
||||
public static ScheduledExecutorService getExecutor() {
|
||||
return EXECUTOR;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
package ms.world;
|
||||
|
||||
import ms.net.IoSession;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.mysql.SQLEntryHandler;
|
||||
import ms.system.mysql.WorldListSQLHandler;
|
||||
import ms.system.util.TaskExecutor;
|
||||
import ms.world.info.Response;
|
||||
import ms.world.info.WorldInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Represents a game world.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class GameServer {
|
||||
|
||||
/**
|
||||
* The world info.
|
||||
*/
|
||||
private final WorldInfo info;
|
||||
|
||||
/**
|
||||
* The I/O session.
|
||||
*/
|
||||
private IoSession session;
|
||||
|
||||
/**
|
||||
* The players active on the game server.
|
||||
*/
|
||||
private final Map<String, PlayerSession> players = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The scheduled future for the updating task.
|
||||
*/
|
||||
private ScheduledFuture<?> future;
|
||||
|
||||
/**
|
||||
* constructs a new {@code GameServer} {@code Object}.
|
||||
* @param info The world info.
|
||||
*/
|
||||
public GameServer(WorldInfo info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the game server.
|
||||
* @param session The I/O session.
|
||||
*/
|
||||
public void configure(IoSession session) {
|
||||
this.session = session;
|
||||
session.setGameServer(this);
|
||||
future = TaskExecutor.getExecutor().scheduleAtFixedRate(() -> {
|
||||
SQLEntryHandler.write(new WorldListSQLHandler(GameServer.this));
|
||||
if (!isActive()) {
|
||||
future.cancel(false);
|
||||
future = null;
|
||||
}
|
||||
}, 0, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a player.
|
||||
* @param player The player.
|
||||
*/
|
||||
public void register(PlayerSession player) {
|
||||
players.put(player.getUsername(), player);
|
||||
player.setWorld(this);
|
||||
player.setActive(true);
|
||||
player.setWorldId(info.getWorldId());
|
||||
player.configure();
|
||||
WorldPacketRepository.sendRegistryResponse(this, player, Response.SUCCESSFUL);
|
||||
player.getCommunication().sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the game server is active.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return session.isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the playerAmount
|
||||
*/
|
||||
public int getPlayerAmount() {
|
||||
return players.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the info
|
||||
*/
|
||||
public WorldInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the session
|
||||
*/
|
||||
public IoSession getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param session the session to set
|
||||
*/
|
||||
public void setSession(IoSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the players value.
|
||||
* @return The players.
|
||||
*/
|
||||
public Map<String, PlayerSession> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,475 +0,0 @@
|
|||
package ms.world;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.system.communication.ClanRepository;
|
||||
import ms.system.communication.CommunicationInfo;
|
||||
import ms.system.mysql.SQLManager;
|
||||
import ms.world.info.UIDInfo;
|
||||
|
||||
/**
|
||||
* Represents a player session.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PlayerSession {
|
||||
|
||||
/**
|
||||
* The player's communication info.
|
||||
*/
|
||||
private CommunicationInfo communication = new CommunicationInfo(this);
|
||||
|
||||
/**
|
||||
* The game server the player is currently in.
|
||||
*/
|
||||
private GameServer world;
|
||||
|
||||
/**
|
||||
* The current clan.
|
||||
*/
|
||||
private ClanRepository clan;
|
||||
|
||||
/**
|
||||
* The player's UID info.
|
||||
*/
|
||||
private UIDInfo uid;
|
||||
|
||||
/**
|
||||
* The username.
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* The password.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* The player's rights.
|
||||
*/
|
||||
private int rights;
|
||||
|
||||
/**
|
||||
* The world id.
|
||||
*/
|
||||
private int worldId;
|
||||
|
||||
/**
|
||||
* If the player session is active.
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* The time stamp of last disconnection.
|
||||
*/
|
||||
private long disconnectionTime = 0L;
|
||||
|
||||
/**
|
||||
* How long the player is banned for.
|
||||
*/
|
||||
private long banTime;
|
||||
|
||||
/**
|
||||
* How long the player is muted for.
|
||||
*/
|
||||
private long muteTime;
|
||||
|
||||
/**
|
||||
* The last world the player logged in.
|
||||
*/
|
||||
private int lastWorld = -1;
|
||||
|
||||
/**
|
||||
* The chat icon.
|
||||
*/
|
||||
private int chatIcon;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PlayerSession} {@code Object}.
|
||||
* @param username The username.
|
||||
* @param password The password.
|
||||
* @param ipAddress The ip address.
|
||||
* @param macAddress The mac address.
|
||||
* @param computerName The computer name.
|
||||
* @param serial The motherboard serial key.
|
||||
*/
|
||||
public PlayerSession(String username, String password, UIDInfo uid) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the session's data from the database.
|
||||
* @return {@code True} if parsed.
|
||||
*/
|
||||
public boolean parse() {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
ResultSet result = null;
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("SELECT * FROM " + "members" + " WHERE " + "" + "username" + "='" + username.toLowerCase() + "' LIMIT 1");
|
||||
result = statement.executeQuery();
|
||||
if (result == null || !result.next()) {
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
}
|
||||
rights = result.getInt("rights");
|
||||
disconnectionTime = result.getLong("disconnectTime");
|
||||
lastWorld = result.getInt("lastWorld");
|
||||
banTime = result.getLong("banTime");
|
||||
communication.parse(result);
|
||||
uid.parse(result);
|
||||
SQLManager.close(connection);
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a session is removed.
|
||||
*/
|
||||
public void remove() {
|
||||
if (world != null && world.getInfo().getRevision() == 498) {
|
||||
return;
|
||||
}
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("UPDATE members SET disconnectTime = ?, lastWorld = ?, contacts = ?, blocked = ?, clanName = ?, currentClan = ?, clanReqs = ?, chatSettings = ?, online= ? WHERE username = ?");
|
||||
statement.setLong(1, System.currentTimeMillis());
|
||||
statement.setInt(2, worldId);
|
||||
communication.save(statement);
|
||||
statement.setBoolean(9, false);
|
||||
statement.setString(10, username);
|
||||
statement.executeUpdate();
|
||||
SQLManager.close(connection);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
communication.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a player session.
|
||||
* @param username the username.
|
||||
* @return the player session.
|
||||
*/
|
||||
public static PlayerSession get(String username) {
|
||||
PlayerSession session = new PlayerSession(username, "", new UIDInfo());
|
||||
if (!session.parse()) {
|
||||
return null;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the player session.
|
||||
*/
|
||||
public void configure() {
|
||||
ClanRepository clan = ClanRepository.getClans().get(username);
|
||||
if (clan != null) {
|
||||
clan.setOwner(this);
|
||||
}
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("UPDATE members SET online = ?, lastWorld = ?, lastLogin = ? WHERE username = ?");
|
||||
statement.setBoolean(1, true);
|
||||
statement.setInt(2, worldId);
|
||||
statement.setLong(3, System.currentTimeMillis());
|
||||
statement.setString(4, username);
|
||||
statement.execute();
|
||||
SQLManager.close(connection);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
} finally {
|
||||
SQLManager.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player has just moved worlds.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean hasMovedWorld() {
|
||||
if (rights == 2) {
|
||||
return false;
|
||||
}
|
||||
return System.currentTimeMillis() - disconnectionTime < ServerConstants.WORLD_SWITCH_DELAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username value.
|
||||
* @return The username.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the password value.
|
||||
* @return The password.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chat icon.
|
||||
* @return The chat icon.
|
||||
*/
|
||||
public int getChatIcon() {
|
||||
return chatIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ipAddress value.
|
||||
* @return The ipAddress.
|
||||
*/
|
||||
public String getIpAddress() {
|
||||
return uid.getIp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the macAddress value.
|
||||
* @return The macAddress.
|
||||
*/
|
||||
public String getMacAddress() {
|
||||
return uid.getMac();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the computerName value.
|
||||
* @return The computerName.
|
||||
*/
|
||||
public String getComputerName() {
|
||||
return uid.getCompName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the worldId value.
|
||||
* @return The worldId.
|
||||
*/
|
||||
public int getWorldId() {
|
||||
return worldId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the worldId value.
|
||||
* @param worldId The worldId to set.
|
||||
*/
|
||||
public void setWorldId(int worldId) {
|
||||
this.worldId = worldId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the active value.
|
||||
* @return The active.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the active value.
|
||||
* @param active The active to set.
|
||||
*/
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serialKey value.
|
||||
* @return The serialKey.
|
||||
*/
|
||||
public String getSerialKey() {
|
||||
return uid.getSerial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rights value.
|
||||
* @return The rights.
|
||||
*/
|
||||
public int getRights() {
|
||||
return rights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rights value.
|
||||
* @param rights The rights to set.
|
||||
*/
|
||||
public void setRights(int rights) {
|
||||
this.rights = rights;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the player is banned.
|
||||
* @return {@code true} if so.
|
||||
*/
|
||||
public boolean isBanned() {
|
||||
return banTime > System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the banTime value.
|
||||
* @return The banTime.
|
||||
*/
|
||||
public long getBanTime() {
|
||||
return banTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the muteTime.
|
||||
* @return the muteTime.
|
||||
*/
|
||||
public long getMuteTime() {
|
||||
return muteTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the muteTime.
|
||||
* @param muteTime the muteTime to set
|
||||
*/
|
||||
public void setMuteTime(long muteTime) {
|
||||
this.muteTime = muteTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the disconnectionTime value.
|
||||
* @return The disconnectionTime.
|
||||
*/
|
||||
public long getDisconnectionTime() {
|
||||
return disconnectionTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lastWorld value.
|
||||
* @return The lastWorld.
|
||||
*/
|
||||
public int getLastWorld() {
|
||||
return lastWorld;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lastWorld value.
|
||||
* @param lastWorld The lastWorld to set.
|
||||
*/
|
||||
public void setLastWorld(int lastWorld) {
|
||||
this.lastWorld = lastWorld;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the communication value.
|
||||
* @return The communication.
|
||||
*/
|
||||
public CommunicationInfo getCommunication() {
|
||||
return communication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the communication value.
|
||||
* @param communication The communication to set.
|
||||
*/
|
||||
public void setCommunication(CommunicationInfo communication) {
|
||||
this.communication = communication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world value.
|
||||
* @return The world.
|
||||
*/
|
||||
public GameServer getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the world value.
|
||||
* @param world The world to set.
|
||||
*/
|
||||
public void setWorld(GameServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan value.
|
||||
* @return The clan.
|
||||
*/
|
||||
public ClanRepository getClan() {
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clan value.
|
||||
* @param clan The clan to set.
|
||||
*/
|
||||
public void setClan(ClanRepository clan) {
|
||||
this.clan = clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat icon.
|
||||
* @param chatIcon
|
||||
*/
|
||||
public void setChatIcon(int chatIcon) {
|
||||
this.chatIcon = chatIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the uid.
|
||||
* @return the uid.
|
||||
*/
|
||||
public UIDInfo getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uid.
|
||||
* @param uid the uid to set
|
||||
*/
|
||||
public void setUid(UIDInfo uid) {
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the disconnect time.
|
||||
* @param time the time.
|
||||
*/
|
||||
public void setDisconnectTime(long time) {
|
||||
this.disconnectionTime = time;
|
||||
}
|
||||
|
||||
public boolean equalsSession(PlayerSession o){
|
||||
return username.equals(o.username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "player [name=" + username + ", pass=" + password + ", ip=" + uid.getIp() + ", mac=" + uid.getMac() + ", comp=" + uid.getCompName() + ", msk=" + uid.getSerial() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,275 +0,0 @@
|
|||
package ms.world;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.packet.IoBuffer;
|
||||
import ms.world.info.CountryFlag;
|
||||
import ms.world.info.WorldInfo;
|
||||
import ms09.MSLogger;
|
||||
|
||||
/**
|
||||
* Holds all the world servers.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class WorldDatabase {
|
||||
|
||||
/**
|
||||
* The game servers.
|
||||
*/
|
||||
private static final GameServer[] DATABASE = new GameServer[ServerConstants.WORLD_LIMIT];
|
||||
|
||||
/**
|
||||
* The update time stamp.
|
||||
*/
|
||||
private static long updateStamp = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Used to prevent {@code WorldDatabase} from getting instantiated.
|
||||
*/
|
||||
private WorldDatabase() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet to update the world list in the lobby.
|
||||
* @param player The player.
|
||||
* @param worldConfiguration If the configuration should be added.
|
||||
* @param worldStatus If the status should be added.
|
||||
* @return The {@code OutgoingPacket} to write.
|
||||
*/
|
||||
public static void sendUpdate(IoSession session, int updateStamp) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(1024);
|
||||
buf.put((byte) 0);
|
||||
buf.putShort((short) 0);
|
||||
buf.put((byte) 1);
|
||||
IoBuffer buffer = new IoBuffer();
|
||||
if (updateStamp == (int) WorldDatabase.updateStamp) {
|
||||
buf.put((byte) 0);
|
||||
} else {
|
||||
buf.put((byte) 1); // Indicates an update occured.
|
||||
putWorldListinfo(buffer);
|
||||
}
|
||||
putPlayerInfo(buffer);
|
||||
if (buffer.toByteBuffer().position() > 0) {
|
||||
buf.put((ByteBuffer) buffer.toByteBuffer().flip());
|
||||
}
|
||||
buf.putShort(1, (short) (buf.position() - 3));
|
||||
session.queue((ByteBuffer) buf.flip());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the world status on the packet.
|
||||
* @param buffer The current packet.
|
||||
*/
|
||||
private static void putPlayerInfo(IoBuffer buffer) {
|
||||
for (GameServer server : DATABASE) {
|
||||
if (server != null) {
|
||||
WorldInfo w = server.getInfo();
|
||||
buffer.putSmart(w.getWorldId());
|
||||
buffer.putShort(server.isActive() ? server.getPlayerAmount() : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the countries for each world.
|
||||
* @param buffer The current packet.
|
||||
*/
|
||||
private static void putCountryInfo(IoBuffer buffer) {
|
||||
for (CountryFlag country : CountryFlag.values()) {
|
||||
buffer.putSmart(country.getId());
|
||||
buffer.putJagString(capitalize(country.name().toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a capitalized string
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private static String capitalize(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
return name;
|
||||
} else {
|
||||
char[] chars = name.toCharArray();
|
||||
chars[0] = Character.toUpperCase(chars[0]);
|
||||
return new String(chars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the world configuration on the packet.
|
||||
* @param buffer The current packet.
|
||||
*/
|
||||
private static void putWorldListinfo(IoBuffer buffer) {
|
||||
buffer.putSmart(CountryFlag.values().length);
|
||||
putCountryInfo(buffer);
|
||||
buffer.putSmart(0);
|
||||
buffer.putSmart(DATABASE.length);
|
||||
buffer.putSmart(getRegisteredAmount());
|
||||
for (GameServer server : DATABASE) {
|
||||
if (server != null) {
|
||||
WorldInfo w = server.getInfo();
|
||||
buffer.putSmart(w.getWorldId());
|
||||
buffer.put(w.getCountry().ordinal());
|
||||
buffer.putInt(w.getSettings());
|
||||
buffer.putJagString(w.getActivity());
|
||||
buffer.putJagString(w.getAddress());
|
||||
}
|
||||
}
|
||||
buffer.putInt((int) updateStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of worlds registered.
|
||||
* @return The amount of worlds registered.
|
||||
*/
|
||||
public static int getRegisteredAmount() {
|
||||
int count = 0;
|
||||
for (GameServer server : DATABASE) {
|
||||
if (server != null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a game server.
|
||||
* @param info The game world info.
|
||||
*/
|
||||
public static GameServer register(WorldInfo info) {
|
||||
GameServer server = DATABASE[info.getWorldId()];
|
||||
if (server != null && server.getSession().isActive() && !server.getSession().getAddress().equals(info.getAddress())) {
|
||||
throw new IllegalStateException("World " + info.getWorldId() + " is already registered!");
|
||||
}
|
||||
flagUpdate();
|
||||
MSLogger.logInfo("Registered world - [id=" + info.getWorldId() + ", ip=" + info.getAddress() + ", country=" + info.getCountry().name().toLowerCase() + ", revision=" + info.getRevision() + "]!");
|
||||
return DATABASE[info.getWorldId()] = new GameServer(info);
|
||||
}
|
||||
|
||||
public static void unRegister(GameServer server){
|
||||
int index = -1;
|
||||
for(int i = 0; i < DATABASE.length; i++){
|
||||
GameServer s = DATABASE[i];
|
||||
if(s == server){
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(index != -1){
|
||||
DATABASE[index] = null;
|
||||
WorldInfo info = server.getInfo();
|
||||
MSLogger.logInfo("Unregistered world - [id=" + info.getWorldId() + ", ip=" + info.getAddress() + ", country=" + info.getCountry().name().toLowerCase() + ", revision=" + info.getRevision() + "]!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world id of the player.
|
||||
* @param username The username of the player.
|
||||
* @return The world id.
|
||||
*/
|
||||
public static int getWorldId(String username) {
|
||||
return getWorldId(getPlayer(username));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world id of the player.
|
||||
* @param player The player.
|
||||
* @return The world id.
|
||||
*/
|
||||
public static int getWorldId(PlayerSession player) {
|
||||
if (player == null || !player.isActive()) {
|
||||
return 0;
|
||||
}
|
||||
return player.getWorldId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the game world is active.
|
||||
* @param worldId The world id.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean isActive(int worldId) {
|
||||
GameServer server = get(worldId);
|
||||
return server != null && server.isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player session for the given name is active.
|
||||
* @param username The player's username.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean isActivePlayer(String username) {
|
||||
PlayerSession session = getPlayer(username);
|
||||
return session != null && session.isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player session for the given name.
|
||||
* @param username The player's username.
|
||||
* @return The player session.
|
||||
*/
|
||||
public static PlayerSession getPlayer(String username) {
|
||||
return getPlayer(username, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player session for the given name.
|
||||
* @param username The player's username.
|
||||
* @param load If we load the users data.
|
||||
* @return The player session.
|
||||
*/
|
||||
public static PlayerSession getPlayer(String username, boolean load) {
|
||||
for (GameServer server : DATABASE) {
|
||||
if (server != null && server.isActive()) {
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player != null) {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (load) {
|
||||
return PlayerSession.get(username);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the game server for the given world id.
|
||||
* @param worldId The world id.
|
||||
* @return The game server.
|
||||
*/
|
||||
public static GameServer get(int worldId) {
|
||||
return DATABASE[worldId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the game servers.
|
||||
* @return The list of game servers.
|
||||
*/
|
||||
public static GameServer[] getWorlds() {
|
||||
return DATABASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the updateStamp.
|
||||
* @return the updateStamp
|
||||
*/
|
||||
public static long getUpdateStamp() {
|
||||
return updateStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the updateStamp.
|
||||
* @param updateStamp the updateStamp to set.
|
||||
*/
|
||||
public static void flagUpdate() {
|
||||
WorldDatabase.updateStamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package ms.world.info;
|
||||
|
||||
/**
|
||||
* The country flags.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public enum CountryFlag {
|
||||
|
||||
/**
|
||||
* Belgium
|
||||
*/
|
||||
BELGIUM(22),
|
||||
|
||||
/**
|
||||
* Canada.
|
||||
*/
|
||||
CANADA(38),
|
||||
|
||||
/**
|
||||
* The united kingdom.
|
||||
*/
|
||||
UNITED_KINGDOM(77),
|
||||
|
||||
/**
|
||||
* Netherlands
|
||||
*/
|
||||
NETHERLANDS(161),
|
||||
|
||||
/**
|
||||
* Sweden
|
||||
*/
|
||||
SWEDEN(191),
|
||||
|
||||
/**
|
||||
* Finland
|
||||
*/
|
||||
FINLAND(69),
|
||||
|
||||
/**
|
||||
* Australia.
|
||||
*/
|
||||
AUSTRALIA(16),
|
||||
|
||||
/**
|
||||
* America (USA)
|
||||
*/
|
||||
UNITED_STATES_OF_AMERICA(225),
|
||||
|
||||
/**
|
||||
* Norway
|
||||
*/
|
||||
NORWAY(162),
|
||||
|
||||
/**
|
||||
* Ireland
|
||||
*/
|
||||
IRELAND(101),
|
||||
|
||||
/**
|
||||
* DENMARK
|
||||
*/
|
||||
DENMARK(58),
|
||||
|
||||
/**
|
||||
* Brazil
|
||||
*/
|
||||
BRAZIL(31),
|
||||
|
||||
/**
|
||||
* Mexico
|
||||
*/
|
||||
MEXICO(152),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* The flag id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code CountryFlag} {@code Object}.
|
||||
* @param id The flag id.
|
||||
*/
|
||||
private CountryFlag(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
package ms.world.info;
|
||||
|
||||
/**
|
||||
* Holds the response codes during the attempt to login.
|
||||
* @author Emperor
|
||||
*/
|
||||
public enum Response {
|
||||
|
||||
/**
|
||||
* An unexpected server response occurred.
|
||||
*/
|
||||
UNEXPECTED_RESPONSE(0),
|
||||
|
||||
/**
|
||||
* Could not display advertisement video, logging in in x seconds.
|
||||
*/
|
||||
COULD_NOT_DISPLAY_AD(1),
|
||||
|
||||
/**
|
||||
* A successful login.
|
||||
*/
|
||||
SUCCESSFUL(2),
|
||||
|
||||
/**
|
||||
* Invalid username or password has been entered.
|
||||
*/
|
||||
INVALID_CREDENTIALS(3),
|
||||
|
||||
/**
|
||||
* This account is banned.
|
||||
*/
|
||||
ACCOUNT_DISABLED(4),
|
||||
|
||||
/**
|
||||
* This account is already logged in.
|
||||
*/
|
||||
ALREADY_ONLINE(5),
|
||||
|
||||
/**
|
||||
* We have updated and client needs to be reloaded.
|
||||
*/
|
||||
UPDATED(6),
|
||||
|
||||
/**
|
||||
* The world is full.
|
||||
*/
|
||||
FULL_WORLD(7),
|
||||
|
||||
/**
|
||||
* Login server is offline.
|
||||
*/
|
||||
LOGIN_SERVER_OFFLINE(8),
|
||||
|
||||
/**
|
||||
* The login limit has been exceeded.
|
||||
*/
|
||||
LOGIN_LIMIT_EXCEEDED(9),
|
||||
|
||||
/**
|
||||
* The session key was invalid.
|
||||
*/
|
||||
BAD_SESSION_ID(10),
|
||||
|
||||
/**
|
||||
* The password is too weak, and should be improved.
|
||||
*/
|
||||
WEAK_PASSWORD(11),
|
||||
|
||||
/**
|
||||
* When trying to connect to a members world while being f2p.
|
||||
*/
|
||||
MEMBERS_WORLD(12),
|
||||
|
||||
/**
|
||||
* Could not login.
|
||||
*/
|
||||
COULD_NOT_LOGIN(13),
|
||||
|
||||
/**
|
||||
* The server is currently updating.
|
||||
*/
|
||||
UPDATING(14),
|
||||
|
||||
/**
|
||||
* Too many incorrect login attempts from your address.
|
||||
*/
|
||||
TOO_MANY_INCORRECT_LOGINS(16),
|
||||
|
||||
/**
|
||||
* When logging on a free world while standing in members area.
|
||||
*/
|
||||
STANDING_IN_MEMBER(17),
|
||||
|
||||
/**
|
||||
* This account is locked as it might have been stolen.
|
||||
*/
|
||||
LOCKED(18),
|
||||
|
||||
/**
|
||||
* Closed beta going on.
|
||||
*/
|
||||
CLOSED_BETA(19),
|
||||
|
||||
/**
|
||||
* The login server connected to is invalid.
|
||||
*/
|
||||
INVALID_LOGIN_SERVER(20),
|
||||
|
||||
/**
|
||||
* Moving from another world...
|
||||
*/
|
||||
MOVING_WORLD(21),
|
||||
|
||||
/**
|
||||
* When the player's saved file exists, but is unable to be loaded.
|
||||
*/
|
||||
ERROR_LOADING_PROFILE(24),
|
||||
|
||||
/**
|
||||
* This computer address is disabled as it was used to break our rules.
|
||||
*/
|
||||
BANNED(26);
|
||||
|
||||
/**
|
||||
* The buffer.
|
||||
*/
|
||||
private final int opcode;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Response} {@code Object}.
|
||||
* @param opcode The login response opcode.
|
||||
*/
|
||||
Response(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the opcode.
|
||||
* @return The opcode.
|
||||
*/
|
||||
public int opcode() {
|
||||
return opcode;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
package ms.world.info;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
|
||||
/**
|
||||
* The unique info of a player.
|
||||
* @author Vexia
|
||||
*
|
||||
*/
|
||||
public class UIDInfo {
|
||||
|
||||
/**
|
||||
* The ip address.
|
||||
*/
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* The computer name.
|
||||
*/
|
||||
private String compName;
|
||||
|
||||
/**
|
||||
* The mac-address.
|
||||
*/
|
||||
private String mac;
|
||||
|
||||
/**
|
||||
* The motherboard serial of the user.
|
||||
*/
|
||||
private String serial;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new {@code UIDInfo} {@code Object}
|
||||
*/
|
||||
public UIDInfo() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code UIDInfo} {@code Object}
|
||||
* @param ip the ip.
|
||||
* @param compName the computer name.
|
||||
* @param mac the mac.
|
||||
* @param serial the serial.
|
||||
*/
|
||||
public UIDInfo(String ip, String compName, String mac, String serial) {
|
||||
this.ip = ip;
|
||||
this.compName = compName;
|
||||
this.mac = mac;
|
||||
this.serial = serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the data from a prepared statement.
|
||||
* @param set The result set
|
||||
* @throws SQLException The exception if thrown.
|
||||
*/
|
||||
public void parse(ResultSet set) throws SQLException {
|
||||
setIp(parseFormat(set.getString("ip")));
|
||||
setCompName(parseFormat(set.getString("computerName")));
|
||||
setMac(parseFormat(set.getString("mac")));
|
||||
setSerial(parseFormat(set.getString("serial")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the UID data on the buffer.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void save(ByteBuffer buffer) {
|
||||
save(buffer, ip, 1);
|
||||
save(buffer, compName, 2);
|
||||
save(buffer, mac, 3);
|
||||
save(buffer, serial, 4);
|
||||
buffer.put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the UID data from the buffer.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void parse(ByteBuffer buffer) {
|
||||
int opcode;
|
||||
while ((opcode = buffer.get()) != 0) {
|
||||
switch (opcode) {
|
||||
case 1:
|
||||
ip = ByteBufferUtils.getString(buffer);
|
||||
break;
|
||||
case 2:
|
||||
compName = ByteBufferUtils.getString(buffer);
|
||||
break;
|
||||
case 3:
|
||||
mac = ByteBufferUtils.getString(buffer);
|
||||
break;
|
||||
case 4:
|
||||
serial = ByteBufferUtils.getString(buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string with a certain format.
|
||||
* @param string the string.
|
||||
* @return the string.
|
||||
*/
|
||||
private String parseFormat(String string) {
|
||||
if (string == null || string.equals("")) {
|
||||
return null;
|
||||
}
|
||||
StringTokenizer token = new StringTokenizer(string, "|");
|
||||
String s = "";
|
||||
int t = token.countTokens();
|
||||
for (int i = 0; i < t; i++) {
|
||||
s = token.nextToken();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a string value to the buffer.
|
||||
* @param buffer the buffer.
|
||||
* @param value the value.
|
||||
* @param opcode the opcode.
|
||||
*/
|
||||
private void save(ByteBuffer buffer, String value, int opcode) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
ByteBufferUtils.putString(value, buffer.put((byte) opcode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a to string in format mode for an admin or mod.
|
||||
* @param admin the admin.
|
||||
* @return the string.
|
||||
*/
|
||||
public String toString(boolean admin) {
|
||||
String format = toString();
|
||||
if (!admin) {//formats for non-admins
|
||||
String[] tokens = format.split("serial=");
|
||||
format = format.replace("serial=", "uid=").replace(tokens[tokens.length - 1], "*****");
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compName.
|
||||
* @return the compName
|
||||
*/
|
||||
public String getCompName() {
|
||||
return compName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ip.
|
||||
* @return the ip
|
||||
*/
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mac.
|
||||
* @return the mac
|
||||
*/
|
||||
public String getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serial.
|
||||
* @return the serial
|
||||
*/
|
||||
public String getSerial() {
|
||||
return serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ip.
|
||||
* @param ip the ip to set.
|
||||
*/
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the compName.
|
||||
* @param compName the compName to set.
|
||||
*/
|
||||
public void setCompName(String compName) {
|
||||
this.compName = compName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mac.
|
||||
* @param mac the mac to set.
|
||||
*/
|
||||
public void setMac(String mac) {
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial.
|
||||
* @param serial the serial to set.
|
||||
*/
|
||||
public void setSerial(String serial) {
|
||||
this.serial = serial;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ip=" + ip + ", compName=" + compName + ", mac=" + mac + ", serial=" + serial + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
package ms.world.info;
|
||||
|
||||
/**
|
||||
* Holds the info of a world server.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class WorldInfo {
|
||||
|
||||
/**
|
||||
* The world id.
|
||||
*/
|
||||
private final int worldId;
|
||||
|
||||
/**
|
||||
* The IP-address.
|
||||
*/
|
||||
private final String address;
|
||||
|
||||
/**
|
||||
* The revision of the world.
|
||||
*/
|
||||
private final int revision;
|
||||
|
||||
/**
|
||||
* The country this world is located in.
|
||||
*/
|
||||
private final CountryFlag country;
|
||||
|
||||
/**
|
||||
* The world activity.
|
||||
*/
|
||||
private final String activity;
|
||||
|
||||
/**
|
||||
* If the world is members only.
|
||||
*/
|
||||
private final boolean members;
|
||||
|
||||
/**
|
||||
* If the world is a PvP world.
|
||||
*/
|
||||
private final boolean pvp;
|
||||
|
||||
/**
|
||||
* If the world is a quick chat only world.
|
||||
*/
|
||||
private final boolean quickChat;
|
||||
|
||||
/**
|
||||
* If the world has lootshare option enabled.
|
||||
*/
|
||||
private final boolean lootshare;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code WorldInfo} {@code Object}.
|
||||
* @param id The world id.
|
||||
* @param address The address.
|
||||
* @param country The country flag.
|
||||
* @param members If the world is members only.
|
||||
*/
|
||||
public WorldInfo(int id, String address, int revision, CountryFlag country, String activity, boolean members, boolean pvp, boolean quickChat, boolean lootshare) {
|
||||
this.worldId = id;
|
||||
this.address = address;
|
||||
this.revision = revision;
|
||||
this.country = country;
|
||||
this.activity = activity;
|
||||
this.members = members;
|
||||
this.pvp = pvp;
|
||||
this.quickChat = quickChat;
|
||||
this.lootshare = lootshare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the settings hash.
|
||||
* @return The settings hash.
|
||||
*/
|
||||
public int getSettings() {
|
||||
int settings = 0;
|
||||
if (members) {
|
||||
settings |= 0x1;
|
||||
}
|
||||
if (quickChat) {
|
||||
settings |= 0x2;
|
||||
}
|
||||
if (pvp) {
|
||||
settings |= 0x4;
|
||||
}
|
||||
if (lootshare) {
|
||||
settings |= 0x8;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the worldId
|
||||
*/
|
||||
public int getWorldId() {
|
||||
return worldId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address
|
||||
*/
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the country
|
||||
*/
|
||||
public CountryFlag getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the members value.
|
||||
* @return The members.
|
||||
*/
|
||||
public boolean isMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the activity value.
|
||||
* @return The activity.
|
||||
*/
|
||||
public String getActivity() {
|
||||
return activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pvp value.
|
||||
* @return The pvp.
|
||||
*/
|
||||
public boolean isPvp() {
|
||||
return pvp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quickChat value.
|
||||
* @return The quickChat.
|
||||
*/
|
||||
public boolean isQuickChat() {
|
||||
return quickChat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lootshare value.
|
||||
* @return The lootshare.
|
||||
*/
|
||||
public boolean isLootshare() {
|
||||
return lootshare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the revision.
|
||||
* @return the revision.
|
||||
*/
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package ms09
|
||||
|
||||
import com.github.ajalt.mordant.rendering.TextColors
|
||||
import com.github.ajalt.mordant.terminal.Terminal
|
||||
import java.io.BufferedWriter
|
||||
import java.io.Writer
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
object MSLogger {
|
||||
val t = Terminal()
|
||||
var tradeLog: Writer? = null
|
||||
var tradeLogWriter: BufferedWriter? = null
|
||||
|
||||
|
||||
fun getTime(): String{
|
||||
val formatter = SimpleDateFormat("HH:mm:ss")
|
||||
return "[" + formatter.format(Date(System.currentTimeMillis())) +"]"
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logInfo(vararg messages: String){
|
||||
for(m in messages){
|
||||
if(m.isNotBlank()) t.println("${getTime()}: [INFO] $m")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logErr(message: String){
|
||||
if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.brightRed("[ ERR] $message")}")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun logWarn(message: String){
|
||||
if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.yellow("[WARN] $message")}")
|
||||
}
|
||||
}
|
||||
166
README.md
166
README.md
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://gitlab.com/200scape/2009scape">
|
||||
<a href="https://gitlab.com/2009scape/2009scape">
|
||||
<img src="https://i.imgur.com/RsfVfkB.png" alt="Logo" width="300" height="67">
|
||||
</a>
|
||||
<h3 align="center">An open source MMORPG emulation server</h3>
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
* [Prerequisites](#prerequisites)
|
||||
* [Project Setup](#project-setup)
|
||||
* [Running the project](#running-the-project)
|
||||
* [Browser WebSocket Transport](#browser-websocket-transport)
|
||||
* [License](#license)
|
||||
* [Contact](#contact)
|
||||
|
||||
|
|
@ -61,7 +62,8 @@ In the current climate of RuneScape Private Servers in general, we believe it's
|
|||
## Contributing
|
||||
|
||||
**Note: All merge requests MUST be made using the defaut MR template. Merge requests that do not use this template will not be accepted.**
|
||||
**More information on Kotlin can be found [here](https://kotlinlang.org/).**
|
||||
|
||||
**Note: All new contributions MUST be made in Kotlin unless you are updating or fixing a bug in legacy code. More information on Kotlin can be found [here](https://kotlinlang.org/).**
|
||||
|
||||
There are many ways everyone can contribute! From the most seasoned programmers to those who do not have the most remote clue how code works! Below are some things that can always use some love from the community.
|
||||
|
||||
|
|
@ -71,7 +73,7 @@ There are many ways everyone can contribute! From the most seasoned programmers
|
|||
* **Wiki Editors**: Did you know we have a wiki? Well it's always in need of people to fill it out and stay on top of it. Editing the wiki is one of the easiest ways you can contribute to 2009Scape! If you're an active player and have the will, there's so much you could be helping out with over at the wiki. [Click here to go to the wiki](https://cdn.2009scape.org/wiki/doku.php?id=start).
|
||||
|
||||
|
||||
* **JSON editors**: We could always use more JSON editors! Please note that JSON editing **must** be done using the [Thanos Tool](https://gitlab.com/2009scape/rs09-thanos-tool/-/jobs/artifacts/master/raw/build/libs/thanostool.jar?job=build).
|
||||
* **JSON editors**: We could always use more JSON editors! Please note that JSON editing **must** be done using the [Thanos Tool](https://gitlab.com/2009scape/tools/rs09-thanos-tool/-/jobs/5153567519/artifacts/file/build/libs/zaros.jar). **This does not run on modern Java** and requires **Java 11** to run (using the usual 'java -jar zaros.jar').
|
||||
|
||||
|
||||
* **Authenticity Auditors**: As a remake, authenticity is central to our core values! We could always use someone to go through the game and create large lists of simple tasks that can be done to bring us closer to the authentic 2009 game! The preferred way to do this is one-area-at-a-time. If you want to see an example of some audits we've done in the past, take a look [here](https://gitlab.com/2009scape/2009scape/-/issues/46).
|
||||
|
|
@ -79,44 +81,56 @@ There are many ways everyone can contribute! From the most seasoned programmers
|
|||
|
||||
* **Code Contributors**: As a remake, we have massive amounts of content that need to be implemented or corrected. If you know how to program or are willing to learn, this is where you could be extremely helpful! We need everything from quests, to dialogue, to mini-games, to skills that still need to be corrected or implemented. This is perhaps one of the most valuable ways someone could help out the project! If you are interested in developing content, reach out in the development channel of the Discord.
|
||||
|
||||
|
||||
### Policy on Use of AI Tools
|
||||
|
||||
You, the contributor, agree to submit quality code to the best of your ability which you have tested yourself and confirmed that it works as intended, and if it doesn’t work, you agree to take constructive feedback and fix it.
|
||||
|
||||
You should be able to explain or defend how any part of your code works, without the use of AI or any other assistive tools.
|
||||
|
||||
2009scape reserves the right to reject your MR on grounds of poor quality, poor functionality, poor code style, poor attitudes or unethical over-reliance on assistive tools.
|
||||
|
||||
2009scape reserves the right to bar an individual from contributing due to patterns of aforementioned behavior, and close or delete all future MRs or issues or suggestions from said person without given explanation.
|
||||
|
||||
AI may not be used to generate your MR description, your issue description, or any responses to any discourse present on the Gitlab at any time or in any fashion. If you use AI in any of these places, it will be assumed that your entire contribution is AI and that you have no clue how it functions, and the remainder of the policy outlined above will be applied to you immediately.
|
||||
|
||||
|
||||
## Content Developers: Setting Up the Project.
|
||||
### GitLab Setup
|
||||
**Note: This allows you to commit changes to the main repo (with approval)! Also, always stay up to date with the most recent updates by pulling into your copy when 2009Scape updates!**
|
||||
|
||||
1. Create a GitLab account if you haven't done so already.
|
||||
|
||||
2. Click "Fork" in the top right-hand side of our GitLab page.
|
||||
2. Follow our Git Basics guide [over on the wiki.](https://gitlab.com/2009scape/2009scape/-/wikis/git-basics)
|
||||
|
||||
**If at anytime you have an issue with GitLab please refer to the [GitLab help center](https://gitlab.com/help).**
|
||||
|
||||
### Prerequisites
|
||||
|
||||
These are mandatory. If you don't install ***all*** of these programs prior to
|
||||
These are mandatory. If you don't install **all** of these programs **in order** prior to
|
||||
the project's setup, things won't work. At all.
|
||||
|
||||
* [Eclipse Temurin JDK 11 (preferred)](https://adoptium.net) or the Java SE Development Kit Version 11
|
||||
* [Git LFS](https://git-lfs.github.com/)
|
||||
*For Windows users* - Turn developer mode on first in Windows developer settings.
|
||||
|
||||
* [JDK 11](https://adoptium.net) or the Java SE Development Kit Version 11
|
||||
* [IntelliJ IDEA Community](https://www.jetbrains.com/idea/download/)
|
||||
|
||||
### SSH setup
|
||||
|
||||
1. [Set up a key if you don't have one (ed25519)](https://docs.gitlab.com/ee/user/ssh.html#generate-an-ssh-key-pair)
|
||||
2. [Add your public key to your gitlab account](https://docs.gitlab.com/ee/user/ssh.html#add-an-ssh-key-to-your-gitlab-account)
|
||||
3. [Verify you can connect to git@gitlab.com](https://docs.gitlab.com/ee/user/ssh.html#verify-that-you-can-connect)
|
||||
|
||||
### Project Setup
|
||||
|
||||
1. Open IntelliJ IDEA
|
||||
2. Clone the project using the `Get from VCS` button.
|
||||
3. Click the "Project" tab on the left-hand side.
|
||||
4. In the top left where the "Project" drop down is, click Project Files
|
||||
5. Expand the Server folder
|
||||
6. Right click `pom.xml` and click "Add Maven Project"
|
||||
7. In IntelliJ, File -> Invalidate Caches -> Invalidate Caches and Restart
|
||||
8. After setting up Git LFS, you may need to run `git lfs pull` in the root of the cloned repo to download essential binaries
|
||||
9. You should now have ready-made run configurations in the top right (you can ignore MS, it's obsolete):
|
||||
* [Windows] Run Server
|
||||
* [Linux] Run Server
|
||||
10. Ensure your working directory (the root of the project) is set in the run configuration editor.
|
||||
11. Go ahead and use the `Run Server` configuration for your OS to make sure everything worked.
|
||||
1. If you haven't already, make sure to follow our [Git Basics](https://gitlab.com/2009scape/2009scape/-/wikis/git-basics) guide.
|
||||
2. Run `git lfs pull` in the 2009scape folder you cloned as part of that guide. This only has to be done once, ever.
|
||||
3. Follow our [IntelliJ IDEA Setup Guide](https://gitlab.com/2009scape/2009scape/-/wikis/Setup-for-IntelliJ-IDEA-IDE)
|
||||
|
||||
### Running the project
|
||||
|
||||
***Note: If you choose not to use the provided run scripts, you *must* run `mvn clean` before it will build correctly.***
|
||||
1. If you followed the IntelliJ setup guide, which you probably should have, just use the provided run configuration.
|
||||
***Note: If you choose not to use the provided run scripts or IntelliJ, you *must* run `mvn clean` before it will build correctly.***
|
||||
|
||||
#### Linux / OSX
|
||||
|
||||
|
|
@ -126,13 +140,119 @@ Start the game server with the included run script. Use `./run -h` for more info
|
|||
|
||||
Start the game server with `run-server.bat`
|
||||
|
||||
#### Browser WebSocket Transport
|
||||
|
||||
Enable the listener in `Server/worldprops/default.conf`:
|
||||
|
||||
```properties
|
||||
websocket_enabled = true
|
||||
websocket_port = 0
|
||||
```
|
||||
|
||||
When `websocket_port = 0`, the listener uses `53594 + world_id`. For world `1`, that is `53595`.
|
||||
|
||||
Both plain WebSocket (`ws://`) and secure WebSocket (`wss://`) are supported. Use `ws://` for local HTTP testing. PWA requires HTTPS/WSS.
|
||||
|
||||
Enable WSS with a Java keystore:
|
||||
|
||||
```properties
|
||||
websocket_tls_enabled = true
|
||||
websocket_tls_keystore_path = "certs/dev-wss.p12"
|
||||
websocket_tls_keystore_password = "<keystore-password>"
|
||||
```
|
||||
|
||||
The keystore password is optional. Leave `websocket_tls_keystore_password` blank when using a PKCS12 file exported with an empty password:
|
||||
|
||||
```bash
|
||||
openssl pkcs12 -export \
|
||||
-in fullchain.pem \
|
||||
-inkey privkey.pem \
|
||||
-out certs/dev-wss.p12 \
|
||||
-name websocket \
|
||||
-passout pass:
|
||||
```
|
||||
|
||||
For local WSS development, create a certificate for your hostname or LAN IP that the browser will use, then point the server at a PKCS12 keystore. For production, use a normal certificate from certbot. Plain WS does not require a certificate.
|
||||
|
||||
#### Docker
|
||||
|
||||
Make sure [Docker Engine](https://docs.docker.com/engine/install/) & [Docker Compose](https://docs.docker.com/compose/install/) plugin are installed first:
|
||||
|
||||
Go to the project root where the git repository is cloned into:
|
||||
|
||||
```bash
|
||||
cd /path/to/project-dir
|
||||
```
|
||||
|
||||
To configure the database, copy the mysql env file template to a env file in the project root:
|
||||
|
||||
```bash
|
||||
cp mysql.env.example mysql.env
|
||||
```
|
||||
|
||||
Customize the env file however necessary.
|
||||
|
||||
Create a new directory called 'config' into the project root.
|
||||
|
||||
```bash
|
||||
mkdir config
|
||||
```
|
||||
|
||||
Copy the server config file template in the config directory:
|
||||
|
||||
```bash
|
||||
cp Server/worldprops/default.conf config/default.conf
|
||||
```
|
||||
|
||||
Edit the server configuration file as per needed.
|
||||
|
||||
Go to the project root directory and execute:
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
Which will build the docker image using the local Dockerfile and starts the server and database containers.
|
||||
|
||||
The previous up command should be run every time the server sources are modified to propagate the changes to the container.
|
||||
|
||||
For the first time, the server compilation process takes a long time. Grab some coffee in the meanwhile.
|
||||
|
||||
You can check (and follow) the containers logs by running the following in the project root directory (-f for follow and Ctrl+C to stop):
|
||||
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
Any compilation or runtime errors will be logged here.
|
||||
|
||||
If you have already compiled the server and made no changes to the sources, you can simply run without the build option (however it will be cached anyways):
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
```
|
||||
|
||||
To later restart the server to apply simple configuration changes, in the project root directory run:
|
||||
|
||||
```bash
|
||||
docker compose restart server
|
||||
```
|
||||
|
||||
To shut down / take down the server, in the project root directory run:
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
The database files, build cache and config files will be persisted on the host filesystem for easy backup management.
|
||||
|
||||
### License
|
||||
|
||||
We use the AGPL 3.0 license, which can be found [here](https://www.gnu.org/licenses/agpl-3.0.en.html). Please be sure to read and understand the license. Failure to follow the guidelines outlined in the license will result in legal action. If you know or hear of anyone breaking this license, please send a report, with proof, to Red Bracket#8151, ceikry#2724, or woahscam#8535 on discord or email woahscam@hotmail.com. **We WILL NOT change the license to fit your needs.**
|
||||
|
||||
### Contact
|
||||
|
||||
**Reminder: There is no official support for setting up your own server. Do not ping/dm developers, or ask in support channels about setting up your server. Support for the live server and 2009Scape single-player is available in the Discord.**
|
||||
**Reminder: There is no official support for setting up your own server. Do not ping/dm developers, or ask in support channels about setting up your server. Support for the live server and 2009Scape single-player is available on the [2009Scape forums](https://forum.2009scape.org/).**
|
||||
|
||||
|
||||
[license-shield]: https://img.shields.io/badge/license-AGPL--3.0-informational
|
||||
|
|
@ -150,4 +270,4 @@ These credits can be spent in the 2009Scape Reward Shop. It's important to be cl
|
|||
|
||||
Testers are not the only people who can gain credits - other ways of earning credits can be found on [the 2009Scape website](https://2009scape.org/site/game_guide/credits.html).
|
||||
|
||||
Please be patient! The Credit system is not fully complete yet, so it will take a long time for credits to be awarded.
|
||||
Please be patient! The Credit system is not fully complete yet, so it will take a long time for credits to be awarded.
|
||||
1
Server/.gitignore
vendored
1
Server/.gitignore
vendored
|
|
@ -2,6 +2,7 @@ bin/**
|
|||
out/**
|
||||
data/logs/**
|
||||
data/profile/**
|
||||
data/playerstats/**
|
||||
.idea/**
|
||||
/bin
|
||||
.DS_Store**
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="[Windows] Run Server" type="BatchConfigurationType" factoryName="Batch">
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<module name="" />
|
||||
<option name="SCRIPT_NAME" value="./run-server.bat" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<CELEDT>
|
||||
<item id="2297" minAmt="3" maxAmt="3" weight="10"/>
|
||||
<item id="534" minAmt="2" maxAmt="2" weight="10"/>
|
||||
<item id="530" minAmt="5" maxAmt="5" weight="10"/>
|
||||
<item id="532" minAmt="3" maxAmt="3" weight="10"/>
|
||||
<item id="526" minAmt="4" maxAmt="4" weight="10"/>
|
||||
<item id="536" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="2436" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="2442" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="2440" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="361" minAmt="5" maxAmt="5" weight="10"/>
|
||||
</CELEDT>
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
<ObjectAction mode="remove" id="356" x="2804" y="3428" z="0"/>
|
||||
<ObjectAction mode="add" id="356" x="2804" y="3428" z="0"/>
|
||||
<ObjectAction mode="add" id="2783" x="3229" y="3254" z="0"/>
|
||||
|
||||
<ObjectAction mode="remove" id="20228" x="2537" y="3573" z="0"/>
|
||||
<ObjectAction mode="add" id="27663" x="2537" y="3573" z="0" direction="w"/>
|
||||
|
|
@ -22,7 +21,6 @@
|
|||
<ObjectAction mode="add" id="39242" x="2955" y="3273" z="0" direction="w"/>
|
||||
<ObjectAction mode="add" id="39241" x="2955" y="3274" z="0" />
|
||||
<ObjectAction mode="add" id="20987" x="2821" y="2996" z="0" direction="s"/>
|
||||
<ObjectAction mode="add" id="9472" x="3353" y="3951" z="0" direction="s"/>
|
||||
<ObjectAction mode="add" id="21301" x="2662" y="3162" z="0" direction="e"/>
|
||||
<ObjectAction mode="add" id="4176" x="2629" y="3661" z="2" type="4" direction="e"/>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"This is my own dialogue",
|
||||
"@name run.",
|
||||
"@name you cant hide from me.",
|
||||
"jajajajajaja",
|
||||
"Jajajajajaja",
|
||||
"How do i get to Varrock @name?",
|
||||
"How do i get to Camelot @name?",
|
||||
"How do i get to Taverly @name?",
|
||||
|
|
@ -21,17 +21,17 @@
|
|||
"How do i get to Yanille @name?",
|
||||
"How do i get to Catherby @name?",
|
||||
"Gotta go srry.",
|
||||
"wiggle wiggle wiggle yeah",
|
||||
"Wiggle wiggle wiggle yeah",
|
||||
"@name lookin goofy",
|
||||
"@name lookin stoopid",
|
||||
"@name lookin like a red bracket",
|
||||
"@name get yo weasel lookin ass outta here",
|
||||
"@name lookin like some sort of twocan sam",
|
||||
" /hop world 1 got a noob here!",
|
||||
"woot",
|
||||
"Woot",
|
||||
"Hows your day been @name?",
|
||||
"heyy @name :)",
|
||||
"gtg srry",
|
||||
"Heyy @name :)",
|
||||
"Gtg srry",
|
||||
"I wont answer your questions @name",
|
||||
"Stop asking questions @name",
|
||||
"Roflmao",
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
"Nice Armor @name!",
|
||||
"Nice Weapon @name!",
|
||||
"Venezuela #1",
|
||||
"2009Scape and chill @name?",
|
||||
"2009scape and chill @name?",
|
||||
"@name is my girlfriend",
|
||||
"Buying gf",
|
||||
"Bank sale pm me for info",
|
||||
|
|
@ -61,14 +61,14 @@
|
|||
"Fuckin sit @name.",
|
||||
"Error: Botting client broken tell Evilwaffles.",
|
||||
"@name bots all the time",
|
||||
"report @name",
|
||||
"apparently @name bots",
|
||||
"Report @name",
|
||||
"Apparently @name bots",
|
||||
"@name hates kermit",
|
||||
"There are no mods on to help you",
|
||||
"Report me, you wont",
|
||||
"Yes, Im botting. And?",
|
||||
"ERROR: BOTSCRIPT 404. REPORT TO BOT OWNER (Evilwaffles)",
|
||||
"flash2:wave: FUCK",
|
||||
"Flash2:wave: FUCK",
|
||||
"I love 2009Scape!",
|
||||
"Ja Ja Ja Ja",
|
||||
"This is fun!",
|
||||
|
|
@ -105,9 +105,9 @@
|
|||
"Trade me @name",
|
||||
"LOL",
|
||||
"How do I get to lumbrich",
|
||||
"bruh",
|
||||
"poggers",
|
||||
"shitpost",
|
||||
"Bruh",
|
||||
"Poggers",
|
||||
"Shitpost",
|
||||
"I wish i could find an RS Gf",
|
||||
"Where do you find runite ore @name?",
|
||||
"Where is the best coal location @name?",
|
||||
|
|
@ -135,41 +135,39 @@
|
|||
"Im not a bot",
|
||||
"Nah Im a real person",
|
||||
"Bruh are you even a real person lol?",
|
||||
"e",
|
||||
"E",
|
||||
"Hellooooo @name",
|
||||
"wc lvl @name?",
|
||||
"fletching level @name?",
|
||||
"firemaking level @name?",
|
||||
"Wc lvl @name?",
|
||||
"Fletching level @name?",
|
||||
"Firemaking level @name?",
|
||||
"Have you seen the dude in the ge?",
|
||||
"Wonderful weather today @name",
|
||||
"Lowkey drunk af rn",
|
||||
"I am so tired",
|
||||
"Wassup @name",
|
||||
"follow me @name!",
|
||||
"Follow me @name!",
|
||||
"Server goes brrrr",
|
||||
"bruh i am not a bot",
|
||||
"Bruh i am not a bot",
|
||||
"I think @name is a bot",
|
||||
"Are you a bot @name?",
|
||||
"insert spiderman meme here",
|
||||
"pot calling the kettle black etc",
|
||||
"ooh, a piece of candy",
|
||||
"Insert spiderman meme here",
|
||||
"Pot calling the kettle black etc",
|
||||
"Ooh, a piece of candy",
|
||||
"I love woodcutting",
|
||||
"Im going to go level up later",
|
||||
"I love mining shooting stars",
|
||||
" /this @name looks dumb",
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAHHHHHH!!!",
|
||||
"como estas @name",
|
||||
"Summer = always the best community manaer",
|
||||
"so how about that ceikry guy",
|
||||
"so how about that kermit dude",
|
||||
"woah is an abusive mod",
|
||||
"Como estas @name",
|
||||
"So how about that ceikry guy",
|
||||
"So how about that kermit dude",
|
||||
"Woah is an abusive mod",
|
||||
"I heard Woah and Ceikry are dating now",
|
||||
"House party in Yanille!",
|
||||
"Can i have some gp @name?",
|
||||
"Where do i find partyhats?",
|
||||
"Why do mobs drop boxes?",
|
||||
"What exp rate do you play on @name?",
|
||||
"Have you met Summer?",
|
||||
"Hey @name",
|
||||
"Hey @name",
|
||||
"Hey @name",
|
||||
|
|
@ -190,33 +188,33 @@
|
|||
"NobodyCLP has big feet",
|
||||
"Chicken tendies for dindin",
|
||||
"Spicey Chicken tendies is litty as a mf titty",
|
||||
"red bracket stinky",
|
||||
"ra ra rasputin",
|
||||
"lover of the russian queen",
|
||||
"Red bracket stinky",
|
||||
"Ra ra rasputin",
|
||||
"Lover of the russian queen",
|
||||
"Whens the next update coming out?",
|
||||
"How many players are maxed?",
|
||||
"I dont use discord @name",
|
||||
"I dont use the CC @name",
|
||||
"Why should i use discord?",
|
||||
"2009Scape is life",
|
||||
"brb gotta make dinner",
|
||||
"Brb gotta make dinner",
|
||||
"I need to go to the GE",
|
||||
"@name can i have a ge tele?",
|
||||
"lol @name shut up",
|
||||
"Lol @name shut up",
|
||||
"Where are teak trees?",
|
||||
"How do i make planks @name?",
|
||||
"Idk about that scraggley ass alex guy.",
|
||||
"Rusty? More like Crusty af lmfao.",
|
||||
"I need to sell some stuff on the ge",
|
||||
"I have so many logs to sell lol",
|
||||
"nah",
|
||||
"yes",
|
||||
"Nah",
|
||||
"Yes",
|
||||
"Where can i mine iron?",
|
||||
"Where can i mine tin?",
|
||||
"Where can i mine copper?",
|
||||
"Where can i mine clay?",
|
||||
"Where can i mine coal?",
|
||||
"no",
|
||||
"No",
|
||||
"We are no strangers to love",
|
||||
"You know the rules and so do I",
|
||||
"A full commitment's what I'm thinking of",
|
||||
|
|
@ -230,10 +228,10 @@
|
|||
"Never gonna make you cry",
|
||||
"Never gonna say goodbye",
|
||||
"Never gonna tell a lie and hurt you",
|
||||
"why",
|
||||
"why",
|
||||
"why",
|
||||
"why",
|
||||
"Why",
|
||||
"Why",
|
||||
"Why",
|
||||
"Why",
|
||||
"Why does it not show your messages in the chatbox?",
|
||||
"Why do you not show up in chat?",
|
||||
"Why do you not show up in chat @name?",
|
||||
|
|
@ -241,7 +239,7 @@
|
|||
"When did you start playing @name?",
|
||||
"When did you start on this server @name?",
|
||||
"When did you first get here @name?",
|
||||
"russias greatest love machine",
|
||||
"Russias greatest love machine",
|
||||
"Never gonna run around and desert you",
|
||||
"Two things are infinite, the universe & @names stupidity",
|
||||
"If you tell the truth, you dont have to remember anything.",
|
||||
|
|
@ -259,7 +257,7 @@
|
|||
"What do you think @name?",
|
||||
"How does that sound @name?",
|
||||
"That sounds great @name.",
|
||||
"I’m learning English.",
|
||||
"I'm learning English.",
|
||||
"I don't understand.",
|
||||
"Could you repeat that please @name?",
|
||||
"Could you please talk slower @name?",
|
||||
|
|
@ -283,26 +281,26 @@
|
|||
"@name?",
|
||||
"@name how long have you played",
|
||||
"@name world 1 or world 2?",
|
||||
"what is your main world @name?",
|
||||
"What is your main world @name?",
|
||||
"I prefer world 1 tbh",
|
||||
"I prefer world 2 tbh",
|
||||
"@name world 1 for life",
|
||||
"@name fog bots when?",
|
||||
"damn somalian pirates",
|
||||
"bracket more like brrrrrr acket",
|
||||
"why the racket bracket",
|
||||
"Damn somalian pirates",
|
||||
"Bracket more like brrrrrr acket",
|
||||
"Why the racket bracket",
|
||||
"Hi @name I am dad",
|
||||
"@name likes dad jokes",
|
||||
"ur nuts @name",
|
||||
"lootshare go brr",
|
||||
"partay with froggay",
|
||||
"Ur nuts @name",
|
||||
"Lootshare go brr",
|
||||
"Partay with froggay",
|
||||
"Know what else is lame? Not being able to play 2009scape right now",
|
||||
"Can you even grind on osrs",
|
||||
"i botted to 88 fishing",
|
||||
"I botted to 88 fishing",
|
||||
"Do not forget to vote in running polls!",
|
||||
"Always check announcments",
|
||||
"we thrivin",
|
||||
"ship @name",
|
||||
"We thrivin",
|
||||
"Ship @name",
|
||||
"Dont forget to vote 2009scape!",
|
||||
"Kermit is too legit 2 quit",
|
||||
"Out here on the range we are having fun",
|
||||
|
|
@ -312,11 +310,11 @@
|
|||
"I dont like him @name",
|
||||
"I dont like it @name",
|
||||
"Im an American.",
|
||||
"ima go pickup my lady ting",
|
||||
"that portuguese dude is something else",
|
||||
"Ima go pickup my lady ting",
|
||||
"That portuguese dude is something else",
|
||||
"@name!! @name!!",
|
||||
"bowdi boy",
|
||||
"i love bowdi... sometimes",
|
||||
"Bowdi boy",
|
||||
"I love bowdi... sometimes",
|
||||
"@name = @name",
|
||||
"I'm bacon.. go on dad... say it",
|
||||
"I'm going to leave.",
|
||||
|
|
@ -340,7 +338,7 @@
|
|||
"I couldn't agree more @name",
|
||||
"It cost me a fortune @name",
|
||||
"I am dog tired",
|
||||
"Don’t take it personally",
|
||||
"Don't take it personally",
|
||||
"We will be having a good time",
|
||||
"Same as always @name",
|
||||
"No problem",
|
||||
|
|
@ -361,41 +359,24 @@
|
|||
"Guthiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxx!!!!!!",
|
||||
"530 gang for life",
|
||||
"@name, have you read the rules?",
|
||||
"@name, have you checked out the Discord?",
|
||||
"why are the leprechauns moving?",
|
||||
"@name, have you checked out the forums?",
|
||||
"Why are the leprechauns moving?",
|
||||
"I am beyond the point of no return!",
|
||||
"Nothin' personnel, kid.",
|
||||
"All your base are belong to us",
|
||||
"May Guthix bring you balance.",
|
||||
"May Guthix bring you balance.",
|
||||
"May Guthix bring you balance.",
|
||||
"Thy death was not in vain, for it brought some balance to the world. May Guthix bring you rest.",
|
||||
"May you walk the path, and never fall, for Guthix walks beside thee on thy journey. May Guthix bring you peace.",
|
||||
"All things must end, as all begin; Only Guthix knows the role thou must play. May Guthix bring you balance.",
|
||||
"In life, in death, in joy, in sorrow: May thine experience show thee balance. May Guthix bring you balance.",
|
||||
"Thou must do as thou must, no matter what. Thine actions bring balance to this world. May Guthix bring you balance.",
|
||||
"The river flows, the sun ignites, May you stand with Guthix in thy fights. May Guthix bring you balance.",
|
||||
"A journey of a single step, May take thee over a thousand miles. May Guthix bring you balance.",
|
||||
"Zamorak give me strength!",
|
||||
"Zamorak give me strength!",
|
||||
"Zamorak give me strength!",
|
||||
"May your bloodthirst never be sated, and may all your battles be glorious. Zamorak bring you strength.",
|
||||
"There is no opinion that cannot be proven true...by crushing those who choose to disagree with it. Zamorak give me strength!",
|
||||
"Battles are not lost and won; They simply remove the weak from the equation. Zamorak give me strength!",
|
||||
"Those who fight, then run away, shame Zamorak with their cowardice. Zamorak give me strength!",
|
||||
"Battle is by those who choose to disagree with it. Zamorak give me strength!",
|
||||
"Strike fast, strike hard, strike true: The strength of Zamorak will be with you. Zamorak give me strength!",
|
||||
"The weak deserve to die, so the strong may flourish. This is the creed of Zamorak.",
|
||||
"This is Saradomin's wisdom.",
|
||||
"This is Saradomin's wisdom.",
|
||||
"This is Saradomin's wisdom.",
|
||||
"Go in peace in the name of Saradomin; may his glory shine upon you like the sun.",
|
||||
"Thy cause was false, thy skills did lack; See you in Lumbridge when you get back.",
|
||||
"Protect your self, protect your friends. Mine is the glory that never ends. This is Saradomin's wisdom.",
|
||||
"The darkness in life may be avoided, by the light of wisdom shining. This is Saradomin's wisdom.",
|
||||
"Show love to your friends, and mercy to your enemies, and know that the wisdom of Saradomin will follow. This is Saradomin's wisdom.",
|
||||
"A fight begun, when the cause is just, will prevail over all others. This is Saradomin's wisdom.",
|
||||
"The currency of goodness is honour; It retains its value through scarcity. This is Saradomin's wisdom.",
|
||||
"For Camelot!",
|
||||
"Firmly grasp it!",
|
||||
"My legs!",
|
||||
|
|
@ -412,7 +393,7 @@
|
|||
"Fluff",
|
||||
"Bwuh",
|
||||
"I'm literally just mothin' bro",
|
||||
"Certified 2009scape classic.",
|
||||
"Certified 2009Scape Classic.",
|
||||
"Make sure to like, comment and subscribe @name it really helps",
|
||||
"Real 2009scape hours!!! Murder that like if you up!!!!",
|
||||
"W00t!",
|
||||
|
|
@ -426,32 +407,32 @@
|
|||
"Drip check",
|
||||
"Uhuhuhuhuhuhuhuhu",
|
||||
"Ahhhhhhhhhhhhhhhh",
|
||||
"yall got any deez?",
|
||||
"Yall got any deez?",
|
||||
"Deez nuts",
|
||||
"When she give you that yoinky sploinky",
|
||||
"Sir, this is a 2009scape.",
|
||||
"Sir, this is a 2009Scape.",
|
||||
"Oh dear! You are dead!",
|
||||
"Cor blimey, mate! What are ye doing in me pockets?",
|
||||
"yeah i got funnies",
|
||||
"read muv luv",
|
||||
"Yeah i got funnies",
|
||||
"Read muv luv",
|
||||
"Why doesn't she love me bros?",
|
||||
"@name is off the goop don't listen to the clown",
|
||||
"do yall got laptops",
|
||||
"cfunny play the alien warp sound effect",
|
||||
"Do yall got laptops",
|
||||
"Cfunny play the alien warp sound effect",
|
||||
"Ware to all whom doom hither, where cope is all yet constant.",
|
||||
"Who wants to come G W D?",
|
||||
"How do I make money?",
|
||||
"Ironmen stand alone together!",
|
||||
"based",
|
||||
"where is she",
|
||||
"Based",
|
||||
"Where is she",
|
||||
"*S N I I I I I I I I I F F F F F F F F F F F*",
|
||||
"Hey @name, who was in Paris?",
|
||||
"Huh whuh?",
|
||||
"who's lone?",
|
||||
"who *is* he?",
|
||||
"Who's lone?",
|
||||
"Who *is* he?",
|
||||
"Hi @name, I'm Dad!",
|
||||
"anyone wanna play melty blood after I high alch these bows?",
|
||||
"buru nyaaaa",
|
||||
"Anyone wanna play melty blood after I high alch these bows?",
|
||||
"Buru nyaaaa",
|
||||
"Number 15, Taverley Dungeon Black Dragons.",
|
||||
"House party at Rimmington! Host: @name!",
|
||||
"Spending 200m! Trade me, no junk!",
|
||||
|
|
@ -461,19 +442,19 @@
|
|||
"Nice outfit @name, does it come in children's size 12?",
|
||||
":)",
|
||||
":D",
|
||||
"die screaming",
|
||||
"Die screaming",
|
||||
"Only on Tuesdays",
|
||||
"we stan 2009scape",
|
||||
"We stan 2009scape",
|
||||
"There is no spoon",
|
||||
"Where's the cow level?",
|
||||
"Join 2009scape Clan Chat!",
|
||||
"Join 2009scape Cc!",
|
||||
"Chop chop!",
|
||||
"Runescape rox my sox!!!!!!1",
|
||||
"2009Scape rox my sox!!!!!!1",
|
||||
"Type ::scripts for all 99s",
|
||||
"Help I just died to Evil Chicken and I lost my stuff!",
|
||||
"Can you fight Bandos in this game?",
|
||||
"one bad gloop",
|
||||
"One bad gloop",
|
||||
"@name is not cute or funny",
|
||||
"You have committed crimes against Gielinor and her people. What say you?",
|
||||
"Barrows trauma",
|
||||
|
|
@ -488,7 +469,7 @@
|
|||
"Praise Andrew Gower",
|
||||
"Please help me I can't stop playing 2009scape",
|
||||
"Are you ignoring me, @name?!",
|
||||
"i agree with this rfc can we put it in the game please",
|
||||
"I agree with this rfc can we put it in the game please",
|
||||
"@name, we've been trying to reach you about your car's extended warranty",
|
||||
"Trimming armour, 25k gp",
|
||||
"Hey why does my furniture disappear?",
|
||||
|
|
@ -498,21 +479,525 @@
|
|||
"Shlisshalpshlaap",
|
||||
"Somebody call for an exterminator?",
|
||||
"Decisive action. Should work.",
|
||||
"R E A D Y T O R A I S E S O M E H E L L",
|
||||
"Darkness overpowering.",
|
||||
"Got any questions about propane? Or propane accessories?",
|
||||
"When someone asks me if I am a god, I say Y E S!!!",
|
||||
"You run out of Marines?",
|
||||
"Goliath Online",
|
||||
"I'm escaping to the one place that hasn't been corrupted by Capitalism. Lunar Isle!",
|
||||
"Selling wildy protection, 100k gp",
|
||||
"Can’t we get you on Mastermind, @name? Next contestant – @name from Lumbridge. Special subject – the bleedin’ obvious.",
|
||||
"Oh, you’re German! I’m sorry, I thought there was something wrong with you.",
|
||||
"Listen, don’t mention the war! I mentioned it once, but I think I got away with it all right.",
|
||||
"Can't we get you on Mastermind, @name?",
|
||||
"Listen, don't mention the war! I mentioned it once, but I think I got away with it all right.",
|
||||
"Cunnilingus and psychiatry brought us to this.",
|
||||
"Oh, poor baby. What do you want, a Brimstail's Sampler?",
|
||||
"There's an old TzHarrian saying, you fuck up once, you lose two teeth.",
|
||||
"The lineup consisted simply of six hydrocoptic marzelvanes so fitted to the ambifacient lunar waneshaft that sidefumbling was prevented."
|
||||
"Ah, the Wilderness... where dreams of riches meet a swift demise.",
|
||||
"Who needs a quest guide? I've got the whole wiki memorized.",
|
||||
"Buying GF 10k coins. Must have at least 70 Agility.",
|
||||
"I swear, the goblins in Goblin Village have it out for me.",
|
||||
"Why do wizards always hang out in towers? Is it a zoning thing?",
|
||||
"I'm training my Construction skill. My house is gonna be lit!",
|
||||
"The GE is like the stock market, but with dragon bones.",
|
||||
"Why do we need a cabbage patch in Draynor? Seriously.",
|
||||
"I've been mining rune essence for hours. My pickaxe hates me.",
|
||||
"@name hit 99 Cooking. Time to open a gourmet restaurant in Varrock.",
|
||||
"I'm convinced the @name is actually a time-traveling wizard.",
|
||||
"Anyone up for a Castle Wars match? I need that decorative armor.",
|
||||
"Accidentally clicked Attack on a guard. Now I'm a wanted criminal.",
|
||||
"Why do we even have a Duel Arena? It's just a fancy boxing ring.",
|
||||
"I've got a stack of burnt lobsters. Anyone want to buy them?",
|
||||
"Greetings, @name! Looking for a quest?",
|
||||
"Just got a rare drop! The RNG gods are smiling upon me!",
|
||||
"Anyone need help with a boss fight? I've got my dragon dagger ready.",
|
||||
"Buying feathers! Will pay top price!",
|
||||
"The Lumbridge cows are my favorite training spot.",
|
||||
"Who needs a teleport? I've got my magic runes stocked.",
|
||||
"@name hit 99 Woodcutting. Time to chop some yews!",
|
||||
"Anyone seen the Wise Old Man lately? I owe him a visit.",
|
||||
"Selling lobsters! Freshly caught from Catherby.",
|
||||
"Swear, the Wilderness is scarier than my nightmares.",
|
||||
"Looking for a clan to join. Any takers?",
|
||||
"I'm an ironman, so no trading for me!",
|
||||
"Anyone up for a Castle Wars match?",
|
||||
"The Grand Exchange prices are crashing. Panic sell!",
|
||||
"Who else remembers the Falador Massacre?",
|
||||
"I'm saving up for a party hat. Wish me luck!",
|
||||
"Barrows runs are my addiction. Those crypts are spooky.",
|
||||
"I'm convinced the Wise Old Man is secretly Zamorak.",
|
||||
"I'm a completionist, so I'm grinding out all the achievements.",
|
||||
"The music in this game is surprisingly epic.",
|
||||
"Tried to trade with a tree... It didn't go well.",
|
||||
"My bank is like a black hole. Items disappear forever.",
|
||||
"I'm convinced the Wise Old Man is just a confused tourist.",
|
||||
"My character's fashion sense? Let's just say it's 'unique.'",
|
||||
"Challenged a cow to a dance-off. It won.",
|
||||
"Why does the Lumbridge Guide always look so lost?",
|
||||
"I'm training Agility, but my real-life agility is zero.",
|
||||
"Tried to fish in the desert. Sandfish are elusive.",
|
||||
"The Grand Exchange is like a chaotic stock market.",
|
||||
"I'm a master at clicking 'Continue' during quests.",
|
||||
"I'm convinced the chickens are plotting world domination.",
|
||||
"I'm a woodcutter, but I've never seen a talking tree.",
|
||||
"I'm a vegetarian, except when it comes to killing dragons.",
|
||||
"Why do wizards wear pointy hats? Is it a fashion statement?",
|
||||
"Challenged a guard to a staring contest. He won.",
|
||||
"I'm collecting cabbage. It's a noble pursuit.",
|
||||
"Accidentally set my cat on fire. It's now a firecat.",
|
||||
"I'm convinced the Wise Old Man is secretly a time traveler.",
|
||||
"I'm a quest completionist, but I still can't find my keys.",
|
||||
"I'm convinced the ducks are spying on us.",
|
||||
"I'm a pro at avoiding the Lumbridge swamp. Too many frogs.",
|
||||
"Hey, can someone lend me 10k? I promise I'll pay it back... eventually.",
|
||||
"Why do I always find the one square where the random event spawns?",
|
||||
"I'm training Prayer by burying bones. It's like a spiritual workout.",
|
||||
"The Wise Old Man's fashion sense is questionable.",
|
||||
"I'm convinced the ducks are secretly plotting world domination.",
|
||||
"Why do wizards wear pointy hats? Is it a dress code?",
|
||||
"I'm collecting cabbage. It's a noble pursuit, really.",
|
||||
"I'm a vegetarian, except when it comes to killing dragons.",
|
||||
"Why does the Lumbridge Guide always look so lost?",
|
||||
"Training Agility, but my real-life agility is zero.",
|
||||
"I'm convinced the Wise Old Man is secretly a time traveler.",
|
||||
"Tried to mine air. It's an untapped resource.",
|
||||
"I'm a quest completionist, but I still can't find my keys.",
|
||||
"Challenged a guard to a staring contest. He won.",
|
||||
"I'm saving up for a party hat. Priorities, you know?",
|
||||
"Why do goblins drop coins? Do they moonlight as accountants?",
|
||||
"I'm convinced the chickens are plotting something.",
|
||||
"Clicked 'Attack' on a chicken. Now I'm a poultry murderer.",
|
||||
"My character's fashion sense? Let's just say it's 'unique.'",
|
||||
"Do you know where I can find the entrance to the Taverley Dungeon?",
|
||||
"Hey, anyone here familiar with the Barrows? I need some tips.",
|
||||
"Is there a bank nearby? My inventory is overflowing with loot",
|
||||
"I'm clueless about clue scrolls",
|
||||
"Where's the best spot to catch sharks? I'm aiming for 99 Fishing.",
|
||||
"Is there a shortcut to the Karamja Volcano?",
|
||||
"Can someone explain the mechanics of the Jad fight in the Fight Caves?",
|
||||
"I'm stuck on the Elemental Workshop quest. Any hints?",
|
||||
"Where can I find a loom to spin flax into bowstrings?",
|
||||
"What's the best gear setup for killing dragons? I want that visage drop!",
|
||||
"I'm trying to unlock the fairy rings",
|
||||
"How do I recharge my amulet of glory?",
|
||||
"Why do goblins drop coins?",
|
||||
"The Grand Exchange is like the stock market",
|
||||
"My real-life agility is more like a lumbering tortoise.",
|
||||
"The Wise Old Man's fashion sense is like Woahs",
|
||||
"I challenged a cow to a dance off, surprisingly smooth mooves.",
|
||||
"Why does the Lumbridge Guide always look lost?",
|
||||
"I'm convinced the ducks in Lumbridge are plotting world domination!",
|
||||
"I accidentally ate my prayer potion I'm blessed with heartburn",
|
||||
"I'm a vegetarian, except when it comes to slaying dragons.",
|
||||
"Why do wizards wear pointy hats? Is it a magical dress code?",
|
||||
"I'm a quest completionist, but I still can't find my keys in real life.",
|
||||
"I challenged a guard to a staring contest. He won.",
|
||||
"I'm saving up for a party hat. Priorities, ya know?",
|
||||
"What's the deal with the Wilderness?",
|
||||
"I'm convinced the chickens are secretly plotting world domination!",
|
||||
"Accidentally clicked 'Attack' on a guard. Now I'm on a watchlist.",
|
||||
"My character's fashion sense? Let's just say it's 'unique'",
|
||||
"Lobsters heal my soul",
|
||||
"Trimmed armor or bust!",
|
||||
"Wilderness: Where friendships go to die",
|
||||
"Buying gf 10k",
|
||||
"Dancing for coins at Lumbridge",
|
||||
"Wearing full rune like a boss",
|
||||
"Teleporting to Camelot for quests",
|
||||
"Fishing for hours at Catherby",
|
||||
"PKing with a rune 2h",
|
||||
"World 1 Falador Park parties",
|
||||
"Staking my bank at the Duel Arena",
|
||||
"Dying to Elvarg's fiery breath sums up my life",
|
||||
"Got the Quest cape finally on my main!",
|
||||
"Wearing a party hat with pride",
|
||||
"Castle Wars: Red vs Blue",
|
||||
"Trading in Varrock Square",
|
||||
"Barrows runs for that sweet loot",
|
||||
"Spending hours in Pest Control is life",
|
||||
"Killing cows for leather armor is a good start",
|
||||
"Farming herbs in Ardougne can be good money",
|
||||
"Clan chat drama LOL",
|
||||
"Mining rune essence endlessly",
|
||||
"Agility courses: A love-hate relationship",
|
||||
"Dueling for honor.... and GP",
|
||||
"Buying runes from Aubury is decent money",
|
||||
"Chasing the Easter Bunny like a scam",
|
||||
"Wearing a skillcape with pride",
|
||||
"Fletching yew longbows for profit",
|
||||
"Going to implings in Puro-Puro",
|
||||
"Castle Wars barricade wars",
|
||||
"Dropping party hats at drop parties like pennies",
|
||||
"Killing lesser demons in Karamja is part of my holy conquest",
|
||||
"@name lures noobs into the Wilderness",
|
||||
"Farming ranarrs for cash",
|
||||
"Getting lost in the Underground Pass",
|
||||
"Selling coal at the Grand Exchange",
|
||||
"Fighting the Kalphite Queen",
|
||||
"Picking flax in Seers' Village",
|
||||
"Begging for free stuff in Lumbridge",
|
||||
"Smithing rune platebodies for profit",
|
||||
"Logging out in Lumbridge Castle",
|
||||
"Hey @name, how do I get to the Grand Exchange?",
|
||||
"Veteran here! @name, what's your favorite quest?",
|
||||
"@name, how do I make money fast?",
|
||||
"Hey @name, what's the best combat style for bossing?",
|
||||
"@name, always carry an emergency teleport!",
|
||||
"New player here! @name, what's the Wilderness like?",
|
||||
"Hey @name, how do I join a clan?",
|
||||
"@name, prioritize Prayer levels!",
|
||||
"@name, what's the best way to train Agility?",
|
||||
"Hey @name, what's your favorite minigame?",
|
||||
"@name, never trust a PKer in Lumbridge!",
|
||||
"@name, how do I get a fire cape?",
|
||||
"Hey @name, what's the fastest way to level up Magic?",
|
||||
"@name, try the Barrows tunnels!",
|
||||
"@name, what's the deal with Pest Control?",
|
||||
"Hey @name, how do I unlock the Fairy Rings?",
|
||||
"@name, remember the old random events?",
|
||||
"@name, should I train Strength or Attack first?",
|
||||
"Hey @name, what's your favorite skillcape?",
|
||||
"@name, can't do the Fight Caves!",
|
||||
"@name, how do I get a pet?",
|
||||
"Hey @name, what's the best food for boss fights?",
|
||||
"@name, Castle Wars or Clan Wars?",
|
||||
"@name, what's a clue scroll?",
|
||||
"Hey @name, how do I defeat Jad?",
|
||||
"@name, use Protect from Melee at KBD!",
|
||||
"@name, should I train Ranged or Magic?",
|
||||
"Hey @name, what's the best way to level up Crafting?",
|
||||
"@name, don't forget your anti-dragon shield!",
|
||||
"@name, what's the Stronghold of Security?",
|
||||
"Hey @name, how do I access the Legends' Guild?",
|
||||
"@name, remember the old PvP worlds?",
|
||||
"@name, how do I get a dragon defender?",
|
||||
"Hey @name, what's the best way to level up Herblore?",
|
||||
"@name, always carry a charged amulet of glory!",
|
||||
"@name, should I train Fishing or Cooking?",
|
||||
"Hey @name, how do I defeat the Chaos Elemental?",
|
||||
"@name, try the TzHaar Fight Pit!",
|
||||
"@name, what's the best way to level up Smithing?",
|
||||
"Hey @name, what's your favorite Slayer master?",
|
||||
"@name, use the Ardougne cloak teleports!",
|
||||
"@name, what's the Legends' Quest about?",
|
||||
"Hey @name, how do I unlock the Ancient Magicks?",
|
||||
"@name, remember the old Pest Control boats?",
|
||||
"@name, what's the best way to level up Construction?",
|
||||
"Hey @name, what's the fastest way to level up Prayer?",
|
||||
"@name, the old Duel Arena stakes!",
|
||||
"@name, what's the Warriors' Guild?",
|
||||
"Hey @name, how do I defeat the Kalphite Queen?",
|
||||
"@name, use the fairy ring code BIP!",
|
||||
"@name, should I train Attack or Defense first?",
|
||||
"Hey @name, what's the best way to level up Thieving?",
|
||||
"@name, don't forget your charged glory amulet!",
|
||||
"@name, what's the Legends' Cape?",
|
||||
"Hey @name, how do I access the Heroes' Guild?",
|
||||
"@name, remember the old Pest Control void gear?",
|
||||
"@name, how do I get a firemaking skillcape?",
|
||||
"Buying gf 10k",
|
||||
"Trimming armor for free!",
|
||||
"Wanna join my clan? We're called The Mighty Cabbages'!",
|
||||
"I'll meet you at the Falador Party Room!",
|
||||
"Dancing for coins in Varrock Square!",
|
||||
"Remember when the Wilderness was dangerous?",
|
||||
"I got a rune scimitar drop from Lesser Demons!",
|
||||
"Lumbridge Swamp is haunted!",
|
||||
"Anyone up for Castle Wars?",
|
||||
"I miss the old random events!",
|
||||
"World 2 is the trading hub!",
|
||||
"I'm going to train my Agility at the Gnome Stronghold!",
|
||||
"I just got 99 Cooking!",
|
||||
"Fishing lobsters at Catherby is life!",
|
||||
"The Legends' Guild is so exclusive!",
|
||||
"Who needs a quest guide? I'll figure it out!",
|
||||
"I'm mining rune essence for hours!",
|
||||
"Barrows armor looks sick!",
|
||||
"I'm stuck in the Underground Pass!",
|
||||
"The Stronghold of Security taught me about account security!",
|
||||
"I'm going to farm herbs in Ardougne!",
|
||||
"I'm getting my fire cape!",
|
||||
"I love the music in RuneScape!",
|
||||
"I'm alching my maple longbows!",
|
||||
"I'm doing the Recipe for Disaster subquests!",
|
||||
"I'm going to train my combat stats at the Rock Crabs!",
|
||||
"I'm going for the Quest Cape!",
|
||||
"I'm going to mine pure essence!",
|
||||
"I'm hunting chinchompas in the Feldip Hills!",
|
||||
"I'm going to train my Woodcutting at Seers' Village!",
|
||||
"I'm going to fish sharks at the Fishing Guild!",
|
||||
"I'm going to train my Thieving at Ardougne Knights!",
|
||||
"I'm going to hunt implings in Puro-Puro!",
|
||||
"I'm going to train my Hunter at the Falconry!",
|
||||
"I'm smithing rune platebodies!",
|
||||
"I'm going to train my Farming at the Tree Gnome Stronghold!",
|
||||
"I'm going to hunt red chinchompas in the Wilderness!",
|
||||
"I'm doing the Underground Pass quest!",
|
||||
"I'm going to fish monkfish in Piscatoris!",
|
||||
"Meet me in Varrock, @name, for an epic trade",
|
||||
"@name, join my clan; we'll conquer the Wilderness together!",
|
||||
"Beware the dragons, @name, they're fiercer than you think",
|
||||
"Crafting runes with @name, the best mage in Gielinor",
|
||||
"Fishing lobsters with @name, the sea's no match for us",
|
||||
"@name, your swordsmanship at Duel Arena is unmatched!",
|
||||
"Questing through dark caves, @name always leads the way",
|
||||
"Share your wisdom, @name, how'd you master those spells?",
|
||||
"Legends speak of @name bravery at the God Wars",
|
||||
"Need more arrows, @name? I've got plenty to spare",
|
||||
"Cooking's a breeze when @name around, no burnt lobsters!",
|
||||
"Mining together, @name and I strike gold every time",
|
||||
"@name, let's barter; your herbs for my potions?",
|
||||
"Training agility with @name, leaping like graceful gazelles",
|
||||
"Heard @name got the best magic beans in town",
|
||||
"Fletching bows with @name, aiming for perfection",
|
||||
"Smithing with @name, our anvils never cool down",
|
||||
"Adventuring with @name, every quest is a thrill",
|
||||
"Battling demons, @name courage inspires us all",
|
||||
"Slaying dragons, @name the hero we need",
|
||||
"Gathering at Falador, @name party room is legendary",
|
||||
"Hunting chinchompas, @name traps are always full",
|
||||
"Farming's fun with @name, our crops never fail",
|
||||
"Brewing potions, @name mixtures are magical",
|
||||
"Casting spells with @name, we're invincible",
|
||||
"Building fires, @name flames warm the coldest nights",
|
||||
"Sailing to Pest Control, @name our fearless captain",
|
||||
"Trading runes, @name deals are the fairest",
|
||||
"Exploring dungeons, @name the light in the darkness",
|
||||
"Charging orbs with @name, our energy knows no bounds",
|
||||
"Dancing in Draynor, @name moves are enchanting",
|
||||
"Playing Gnomeball, @name the star player",
|
||||
"Harvesting willows, @name axe swings true",
|
||||
"Enchanting jewelry, @name touch turns copper to gold",
|
||||
"Summoning familiars, @name spirit wolf leads the pack",
|
||||
"Thieving from stalls, @name hands are lightning-fast",
|
||||
"Crafting runes, @name essence never runs dry",
|
||||
"Fishing at Catherby, @name catch feeds us all",
|
||||
"Cooking feasts, @name dishes delight the gods",
|
||||
"Mining runite, @name pickaxe strikes rich veins",
|
||||
"Bartering at Grand Exchange, @name a trading master",
|
||||
"Training prayer, @name piety moves mountains",
|
||||
"Fighting revenants, @name valor shines bright",
|
||||
"Building homes, @name construction is flawless",
|
||||
"Hunting imps, @name net is always full",
|
||||
"Brewing ale, @name tavern is the town's favorite",
|
||||
"Casting high alchemy, @name turns junk into treasure",
|
||||
"Sailing to Karamja, @name adventures are legendary",
|
||||
"Forging alliances, @name charisma unites clans",
|
||||
"Defeating bosses, @name name echoes in legends",
|
||||
"Are you mewing @name???",
|
||||
"Check out that gyatt @name",
|
||||
"Bruhhhhh @name got that rizz",
|
||||
"@name rizzing up the bots",
|
||||
"Ironman? More like copperboy LOL",
|
||||
"What that gyatt do @name",
|
||||
"He's got the zoomies!",
|
||||
"@name likes pickles and dipped in mayo",
|
||||
"Lmaaooooooo",
|
||||
"Bruh she said she loved me...",
|
||||
"I caught @name rizzing a mewing teacher",
|
||||
"What that mouth do bb",
|
||||
"Ayo tf he say",
|
||||
"Ayo",
|
||||
"Ayo @name a freak lowkey",
|
||||
"Ayo tf",
|
||||
"@name catch me outside howbout that",
|
||||
"Wasssssuuuuppppppp",
|
||||
"Knock knock @name",
|
||||
"Oh boy howdy do i have a surprise for you",
|
||||
"Noooooo",
|
||||
"What do you mean I haven't done anything wtf",
|
||||
"Redrocket redrocket!!!",
|
||||
"I made 20,000 crochet sock puppets for ceikry",
|
||||
"Come on @name",
|
||||
"Are we rading tonight @name?",
|
||||
"Why would he say that",
|
||||
"Penguins are technically reptiles",
|
||||
"Brb smell something burning",
|
||||
"Need pest control partner, you handle the portals, i will afk",
|
||||
"Bruhhhh the skibiddi rizz in my gyatt makes my mewing sesh rough",
|
||||
"@name jajajajaja",
|
||||
"Wait, I can't raid tonight @name",
|
||||
"Brb, pizza's here. Hope they ask why I'm a grown man dressed like an elf",
|
||||
"Sorry, gotta go AFK. My dog just ate my gaming headset.",
|
||||
"Brb, my grandma just fell down the stairs",
|
||||
"Hold on, the baby's crying, aka @name",
|
||||
"Oops, spilled my drink",
|
||||
"Guys, I need to log off, my plants are staging a revolt for not watering them",
|
||||
"AFK a sec, my neighbor's llama is in my backyard again",
|
||||
"My pizza rolls are ready",
|
||||
"Lost track of time, i'm late for my own wedding",
|
||||
"Sorry, can't hear you over the sound of my laundry",
|
||||
"Turn HDR off in windows @name",
|
||||
"Www. no one cares .com",
|
||||
"Hey @name www dot stfu dot com",
|
||||
"Like pitching a tent in a pair of britches",
|
||||
"Mad as a bag of ferrets",
|
||||
"I dont think beavers built the hoover dam",
|
||||
"How do beavers get the concrete for dams?",
|
||||
"@name show me the way",
|
||||
"@name onwards brutha",
|
||||
"@name eats fried rat tails",
|
||||
"@name is a rat",
|
||||
"Why are there so many people farming right now",
|
||||
"@name fuck the police",
|
||||
"@name says the like pickles on their hotdogs",
|
||||
"Fuck the guards, free woah in varrock prison",
|
||||
"Ayo fuck u mean",
|
||||
"Woop woop thats da sound of the beast",
|
||||
"How are you the way that you are",
|
||||
"She sells seashells by the sea shore",
|
||||
"@name certified rat",
|
||||
"@name buys skimmed milk",
|
||||
"Got milk?",
|
||||
"Are you JSON because i want you to get array from me",
|
||||
"@name likes string manipulation",
|
||||
"@name sells legos",
|
||||
"JUST DO IT",
|
||||
"Why are there so many motherfucking options",
|
||||
"Just hit the fucking auto hide thing",
|
||||
"Just play",
|
||||
"Hell no this shit is fuzzy as balls",
|
||||
"@name is fuzzy as balls",
|
||||
"Turn your brightness up @name",
|
||||
"On my pc it runs perfectly",
|
||||
"I know why mine seems a little jumpy",
|
||||
"Stream the window not the monitor",
|
||||
"Discords a bitch",
|
||||
"Why are there so many handsome people at the ge like @name",
|
||||
"I'll make you squeel of fortune",
|
||||
"You will get it in due time @name",
|
||||
"I was one turn away",
|
||||
"It do be pipe time @name",
|
||||
"Sometimes i like to cover myself in vaseline and pretend i'm a slug",
|
||||
"Woah is a greased pig",
|
||||
"Sometimes i dig holes in my backyard and pretend i'm a carrot",
|
||||
"It's pipe time @name",
|
||||
"If i am not pipe timing i am programming",
|
||||
"Yes i have thigh high socks, no you cannot have them",
|
||||
"I scream when i wear my programming socks",
|
||||
"Anyone wanna buy @name's bathwater?",
|
||||
"Anyone wanna buy my used socks?",
|
||||
"@name be getting bags",
|
||||
"What the fuck is this",
|
||||
"Hi i noticed you haven't taken a break in hours @name",
|
||||
"I really am seething rn",
|
||||
"I am so fucking tilted",
|
||||
"Go back to your fucking frogs",
|
||||
"Life is simple as frog farmer",
|
||||
"A q p",
|
||||
"Oooooh that's a first",
|
||||
"Been a minute @name",
|
||||
"Hey @name",
|
||||
"Oh shit it's @name",
|
||||
"Hey @name wyd today?",
|
||||
"Ayo @name",
|
||||
"Wyd @name",
|
||||
"Wbu @name?",
|
||||
"Good fuck em, that's what they get",
|
||||
"Deathknight lookin rat ass mf @name",
|
||||
"@name sucks slugs",
|
||||
"Brb gotta take a shit",
|
||||
"@name will brb went to take a shit",
|
||||
"Tell me when he is coming",
|
||||
"This guy is being incredibly based",
|
||||
"@name is based af",
|
||||
"Taking l's all day today @name",
|
||||
"That sucks massive dongus",
|
||||
"Ah i was about to type that",
|
||||
"Where is stormwind?",
|
||||
"How do i buy gold",
|
||||
"@name sells gold",
|
||||
"@name is a gold digger",
|
||||
"Ayo @name wanna buy some frog legs?",
|
||||
"Brb fucking burnt my pizza rolls",
|
||||
"I swear @name if you need roll again",
|
||||
"@name you are a hunter you don't need plate armor",
|
||||
"Dragonriding is satisfying",
|
||||
"There's an old TzHarrian saying, you fuck up once, you lose two teeth",
|
||||
"FUCK",
|
||||
"@name i am ready when you are",
|
||||
"Anyone selling logs?",
|
||||
"That is hilarious @name",
|
||||
"Alright @name",
|
||||
"I need to go get my quest cape",
|
||||
"500 barrows runs dry",
|
||||
"Back to back to back barrows items, easy game",
|
||||
"@name did you know them?",
|
||||
"@name sucks eggs",
|
||||
"@name eats snails",
|
||||
"Who is that?",
|
||||
"I've gotta go in 20 minutes",
|
||||
"Bonk",
|
||||
"Gtg in 30 minutes",
|
||||
"They left 50 minutes ago",
|
||||
"I think it's just gonna be us",
|
||||
"Who is that?",
|
||||
"Stop following me",
|
||||
"@name stop following me",
|
||||
"I think @name is watching me",
|
||||
"@name wouldn't let me get a hit in at clan wars",
|
||||
"Clan wars and chill?",
|
||||
"Quick mewing sesh",
|
||||
"Don't you stickbug me",
|
||||
"Get stick bugged",
|
||||
"Wtf why are you a dragon",
|
||||
"Fun fact, woah eats eggs whole like a snake",
|
||||
"Ceikys there's a rare over there",
|
||||
"Where is goldshire?",
|
||||
"How long have you played @name?",
|
||||
"Wanna quest?",
|
||||
"TROGDORRRRRR",
|
||||
"Fuck this shit i'm out",
|
||||
"Wait till you get your first 99",
|
||||
"How is that even possible",
|
||||
"That's the max",
|
||||
"@name is trying to max",
|
||||
"Complesionist cape?",
|
||||
"How can you increase your run speed?",
|
||||
"@name where is barrows?",
|
||||
"@name where are rune rocks?",
|
||||
"@name where is yanille?",
|
||||
"@name how long have you played for?",
|
||||
"Yes these quotes were hand typed",
|
||||
"Kermit was here",
|
||||
"World of Warcraft died after Wrath",
|
||||
"Ceikry needs to add talent trees",
|
||||
"How do you get to the wilderness?",
|
||||
"Anyone tryna lure @name?",
|
||||
"@name tried to lure me",
|
||||
"@name bots all the time",
|
||||
"Anyone want chicken tendies",
|
||||
"Brb foods ready",
|
||||
"Brb",
|
||||
"Gotta go get food",
|
||||
"Anyone else from northern alaska?",
|
||||
"Fishing 4 gp",
|
||||
"Looking for gf",
|
||||
"Anyone wanna be my discord kitten?",
|
||||
"Selling discord kittens",
|
||||
"@name is a discord kitten",
|
||||
"Add me on discord",
|
||||
"Are you in the 09discord",
|
||||
"Where are you going @name?",
|
||||
"Idk what i am going to cook today",
|
||||
"What should i eat tonight",
|
||||
"He is in the cave",
|
||||
"Don't forget to save game before logging out",
|
||||
"American horror story died after season 1",
|
||||
"Prequels are better than the sequels",
|
||||
"Disney star wars is the best star wars",
|
||||
"Halo 5 sucked",
|
||||
"Selling xbox live gold and 1600 microsoft points for 50k gp",
|
||||
"Buying gf 25gp and a bucket",
|
||||
"@name i heard evilwaffles bots",
|
||||
"@name hopefully ceikry doesn't find out about evilwaffles",
|
||||
"Honk honk",
|
||||
"Where is the road to mordor?",
|
||||
"Golem lookin ass bitch",
|
||||
"@name rat looking mf",
|
||||
"@name uses sand paper to wipe",
|
||||
"@name said Woah is cute",
|
||||
"You need 25 of 40 to do that",
|
||||
"Over 1000 unique lines of dialogue",
|
||||
"What should i get to eat",
|
||||
"Ge be poppin today",
|
||||
"Where all the woahs at",
|
||||
"Ayo woahscam got that gyatt",
|
||||
"That is one i haven't seen before"
|
||||
],
|
||||
"halloween": [
|
||||
"Trick or treat!!!",
|
||||
|
|
@ -523,9 +1008,9 @@
|
|||
"Costume party at my P O H!! Follow me!",
|
||||
"Trick, then!",
|
||||
"Brrrainssssssss...",
|
||||
"'Cause this is thriller, thriller night, and no one's gonna save you from the beast about to strike!",
|
||||
"This is Hallowe'en, this is Hallowe'en, pumpkins scream in the dead of night!",
|
||||
"This is Hallowe'en, everybody make a scene, Trick or treat till the neighbors gonna die of fright!",
|
||||
"'Cause this is thriller, thriller night!",
|
||||
"This is Hallowe'en, this is Hallowe'en!",
|
||||
"This is Hallowe'en, everybody make a scene!",
|
||||
"In this town we call home, everyone hail to the pumpkin song!",
|
||||
"Watch out for Skeleton Jack!",
|
||||
"The headless-what-man? Horse? Never heard of those.",
|
||||
|
|
@ -596,7 +1081,7 @@
|
|||
"Rusty = the grinch, @name = santa",
|
||||
"@name the red nose reindeer",
|
||||
"Put one foot in front of the other",
|
||||
"and soon you will be walking out the doooor",
|
||||
"And soon you will be walking out the doooor",
|
||||
"Elf on the shelf time",
|
||||
"@name loves pinecones",
|
||||
"I love the smell of pinecones",
|
||||
|
|
@ -695,21 +1180,21 @@
|
|||
"Woah got those roofies strapped",
|
||||
"Why is my drink cloudy?",
|
||||
"@name and woah be wrestlin",
|
||||
"bekky want sum fuk?",
|
||||
"Bekky want sum fuk?",
|
||||
"Damn @name you got an ass",
|
||||
"Is that a footlong in your pants or are you happy to see me?",
|
||||
"@name so hot i gotta change my pants",
|
||||
"@name is a sex god",
|
||||
"bruh we hype today",
|
||||
"dont be silly wrap the willy @name!",
|
||||
"wrap it before you smack it @name",
|
||||
"can i get a reeeeee @name?",
|
||||
"valentines day is the best day",
|
||||
"Bruh we hype today",
|
||||
"Dont be silly wrap the willy @name!",
|
||||
"Wrap it before you smack it @name",
|
||||
"Can i get a reeeeee @name?",
|
||||
"Valentines day is the best day",
|
||||
"@name shut up before i smack you with my crusty sock",
|
||||
"Valentines day, more like me and my hand day smh",
|
||||
"If you think these quotes are wild just wait @name",
|
||||
"All im saying is we have never seen @name and biden in the same room",
|
||||
"red rocket, red rocket!",
|
||||
"Red rocket, red rocket!",
|
||||
"Woahs favourite game is red rocket",
|
||||
"@name sexy af today",
|
||||
"Happy Valentines day @name!!!",
|
||||
|
|
@ -754,4 +1239,4 @@
|
|||
"@name and i are going to look for the easter bunny!!",
|
||||
"Hint for anyone who sees this you must dig above eagles peak"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
68
Server/data/botdata/ge_bot_appearances_and_equipment.json
Normal file
68
Server/data/botdata/ge_bot_appearances_and_equipment.json
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"noob": [
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"3","id":"1265"},{"amount":"1","charge":"1000","slot":"5","id":"1171"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"0"},{"color":"0","look":"11"},{"color":"16","look":"18"},{"color":"0","look":"27"},{"color":"0","look":"34"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1169"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"9183"},{"amount":"1","charge":"1000","slot":"4","id":"1131"},{"amount":"1","charge":"1000","slot":"7","id":"2495"},{"amount":"1","charge":"1000","slot":"9","id":"2491"},{"amount":"1","charge":"1000","slot":"10","id":"88"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"106"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1163"},{"amount":"1","charge":"1000","slot":"2","id":"1725"},{"amount":"1","charge":"1000","slot":"3","id":"5698"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"10","id":"3105"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"9","look":"266"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"3","id":"1333"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"5","id":"1201"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"10","id":"11019"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"2"},{"color":"0","look":"13"},{"color":"1","look":"18"},{"color":"0","look":"28"},{"color":"0","look":"33"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"2910"},{"amount":"1","charge":"1000","slot":"1","id":"10499"},{"amount":"1","charge":"1000","slot":"2","id":"552"},{"amount":"1","charge":"1000","slot":"3","id":"861"},{"amount":"1","charge":"1000","slot":"4","id":"544"},{"amount":"1","charge":"1000","slot":"7","id":"2497"},{"amount":"1","charge":"1000","slot":"9","id":"7458"},{"amount":"1","charge":"1000","slot":"10","id":"2904"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"1007"},{"amount":"1","charge":"1000","slot":"3","id":"1381"},{"amount":"1","charge":"1000","slot":"4","id":"426"},{"amount":"1","charge":"1000","slot":"7","id":"428"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"20","look":"267"},{"color":"0","look":"12"},{"color":"0","look":"18"},{"color":"0","look":"31"},{"color":"4","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"3","id":"6908"},{"amount":"1","charge":"1000","slot":"4","id":"1135"},{"amount":"1","charge":"1000","slot":"7","id":"428"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"6","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1161"},{"amount":"1","charge":"1000","slot":"3","id":"1287"},{"amount":"1","charge":"1000","slot":"4","id":"1123"},{"amount":"1","charge":"1000","slot":"5","id":"1199"},{"amount":"1","charge":"1000","slot":"7","id":"1073"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"16"},{"color":"6","look":"18"},{"color":"0","look":"27"},{"color":"0","look":"84"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1153"},{"amount":"1","charge":"1000","slot":"3","id":"1363"},{"amount":"1","charge":"1000","slot":"4","id":"6184"},{"amount":"1","charge":"1000","slot":"5","id":"1540"},{"amount":"1","charge":"1000","slot":"7","id":"6185"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"16"},{"color":"6","look":"18"},{"color":"0","look":"27"},{"color":"0","look":"84"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"11021"},{"amount":"1","charge":"1000","slot":"1","id":"4411"},{"amount":"1","charge":"1000","slot":"2","id":"1725"},{"amount":"1","charge":"1000","slot":"3","id":"1333"},{"amount":"1","charge":"1000","slot":"4","id":"11020"},{"amount":"1","charge":"1000","slot":"5","id":"1185"},{"amount":"1","charge":"1000","slot":"7","id":"11022"},{"amount":"1","charge":"1000","slot":"10","id":"11019"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"16"},{"color":"6","look":"18"},{"color":"0","look":"27"},{"color":"0","look":"84"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1949"},{"amount":"1","charge":"1000","slot":"1","id":"1007"},{"amount":"1","charge":"1000","slot":"3","id":"1381"},{"amount":"1","charge":"1000","slot":"4","id":"426"},{"amount":"1","charge":"1000","slot":"5","id":"1540"},{"amount":"1","charge":"1000","slot":"7","id":"428"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"16"},{"color":"6","look":"18"},{"color":"0","look":"27"},{"color":"0","look":"84"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"10774"},{"amount":"1","charge":"1000","slot":"1","id":"10069"},{"amount":"1","charge":"1000","slot":"2","id":"1725"},{"amount":"1","charge":"1000","slot":"3","id":"1333"},{"amount":"1","charge":"1000","slot":"4","id":"1125"},{"amount":"1","charge":"1000","slot":"7","id":"1077"},{"amount":"1","charge":"1000","slot":"9","id":"2997"},{"amount":"1","charge":"1000","slot":"10","id":"7114"}]}
|
||||
|
||||
],
|
||||
"intermediate": [
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"3","id":"1265"},{"amount":"1","charge":"1000","slot":"5","id":"1171"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"1"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"2637"},{"amount":"1","charge":"1000","slot":"1","id":"6568"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1305"},{"amount":"1","charge":"1000","slot":"4","id":"3140"},{"amount":"1","charge":"1000","slot":"5","id":"6524"},{"amount":"1","charge":"1000","slot":"7","id":"4087"},{"amount":"1","charge":"1000","slot":"9","id":"3060"},{"amount":"1","charge":"1000","slot":"10","id":"11732"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"1"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"11674"},{"amount":"1","charge":"1000","slot":"1","id":"10720"},{"amount":"1","charge":"1000","slot":"2","id":"1725"},{"amount":"1","charge":"1000","slot":"3","id":"1387"},{"amount":"1","charge":"1000","slot":"4","id":"8839"},{"amount":"1","charge":"1000","slot":"7","id":"8840"},{"amount":"1","charge":"1000","slot":"9","id":"8842"},{"amount":"1","charge":"1000","slot":"10","id":"11732"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"261"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"16","look":"38"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"9805"},{"amount":"1","charge":"1000","slot":"4","id":"10348"},{"amount":"1","charge":"1000","slot":"10","id":"1837"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"261"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"16","look":"38"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"10392"},{"amount":"1","charge":"1000","slot":"1","id":"1007"},{"amount":"1","charge":"1000","slot":"2","id":"11113"},{"amount":"1","charge":"1000","slot":"3","id":"1387"},{"amount":"1","charge":"1000","slot":"4","id":"1117"},{"amount":"1","charge":"1000","slot":"5","id":"1173"},{"amount":"1","charge":"1000","slot":"7","id":"1075"},{"amount":"1","charge":"1000","slot":"10","id":"4129"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"3"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"3755"},{"amount":"1","charge":"1000","slot":"1","id":"2412"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1383"},{"amount":"1","charge":"1000","slot":"4","id":"4091"},{"amount":"1","charge":"1000","slot":"7","id":"4093"},{"amount":"1","charge":"1000","slot":"9","id":"7462"},{"amount":"1","charge":"1000","slot":"10","id":"10696"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"3"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9755"},{"amount":"1","charge":"1000","slot":"1","id":"9754"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1275"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"10","id":"88"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"106"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"11665"},{"amount":"1","charge":"1000","slot":"1","id":"9807"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"13290"},{"amount":"1","charge":"1000","slot":"4","id":"8839"},{"amount":"1","charge":"1000","slot":"5","id":"1201"},{"amount":"1","charge":"1000","slot":"7","id":"8840"},{"amount":"1","charge":"1000","slot":"9","id":"8842"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"106"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9672"},{"amount":"1","charge":"1000","slot":"1","id":"9783"},{"amount":"1","charge":"1000","slot":"2","id":"1725"},{"amount":"1","charge":"1000","slot":"3","id":"4587"},{"amount":"1","charge":"1000","slot":"4","id":"9674"},{"amount":"1","charge":"1000","slot":"7","id":"2497"},{"amount":"1","charge":"1000","slot":"9","id":"7458"},{"amount":"1","charge":"1000","slot":"10","id":"3105"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"106"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"10828"},{"amount":"1","charge":"1000","slot":"1","id":"9763"},{"amount":"1","charge":"1000","slot":"2","id":"1725"},{"amount":"1","charge":"1000","slot":"3","id":"4587"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"5","id":"8850"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"10","id":"3105"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"9","look":"266"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"10828"},{"amount":"1","charge":"1000","slot":"1","id":"2414"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"4587"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"5","id":"1201"},{"amount":"1","charge":"1000","slot":"7","id":"4087"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"2"},{"color":"0","look":"13"},{"color":"1","look":"18"},{"color":"0","look":"28"},{"color":"0","look":"33"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"9802"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"2"},{"color":"0","look":"13"},{"color":"1","look":"18"},{"color":"0","look":"28"},{"color":"0","look":"33"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"6182"},{"amount":"1","charge":"1000","slot":"1","id":"4355"},{"amount":"1","charge":"1000","slot":"2","id":"1478"},{"amount":"1","charge":"1000","slot":"3","id":"9185"},{"amount":"1","charge":"1000","slot":"4","id":"544"},{"amount":"1","charge":"1000","slot":"7","id":"2497"}]} ,
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"1"},{"color":"0","look":"10"},{"color":"14","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"20","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"10071"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"8872"},{"amount":"1","charge":"1000","slot":"9","id":"1059"},{"amount":"1","charge":"1000","slot":"10","id":"88"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"20","look":"278"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"0","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1149"},{"amount":"1","charge":"1000","slot":"1","id":"6568"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1305"},{"amount":"1","charge":"1000","slot":"4","id":"2623"},{"amount":"1","charge":"1000","slot":"5","id":"6524"},{"amount":"1","charge":"1000","slot":"7","id":"4087"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"20","look":"1"},{"color":"0","look":"14"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"4413"},{"amount":"1","charge":"1000","slot":"3","id":"1271"},{"amount":"1","charge":"1000","slot":"4","id":"1123"},{"amount":"1","charge":"1000","slot":"7","id":"1073"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"20","look":"1"},{"color":"0","look":"14"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"3751"},{"amount":"1","charge":"1000","slot":"1","id":"10499"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"4587"},{"amount":"1","charge":"1000","slot":"4","id":"546"},{"amount":"1","charge":"1000","slot":"5","id":"1201"},{"amount":"1","charge":"1000","slot":"7","id":"548"},{"amount":"1","charge":"1000","slot":"10","id":"3105"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"14120"},{"amount":"1","charge":"1000","slot":"2","id":"9470"},{"amount":"1","charge":"1000","slot":"3","id":"1305"},{"amount":"1","charge":"1000","slot":"4","id":"10822"},{"amount":"1","charge":"1000","slot":"5","id":"1540"},{"amount":"1","charge":"1000","slot":"7","id":"10824"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"5","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1153"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"4153"},{"amount":"1","charge":"1000","slot":"4","id":"1115"},{"amount":"1","charge":"1000","slot":"7","id":"1067"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"5","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"3751"},{"amount":"1","charge":"1000","slot":"1","id":"6568"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"5698"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"5","id":"8847"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"10","id":"4131"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"5","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1163"},{"amount":"1","charge":"1000","slot":"2","id":"3853"},{"amount":"1","charge":"1000","slot":"3","id":"1373"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"5","id":"1201"},{"amount":"1","charge":"1000","slot":"7","id":"1079"}]} ,
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"5","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"11021"},{"amount":"1","charge":"1000","slot":"2","id":"3853"},{"amount":"1","charge":"1000","slot":"3","id":"1373"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"5","id":"1201"},{"amount":"1","charge":"1000","slot":"7","id":"1079"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"5","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"11021"},{"amount":"1","charge":"1000","slot":"1","id":"14081"},{"amount":"1","charge":"1000","slot":"2","id":"3853"},{"amount":"1","charge":"1000","slot":"3","id":"1373"},{"amount":"1","charge":"1000","slot":"4","id":"6184"},{"amount":"1","charge":"1000","slot":"7","id":"6185"},{"amount":"1","charge":"1000","slot":"10","id":"3107"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"6","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"6182"},{"amount":"1","charge":"1000","slot":"1","id":"10636"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1371"},{"amount":"1","charge":"1000","slot":"4","id":"10633"},{"amount":"1","charge":"1000","slot":"5","id":"3122"},{"amount":"1","charge":"1000","slot":"7","id":"6181"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"16"},{"color":"6","look":"18"},{"color":"0","look":"27"},{"color":"0","look":"84"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"10071"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1381"},{"amount":"1","charge":"1000","slot":"10","id":"88"}]}
|
||||
|
||||
],
|
||||
"veteran": [
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1038"},{"amount":"1","charge":"1000","slot":"1","id":"6570"},{"amount":"1","charge":"1000","slot":"2","id":"10360"},{"amount":"1","charge":"1000","slot":"3","id":"3053"},{"amount":"1","charge":"1000","slot":"4","id":"3140"},{"amount":"1","charge":"1000","slot":"5","id":"1171"},{"amount":"1","charge":"1000","slot":"7","id":"10394"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"4","look":"48"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"0","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1038"},{"amount":"1","charge":"1000","slot":"1","id":"6570"},{"amount":"1","charge":"1000","slot":"2","id":"10360"},{"amount":"1","charge":"1000","slot":"3","id":"3053"},{"amount":"1","charge":"1000","slot":"4","id":"3140"},{"amount":"1","charge":"1000","slot":"5","id":"1171"},{"amount":"1","charge":"1000","slot":"7","id":"10394"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"4","look":"48"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"0","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9950"},{"amount":"1","charge":"1000","slot":"1","id":"6570"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"7668"},{"amount":"1","charge":"1000","slot":"4","id":"2503"},{"amount":"1","charge":"1000","slot":"7","id":"2497"},{"amount":"1","charge":"1000","slot":"9","id":"5556"},{"amount":"1","charge":"1000","slot":"10","id":"11732"},{"amount":"293","charge":"1000","slot":"13","id":"877"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"261"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"16","look":"38"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"9805"},{"amount":"1","charge":"1000","slot":"4","id":"10348"},{"amount":"1","charge":"1000","slot":"10","id":"1837"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"3"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"9807"},{"amount":"1","charge":"1000","slot":"2","id":"1656"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"9","id":"7462"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"3"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9758"},{"amount":"1","charge":"1000","slot":"1","id":"9757"},{"amount":"1","charge":"1000","slot":"2","id":"1656"},{"amount":"1","charge":"1000","slot":"3","id":"1387"},{"amount":"1","charge":"1000","slot":"4","id":"10378"},{"amount":"1","charge":"1000","slot":"5","id":"1183"},{"amount":"1","charge":"1000","slot":"7","id":"10380"},{"amount":"1","charge":"1000","slot":"9","id":"7462"},{"amount":"1","charge":"1000","slot":"10","id":"10696"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"3"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"10828"},{"amount":"1","charge":"1000","slot":"1","id":"10635"},{"amount":"1","charge":"1000","slot":"2","id":"9470"},{"amount":"1","charge":"1000","slot":"3","id":"9185"},{"amount":"1","charge":"1000","slot":"4","id":"10386"},{"amount":"1","charge":"1000","slot":"5","id":"3842"},{"amount":"1","charge":"1000","slot":"7","id":"10388"},{"amount":"1","charge":"1000","slot":"10","id":"1837"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"3"},{"color":"0","look":"16"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9755"},{"amount":"1","charge":"1000","slot":"1","id":"9754"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"1275"},{"amount":"1","charge":"1000","slot":"4","id":"1127"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"10","id":"88"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9764"},{"amount":"1","charge":"1000","slot":"1","id":"9763"},{"amount":"1","charge":"1000","slot":"2","id":"1704"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"108"},{"color":"3","look":"34"},{"color":"16","look":"38"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9814"},{"amount":"1","charge":"1000","slot":"1","id":"10662"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"16","look":"18"},{"color":"0","look":"108"},{"color":"3","look":"34"},{"color":"16","look":"38"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"9749"},{"amount":"1","charge":"1000","slot":"1","id":"10662"},{"amount":"1","charge":"1000","slot":"2","id":"6585"},{"amount":"1","charge":"1000","slot":"3","id":"5016"},{"amount":"1","charge":"1000","slot":"4","id":"13858"},{"amount":"1","charge":"1000","slot":"5","id":"7053"},{"amount":"1","charge":"1000","slot":"7","id":"13861"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"2"},{"color":"0","look":"13"},{"color":"1","look":"18"},{"color":"0","look":"28"},{"color":"0","look":"33"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"11718"},{"amount":"1","charge":"1000","slot":"1","id":"10499"},{"amount":"1","charge":"1000","slot":"2","id":"87"},{"amount":"1","charge":"1000","slot":"3","id":"9185"},{"amount":"1","charge":"1000","slot":"4","id":"11720"},{"amount":"1","charge":"1000","slot":"5","id":"11283"},{"amount":"1","charge":"1000","slot":"7","id":"11722"},{"amount":"1","charge":"1000","slot":"9","id":"7458"},{"amount":"1","charge":"1000","slot":"10","id":"6920"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"1","look":"2"},{"color":"0","look":"13"},{"color":"1","look":"18"},{"color":"0","look":"28"},{"color":"0","look":"33"},{"color":"16","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"6918"},{"amount":"1","charge":"1000","slot":"1","id":"9771"},{"amount":"1","charge":"1000","slot":"2","id":"87"},{"amount":"1","charge":"1000","slot":"3","id":"1387"},{"amount":"1","charge":"1000","slot":"4","id":"6916"},{"amount":"1","charge":"1000","slot":"5","id":"11283"},{"amount":"1","charge":"1000","slot":"7","id":"6924"},{"amount":"1","charge":"1000","slot":"9","id":"6922"},{"amount":"1","charge":"1000","slot":"10","id":"6920"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"45"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"6","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"2637"},{"amount":"1","charge":"1000","slot":"1","id":"9769"},{"amount":"1","charge":"1000","slot":"2","id":"1478"},{"amount":"1","charge":"1000","slot":"3","id":"4151"},{"amount":"1","charge":"1000","slot":"4","id":"10460"},{"amount":"1","charge":"1000","slot":"5","id":"3842"},{"amount":"1","charge":"1000","slot":"7","id":"10394"},{"amount":"1","charge":"1000","slot":"9","id":"2912"},{"amount":"1","charge":"1000","slot":"10","id":"2904"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"45"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"6","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"8903"},{"amount":"1","charge":"1000","slot":"1","id":"9807"},{"amount":"1","charge":"1000","slot":"2","id":"6585"},{"amount":"1","charge":"1000","slot":"3","id":"4151"},{"amount":"1","charge":"1000","slot":"4","id":"14479"},{"amount":"1","charge":"1000","slot":"5","id":"1187"},{"amount":"1","charge":"1000","slot":"7","id":"4087"},{"amount":"1","charge":"1000","slot":"9","id":"2912"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"20","look":"278"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"0","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"1","id":"10635"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"4151"},{"amount":"1","charge":"1000","slot":"4","id":"4757"},{"amount":"1","charge":"1000","slot":"5","id":"7053"},{"amount":"1","charge":"1000","slot":"7","id":"4759"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"20","look":"278"},{"color":"0","look":"1000"},{"color":"0","look":"56"},{"color":"0","look":"61"},{"color":"0","look":"68"},{"color":"0","look":"70"},{"color":"0","look":"79"}],"gender":"1"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"1163"},{"amount":"1","charge":"1000","slot":"1","id":"9766"},{"amount":"1","charge":"1000","slot":"2","id":"1704"},{"amount":"1","charge":"1000","slot":"3","id":"4587"},{"amount":"1","charge":"1000","slot":"4","id":"10551"},{"amount":"1","charge":"1000","slot":"5","id":"8850"},{"amount":"1","charge":"1000","slot":"7","id":"1079"},{"amount":"1","charge":"1000","slot":"9","id":"7455"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"12","look":"2"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"0","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"2643"},{"amount":"1","charge":"1000","slot":"1","id":"10446"},{"amount":"1","charge":"1000","slot":"2","id":"6585"},{"amount":"1","charge":"1000","slot":"3","id":"4151"},{"amount":"1","charge":"1000","slot":"4","id":"4712"},{"amount":"1","charge":"1000","slot":"5","id":"8850"},{"amount":"1","charge":"1000","slot":"7","id":"4714"},{"amount":"1","charge":"1000","slot":"9","id":"7461"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]},
|
||||
{"appearance":{"appearance_cache":[{"color":"0","look":"0"},{"color":"0","look":"10"},{"color":"0","look":"18"},{"color":"0","look":"26"},{"color":"6","look":"33"},{"color":"0","look":"36"},{"color":"0","look":"42"}],"gender":"0"},"equipment":[{"amount":"1","charge":"1000","slot":"0","id":"10828"},{"amount":"1","charge":"1000","slot":"1","id":"2414"},{"amount":"1","charge":"1000","slot":"2","id":"6585"},{"amount":"1","charge":"1000","slot":"3","id":"4587"},{"amount":"1","charge":"1000","slot":"4","id":"10551"},{"amount":"1","charge":"1000","slot":"5","id":"1187"},{"amount":"1","charge":"1000","slot":"7","id":"4087"},{"amount":"1","charge":"1000","slot":"9","id":"7462"},{"amount":"1","charge":"1000","slot":"10","id":"11732"}]}
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
BIN
Server/data/cache/main_file_cache.dat2
(Stored with Git LFS)
vendored
BIN
Server/data/cache/main_file_cache.dat2
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Server/data/cache/main_file_cache.idx19
(Stored with Git LFS)
vendored
BIN
Server/data/cache/main_file_cache.idx19
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Server/data/cache/main_file_cache.idx255
(Stored with Git LFS)
vendored
BIN
Server/data/cache/main_file_cache.idx255
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
Server/data/cache/main_file_cache.idx5
(Stored with Git LFS)
vendored
BIN
Server/data/cache/main_file_cache.idx5
(Stored with Git LFS)
vendored
Binary file not shown.
2
Server/data/configs/account_limit_exceptions.conf
Normal file
2
Server/data/configs/account_limit_exceptions.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[exceptions]
|
||||
"127.0.0.1" = 5
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
"start_graphic": "232,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "226,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "813",
|
||||
|
|
@ -133,7 +133,7 @@
|
|||
"start_graphic": "233,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "227,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "814",
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
"start_graphic": "234,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "228,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "815",
|
||||
|
|
@ -149,7 +149,7 @@
|
|||
"start_graphic": "235,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "229,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "816",
|
||||
|
|
@ -157,7 +157,7 @@
|
|||
"start_graphic": "236,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "230,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "817",
|
||||
|
|
@ -165,7 +165,7 @@
|
|||
"start_graphic": "237,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "231,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "825",
|
||||
|
|
@ -221,7 +221,7 @@
|
|||
"start_graphic": "206,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "200,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "832",
|
||||
|
|
@ -229,7 +229,7 @@
|
|||
"start_graphic": "207,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "201,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "833",
|
||||
|
|
@ -237,7 +237,7 @@
|
|||
"start_graphic": "208,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "202,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "834",
|
||||
|
|
@ -245,7 +245,7 @@
|
|||
"start_graphic": "209,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "203,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "835",
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
"start_graphic": "210,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "204,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "836",
|
||||
|
|
@ -261,7 +261,7 @@
|
|||
"start_graphic": "211,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "205,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "863",
|
||||
|
|
@ -325,7 +325,7 @@
|
|||
"start_graphic": "219,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "212,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "871",
|
||||
|
|
@ -333,7 +333,7 @@
|
|||
"start_graphic": "220,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "213,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "872",
|
||||
|
|
@ -341,7 +341,7 @@
|
|||
"start_graphic": "221,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "214,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "873",
|
||||
|
|
@ -349,7 +349,7 @@
|
|||
"start_graphic": "223,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "216,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "874",
|
||||
|
|
@ -357,7 +357,7 @@
|
|||
"start_graphic": "222,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "215,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "875",
|
||||
|
|
@ -365,7 +365,7 @@
|
|||
"start_graphic": "224,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "217,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "876",
|
||||
|
|
@ -373,7 +373,7 @@
|
|||
"start_graphic": "225,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "218,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "877",
|
||||
|
|
@ -389,7 +389,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "879",
|
||||
|
|
@ -421,7 +421,7 @@
|
|||
"start_graphic": "19,96",
|
||||
"darkbow_graphic": "1104,96",
|
||||
"projectile": "10,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "884",
|
||||
|
|
@ -437,7 +437,7 @@
|
|||
"start_graphic": "18,96",
|
||||
"darkbow_graphic": "1105,96",
|
||||
"projectile": "9,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "886",
|
||||
|
|
@ -453,7 +453,7 @@
|
|||
"start_graphic": "20,96",
|
||||
"darkbow_graphic": "1106,96",
|
||||
"projectile": "11,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "888",
|
||||
|
|
@ -469,7 +469,7 @@
|
|||
"start_graphic": "21,96",
|
||||
"darkbow_graphic": "1107,96",
|
||||
"projectile": "12,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "890",
|
||||
|
|
@ -485,7 +485,7 @@
|
|||
"start_graphic": "22,96",
|
||||
"darkbow_graphic": "1108,96",
|
||||
"projectile": "13,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "892",
|
||||
|
|
@ -501,7 +501,7 @@
|
|||
"start_graphic": "24,96",
|
||||
"darkbow_graphic": "1109,96",
|
||||
"projectile": "15,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "2532",
|
||||
|
|
@ -565,7 +565,7 @@
|
|||
"start_graphic": "273,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "227,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "4160",
|
||||
|
|
@ -725,7 +725,7 @@
|
|||
"start_graphic": "19,96",
|
||||
"darkbow_graphic": "1104,96",
|
||||
"projectile": "10,40,36,41,46,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5617",
|
||||
|
|
@ -733,7 +733,7 @@
|
|||
"start_graphic": "18,96",
|
||||
"darkbow_graphic": "1105,96",
|
||||
"projectile": "9,40,36,41,46,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5618",
|
||||
|
|
@ -741,7 +741,7 @@
|
|||
"start_graphic": "20,96",
|
||||
"darkbow_graphic": "1106,96",
|
||||
"projectile": "11,40,36,41,46,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5619",
|
||||
|
|
@ -749,7 +749,7 @@
|
|||
"start_graphic": "21,96",
|
||||
"darkbow_graphic": "1107,96",
|
||||
"projectile": "12,40,36,41,46,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5620",
|
||||
|
|
@ -757,7 +757,7 @@
|
|||
"start_graphic": "22,96",
|
||||
"darkbow_graphic": "1108,96",
|
||||
"projectile": "13,40,36,41,46,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5621",
|
||||
|
|
@ -773,7 +773,7 @@
|
|||
"start_graphic": "19,96",
|
||||
"darkbow_graphic": "1104,96",
|
||||
"projectile": "10,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5623",
|
||||
|
|
@ -781,7 +781,7 @@
|
|||
"start_graphic": "18,96",
|
||||
"darkbow_graphic": "1105,96",
|
||||
"projectile": "9,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5624",
|
||||
|
|
@ -789,7 +789,7 @@
|
|||
"start_graphic": "20,96",
|
||||
"darkbow_graphic": "1106,96",
|
||||
"projectile": "11,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5625",
|
||||
|
|
@ -797,7 +797,7 @@
|
|||
"start_graphic": "21,96",
|
||||
"darkbow_graphic": "1107,96",
|
||||
"projectile": "12,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5626",
|
||||
|
|
@ -805,7 +805,7 @@
|
|||
"start_graphic": "22,96",
|
||||
"darkbow_graphic": "1108,96",
|
||||
"projectile": "13,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5627",
|
||||
|
|
@ -813,7 +813,7 @@
|
|||
"start_graphic": "24,96",
|
||||
"darkbow_graphic": "1109,96",
|
||||
"projectile": "15,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5628",
|
||||
|
|
@ -821,7 +821,7 @@
|
|||
"start_graphic": "232,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "226,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5629",
|
||||
|
|
@ -829,7 +829,7 @@
|
|||
"start_graphic": "233,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "227,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5630",
|
||||
|
|
@ -837,7 +837,7 @@
|
|||
"start_graphic": "235,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "229,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5631",
|
||||
|
|
@ -845,7 +845,7 @@
|
|||
"start_graphic": "273,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "227,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5633",
|
||||
|
|
@ -853,7 +853,7 @@
|
|||
"start_graphic": "236,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "230,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5634",
|
||||
|
|
@ -861,7 +861,7 @@
|
|||
"start_graphic": "237,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "231,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5635",
|
||||
|
|
@ -869,7 +869,7 @@
|
|||
"start_graphic": "232,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "226,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5636",
|
||||
|
|
@ -877,7 +877,7 @@
|
|||
"start_graphic": "233,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "227,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5637",
|
||||
|
|
@ -885,7 +885,7 @@
|
|||
"start_graphic": "234,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "228,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5638",
|
||||
|
|
@ -893,7 +893,7 @@
|
|||
"start_graphic": "273,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "227,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5639",
|
||||
|
|
@ -901,7 +901,7 @@
|
|||
"start_graphic": "235,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "229,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5640",
|
||||
|
|
@ -909,7 +909,7 @@
|
|||
"start_graphic": "236,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "230,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5641",
|
||||
|
|
@ -917,7 +917,7 @@
|
|||
"start_graphic": "237,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "231,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5642",
|
||||
|
|
@ -925,7 +925,7 @@
|
|||
"start_graphic": "206,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "200,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5643",
|
||||
|
|
@ -933,7 +933,7 @@
|
|||
"start_graphic": "207,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "201,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5644",
|
||||
|
|
@ -941,7 +941,7 @@
|
|||
"start_graphic": "208,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "202,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5645",
|
||||
|
|
@ -949,7 +949,7 @@
|
|||
"start_graphic": "209,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "203,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5646",
|
||||
|
|
@ -957,7 +957,7 @@
|
|||
"start_graphic": "210,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "204,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5647",
|
||||
|
|
@ -965,7 +965,7 @@
|
|||
"start_graphic": "211,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "205,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5648",
|
||||
|
|
@ -973,7 +973,7 @@
|
|||
"start_graphic": "206,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "200,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5649",
|
||||
|
|
@ -981,7 +981,7 @@
|
|||
"start_graphic": "207,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "201,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5650",
|
||||
|
|
@ -989,7 +989,7 @@
|
|||
"start_graphic": "208,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "202,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5651",
|
||||
|
|
@ -997,7 +997,7 @@
|
|||
"start_graphic": "209,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "203,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5652",
|
||||
|
|
@ -1005,7 +1005,7 @@
|
|||
"start_graphic": "210,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "204,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5653",
|
||||
|
|
@ -1013,7 +1013,7 @@
|
|||
"start_graphic": "211,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "205,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5654",
|
||||
|
|
@ -1021,7 +1021,7 @@
|
|||
"start_graphic": "219,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "212,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5655",
|
||||
|
|
@ -1029,7 +1029,7 @@
|
|||
"start_graphic": "220,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "213,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5656",
|
||||
|
|
@ -1037,7 +1037,7 @@
|
|||
"start_graphic": "221,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "214,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5657",
|
||||
|
|
@ -1045,7 +1045,7 @@
|
|||
"start_graphic": "223,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "216,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5658",
|
||||
|
|
@ -1053,7 +1053,7 @@
|
|||
"start_graphic": "222,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "215,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5659",
|
||||
|
|
@ -1061,7 +1061,7 @@
|
|||
"start_graphic": "224,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "217,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5660",
|
||||
|
|
@ -1069,7 +1069,7 @@
|
|||
"start_graphic": "225,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "218,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "5661",
|
||||
|
|
@ -1077,7 +1077,7 @@
|
|||
"start_graphic": "219,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "212,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5662",
|
||||
|
|
@ -1085,7 +1085,7 @@
|
|||
"start_graphic": "220,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "213,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5663",
|
||||
|
|
@ -1093,7 +1093,7 @@
|
|||
"start_graphic": "221,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "214,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5664",
|
||||
|
|
@ -1101,7 +1101,7 @@
|
|||
"start_graphic": "223,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "216,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5665",
|
||||
|
|
@ -1109,7 +1109,7 @@
|
|||
"start_graphic": "222,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "215,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5666",
|
||||
|
|
@ -1117,7 +1117,7 @@
|
|||
"start_graphic": "224,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "217,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "5667",
|
||||
|
|
@ -1125,7 +1125,7 @@
|
|||
"start_graphic": "225,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "218,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "6061",
|
||||
|
|
@ -1133,7 +1133,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "6062",
|
||||
|
|
@ -1141,7 +1141,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "6522",
|
||||
|
|
@ -1293,7 +1293,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "9287",
|
||||
|
|
@ -1301,7 +1301,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "9288",
|
||||
|
|
@ -1309,7 +1309,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "9289",
|
||||
|
|
@ -1317,7 +1317,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "9290",
|
||||
|
|
@ -1325,7 +1325,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "9291",
|
||||
|
|
@ -1333,7 +1333,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "9293",
|
||||
|
|
@ -1341,7 +1341,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "9294",
|
||||
|
|
@ -1349,7 +1349,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "9295",
|
||||
|
|
@ -1357,7 +1357,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "9296",
|
||||
|
|
@ -1365,7 +1365,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "9297",
|
||||
|
|
@ -1373,7 +1373,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "9298",
|
||||
|
|
@ -1381,7 +1381,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "9300",
|
||||
|
|
@ -1389,7 +1389,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "9301",
|
||||
|
|
@ -1397,7 +1397,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "9302",
|
||||
|
|
@ -1405,7 +1405,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "9303",
|
||||
|
|
@ -1413,7 +1413,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "9304",
|
||||
|
|
@ -1421,7 +1421,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "9305",
|
||||
|
|
@ -1429,7 +1429,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "9335",
|
||||
|
|
@ -1557,7 +1557,7 @@
|
|||
"start_graphic": "1116,96",
|
||||
"darkbow_graphic": "1114,96",
|
||||
"projectile": "1120,40,36,41,46,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "11228",
|
||||
|
|
@ -1565,7 +1565,7 @@
|
|||
"start_graphic": "1116,96",
|
||||
"darkbow_graphic": "1114,96",
|
||||
"projectile": "1120,40,36,41,46,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "11229",
|
||||
|
|
@ -1573,7 +1573,7 @@
|
|||
"start_graphic": "1116,96",
|
||||
"darkbow_graphic": "1114,96",
|
||||
"projectile": "1120,40,36,41,46,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "11230",
|
||||
|
|
@ -1589,7 +1589,7 @@
|
|||
"start_graphic": "1123,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1122,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "11233",
|
||||
|
|
@ -1597,7 +1597,7 @@
|
|||
"start_graphic": "1123,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1122,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "11234",
|
||||
|
|
@ -1605,7 +1605,7 @@
|
|||
"start_graphic": "1123,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1122,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "13083",
|
||||
|
|
@ -1621,7 +1621,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "13085",
|
||||
|
|
@ -1629,7 +1629,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "13086",
|
||||
|
|
@ -1637,7 +1637,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "27,38,36,41,32,5,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "13280",
|
||||
|
|
@ -1661,7 +1661,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1837,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "13881",
|
||||
|
|
@ -1669,7 +1669,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1837,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "13882",
|
||||
|
|
@ -1677,7 +1677,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1837,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "13883",
|
||||
|
|
@ -1701,7 +1701,7 @@
|
|||
"start_graphic": "-1,0",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1837,40,36,32,32,15,0",
|
||||
"poison_damage": "28"
|
||||
"poison_damage": "10"
|
||||
},
|
||||
{
|
||||
"itemId": "13955",
|
||||
|
|
@ -1709,7 +1709,7 @@
|
|||
"start_graphic": "1837,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1840,40,36,32,32,15,0",
|
||||
"poison_damage": "38"
|
||||
"poison_damage": "15"
|
||||
},
|
||||
{
|
||||
"itemId": "13956",
|
||||
|
|
@ -1717,7 +1717,7 @@
|
|||
"start_graphic": "1837,96",
|
||||
"darkbow_graphic": "",
|
||||
"projectile": "1840,40,36,32,32,15,0",
|
||||
"poison_damage": "48"
|
||||
"poison_damage": "20"
|
||||
},
|
||||
{
|
||||
"itemId": "13957",
|
||||
|
|
|
|||
|
|
@ -389,31 +389,31 @@
|
|||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10666,
|
||||
"id": 7334,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10669,
|
||||
"id": 7340,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10672,
|
||||
"id": 7346,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10675,
|
||||
"id": 7352,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10678,
|
||||
"id": 7358,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -949,7 +949,7 @@
|
|||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10667,
|
||||
"id": 7336,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -961,7 +961,7 @@
|
|||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10670,
|
||||
"id": 7342,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -973,7 +973,7 @@
|
|||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10673,
|
||||
"id": 7348,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -985,7 +985,7 @@
|
|||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10676,
|
||||
"id": 7354,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -997,7 +997,7 @@
|
|||
{
|
||||
"minAmount": 1,
|
||||
"weight": "5",
|
||||
"id": 10679,
|
||||
"id": 7360,
|
||||
"maxAmount": 1
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@
|
|||
},
|
||||
{
|
||||
"id": "92",
|
||||
"replaceId": "17317",
|
||||
"replaceId": "91",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -193,7 +193,7 @@
|
|||
},
|
||||
{
|
||||
"id": "1553",
|
||||
"replaceId": "1552",
|
||||
"replaceId": "1556",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -301,7 +301,7 @@
|
|||
},
|
||||
{
|
||||
"id": "2025",
|
||||
"replaceId": "1534",
|
||||
"replaceId": "2026",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -312,14 +312,14 @@
|
|||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "2036",
|
||||
"id": "1530",
|
||||
"replaceId": "1531",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "2039",
|
||||
"replaceId": "1561",
|
||||
"replaceId": "1560",
|
||||
"fence": "false",
|
||||
"metal": "true"
|
||||
},
|
||||
|
|
@ -332,18 +332,18 @@
|
|||
{
|
||||
"id": "2050",
|
||||
"replaceId": "15511",
|
||||
"fence": "false",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "2051",
|
||||
"replaceId": "15513",
|
||||
"fence": "false",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "2054",
|
||||
"replaceId": "24375",
|
||||
"replaceId": "2055",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -419,18 +419,6 @@
|
|||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "2391",
|
||||
"replaceId": "1561",
|
||||
"fence": "false",
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "2392",
|
||||
"replaceId": "1561",
|
||||
"fence": "false",
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "2397",
|
||||
"replaceId": "24383",
|
||||
|
|
@ -896,12 +884,12 @@
|
|||
{
|
||||
"id": "3725",
|
||||
"replaceId": "3727",
|
||||
"fence": "false",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "3726",
|
||||
"replaceId": "3727",
|
||||
"replaceId": "3728",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -925,7 +913,7 @@
|
|||
},
|
||||
{
|
||||
"id": "3747",
|
||||
"replaceId": "1534",
|
||||
"replaceId": "3748",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -943,7 +931,7 @@
|
|||
},
|
||||
{
|
||||
"id": "4148",
|
||||
"replaceId": "4248",
|
||||
"replaceId": "4246",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -979,19 +967,19 @@
|
|||
},
|
||||
{
|
||||
"id": "4423",
|
||||
"replaceId": "4429",
|
||||
"replaceId": "4425",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "4424",
|
||||
"replaceId": "11382",
|
||||
"replaceId": "4426",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "4427",
|
||||
"replaceId": "11380",
|
||||
"replaceId": "4429",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -1238,12 +1226,12 @@
|
|||
{
|
||||
"id": "7049",
|
||||
"replaceId": "7051",
|
||||
"fence": "false",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "7050",
|
||||
"replaceId": "23919",
|
||||
"replaceId": "7052",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -1340,7 +1328,7 @@
|
|||
{
|
||||
"id": "8810",
|
||||
"replaceId": "8812",
|
||||
"fence": "false",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
|
|
@ -1439,6 +1427,12 @@
|
|||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "11470",
|
||||
"replaceId": "11471",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "11483",
|
||||
"replaceId": "11708",
|
||||
|
|
@ -1759,7 +1753,7 @@
|
|||
},
|
||||
{
|
||||
"id": "14245",
|
||||
"replaceId": "14248",
|
||||
"replaceId": "14246",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -1983,7 +1977,15 @@
|
|||
"id": "20391",
|
||||
"replaceId": "28518",
|
||||
"fence": "false",
|
||||
"metal": "true"
|
||||
"metal": "true",
|
||||
"autowalk": "true"
|
||||
},
|
||||
{
|
||||
"id": "28514",
|
||||
"replaceId": "28518",
|
||||
"fence": "false",
|
||||
"metal": "true",
|
||||
"autowalk": "true"
|
||||
},
|
||||
{
|
||||
"id": "21065",
|
||||
|
|
@ -2144,18 +2146,18 @@
|
|||
{
|
||||
"id": "24369",
|
||||
"replaceId": "24373",
|
||||
"fence": "true",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "24370",
|
||||
"replaceId": "24374",
|
||||
"fence": "true",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "24376",
|
||||
"replaceId": "24377",
|
||||
"replaceId": "24375",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -2177,18 +2179,6 @@
|
|||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "24560",
|
||||
"replaceId": "15515",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "24561",
|
||||
"replaceId": "15517",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "24565",
|
||||
"replaceId": "36316",
|
||||
|
|
@ -2357,11 +2347,25 @@
|
|||
"fence": "false",
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "26081",
|
||||
"replaceId": "26083",
|
||||
"fence": "false",
|
||||
"metal": "true",
|
||||
"autowalk": "true"
|
||||
},
|
||||
{
|
||||
"id": "26082",
|
||||
"replaceId": "26084",
|
||||
"fence": "false",
|
||||
"metal": "true",
|
||||
"autowalk": "true"
|
||||
},
|
||||
{
|
||||
"id": "26130",
|
||||
"replaceId": "26132",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "26131",
|
||||
|
|
@ -2507,12 +2511,6 @@
|
|||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
"id": "28514",
|
||||
"replaceId": "28518",
|
||||
"fence": "true",
|
||||
"metal": "true"
|
||||
},
|
||||
{
|
||||
"id": "28589",
|
||||
"replaceId": "28588",
|
||||
|
|
@ -2671,7 +2669,7 @@
|
|||
},
|
||||
{
|
||||
"id": "31815",
|
||||
"replaceId": "31816",
|
||||
"replaceId": "31817",
|
||||
"fence": "false",
|
||||
"metal": "false"
|
||||
},
|
||||
|
|
@ -2798,7 +2796,7 @@
|
|||
{
|
||||
"id": "34780",
|
||||
"replaceId": "34778",
|
||||
"fence": "false",
|
||||
"fence": "true",
|
||||
"metal": "false"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
|||
[
|
||||
{
|
||||
"id": "5",
|
||||
"interfaceType": "1",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
|
|
@ -25,7 +25,49 @@
|
|||
},
|
||||
{
|
||||
"id": "24",
|
||||
"interfaceType": "1",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "34",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "38",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "42",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "46",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "57",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "58",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "59",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
|
|
@ -53,6 +95,30 @@
|
|||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "68",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "69",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "70",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "71",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "74",
|
||||
"interfaceType": "4",
|
||||
|
|
@ -125,6 +191,12 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "139",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "140",
|
||||
"interfaceType": "4",
|
||||
|
|
@ -137,6 +209,12 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "3"
|
||||
},
|
||||
{
|
||||
"id": "169",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "172",
|
||||
"interfaceType": "4",
|
||||
|
|
@ -197,9 +275,33 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "6"
|
||||
},
|
||||
{
|
||||
"id": "194",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "195",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "196",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "198",
|
||||
"interfaceType": "1",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "209",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
|
|
@ -257,6 +359,12 @@
|
|||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "240",
|
||||
"interfaceType": "3",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "241",
|
||||
"interfaceType": "4",
|
||||
|
|
@ -281,6 +389,36 @@
|
|||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "245",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "246",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "247",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "248",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "256",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "259",
|
||||
"interfaceType": "2",
|
||||
|
|
@ -371,6 +509,12 @@
|
|||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "328",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "336",
|
||||
"interfaceType": "3",
|
||||
|
|
@ -395,6 +539,18 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "375",
|
||||
"interfaceType": "3",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "377",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "380",
|
||||
"interfaceType": "1",
|
||||
|
|
@ -449,12 +605,24 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "4"
|
||||
},
|
||||
{
|
||||
"id": "418",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "421",
|
||||
"interfaceType": "4",
|
||||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "428",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "430",
|
||||
"interfaceType": "2",
|
||||
|
|
@ -473,6 +641,30 @@
|
|||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "485",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "486",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "487",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "488",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "498",
|
||||
"interfaceType": "0",
|
||||
|
|
@ -493,7 +685,7 @@
|
|||
},
|
||||
{
|
||||
"id": "532",
|
||||
"interfaceType": "1",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
|
|
@ -605,9 +797,15 @@
|
|||
"walkable": "false",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "653",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
{
|
||||
"id": "656",
|
||||
"interfaceType": "1",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
},
|
||||
|
|
@ -721,7 +919,7 @@
|
|||
},
|
||||
{
|
||||
"id": "809",
|
||||
"interfaceType": "1",
|
||||
"interfaceType": "8",
|
||||
"walkable": "true",
|
||||
"tabIndex": "-1"
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2574
Server/data/configs/music_regions.json
Normal file
2574
Server/data/configs/music_regions.json
Normal file
File diff suppressed because it is too large
Load diff
62
Server/data/configs/music_tiles.json
Normal file
62
Server/data/configs/music_tiles.json
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
[
|
||||
{
|
||||
"id": "98",
|
||||
"borders": "{3072,3456,3135,3519,[3076,3456,3085,3458]~,[3082,3459,3085,3460]}"
|
||||
},
|
||||
{
|
||||
"id": "141",
|
||||
"borders": "{3072,3392,3135,3455,[3076,3452,3085,3455]}"
|
||||
},
|
||||
{
|
||||
"id": "228",
|
||||
"borders": "{2896,5446,2919,5462}"
|
||||
},
|
||||
{
|
||||
"id": "229",
|
||||
"borders": "{2921,5456,2937,5479}"
|
||||
},
|
||||
{
|
||||
"id": "230",
|
||||
"borders": "{2904,5481,2927,5497}"
|
||||
},
|
||||
{
|
||||
"id": "231",
|
||||
"borders": "{2886,5464,2902,5487}"
|
||||
},
|
||||
{
|
||||
"id": "386",
|
||||
"borders": "{2820,5312,2849,5369}-{2849,5349,2880,5374}"
|
||||
},
|
||||
{
|
||||
"id": "391",
|
||||
"borders": "{2879,5340,2944,5366}-{2909,5316,2944,5340}"
|
||||
},
|
||||
{
|
||||
"id": "399",
|
||||
"borders": "{2816,5248,2943,5375,[2823,5250,2844,5310]~,[2844,5250,2878,5280]~,[2879,5340,2944,5366]~,[2909,5316,2944,5340]~,[2820,5312,2849,5369]~,[2849,5349,2880,5374]~,[2885,5253,2934,5278]~,[2913,5278,2937,5306]}"
|
||||
},
|
||||
{
|
||||
"id": "404",
|
||||
"borders": "{2823,5250,2844,5310}-{2844,5250,2878,5276}"
|
||||
},
|
||||
{
|
||||
"id": "408",
|
||||
"borders": "{2885,5253,2934,5278}-{2913,5278,2937,5306}"
|
||||
},
|
||||
{
|
||||
"id": "459",
|
||||
"borders": "{3137,5442,3192,5564}-{3193,5442,3198,5472}-{3193,5507,3198,5564}"
|
||||
},
|
||||
{
|
||||
"id": "467",
|
||||
"borders": "{3199,5441,3262,5564}-{3193,5482,3198,5497}"
|
||||
},
|
||||
{
|
||||
"id": "488",
|
||||
"borders": "{3263,5441,3327,5566}"
|
||||
},
|
||||
{
|
||||
"id": "492",
|
||||
"borders": "{3076,3452,3085,3460,[3076,3459,3081,3460]}"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -15,7 +15,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236"
|
||||
},
|
||||
{
|
||||
"itemId": "800",
|
||||
|
|
@ -294,7 +294,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236"
|
||||
},
|
||||
{
|
||||
"itemId": "839",
|
||||
|
|
@ -1095,7 +1095,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "8882,877,878,6061,6062,879,9236"
|
||||
"ammunition": "8882,877,878,6061,6062,879,9236,9139,9286,9293,9300,9140,9287,9294,9237,9145,9301,9292,9299,9306,9335,880,9238"
|
||||
},
|
||||
{
|
||||
"itemId": "9174",
|
||||
|
|
@ -1104,7 +1104,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236"
|
||||
},
|
||||
{
|
||||
"itemId": "9176",
|
||||
|
|
@ -1113,7 +1113,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,9140,879,9139,9236,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9139,9236,9286,9293,9300,9335,9237"
|
||||
},
|
||||
{
|
||||
"itemId": "9177",
|
||||
|
|
@ -1122,7 +1122,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,9139,9140,9287,9294,9301,880,9238,9145,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236,9139,9140,9287,9294,9301,880,9238,9145,9286,9293,9300,9292,9299,9306,9335,9237"
|
||||
},
|
||||
{
|
||||
"itemId": "9179",
|
||||
|
|
@ -1131,7 +1131,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9139,9140,9236,9141,9288,9295,9302,9336,9239,9145,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9139,9140,9236,9141,9288,9295,9302,9336,9239,9145,9286,9293,9300,9287,9294,9301,9292,9299,9306,9335,9237,880,9238"
|
||||
},
|
||||
{
|
||||
"itemId": "9181",
|
||||
|
|
@ -1140,7 +1140,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9145,9139,9140,9241,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9145,9139,9140,9241,9286,9293,9300,9140,9287,9294,9301,9292,9299,9306,9335,9237,880,9238,13083,13084,13085,13086"
|
||||
},
|
||||
{
|
||||
"itemId": "9183",
|
||||
|
|
@ -1149,7 +1149,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9145,9143,9290,9297,9304,9339,9242,9340,9243,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9145,9143,9290,9297,9304,9339,9242,9340,9243,9286,9293,9300,9140,9287,9294,9301,9292,9299,9306,9335,9237,880,9238,13083,13084,13085,13086"
|
||||
},
|
||||
{
|
||||
"itemId": "9185",
|
||||
|
|
@ -1158,7 +1158,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9145,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9143,9290,9297,9304,9339,9242,9340,9243,9144,9291,9298,9305,9341,9244,9342,9245,9140,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9236,9139,9141,9288,9295,9302,9336,9239,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9145,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9143,9290,9297,9304,9339,9242,9340,9243,9144,9291,9298,9305,9341,9244,9342,9245,9140,13280,9139,9286,9293,9300,9287,9294,9301,9292,9299,9306,9335,9237,880,13083,13084,13085,13086"
|
||||
},
|
||||
{
|
||||
"itemId": "9705",
|
||||
|
|
@ -1293,7 +1293,7 @@
|
|||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9140,9336,9239,13083,13084,13085,13086,13280"
|
||||
"ammunition": "877,878,6061,6062,879,9139,9140,9236,9141,9288,9295,9302,9336,9239,9145,9286,9293,9300,9287,9294,9301,9292,9299,9306,9335,9237,880,9238,13083,13084,13085,13086"
|
||||
},
|
||||
{
|
||||
"itemId": "13405",
|
||||
|
|
@ -1502,69 +1502,6 @@
|
|||
"drop_ammo": "true",
|
||||
"ammunition": "882,883,5616,5622,598,884,885,5617,5623,2532,886,887,5618,5624,2534,888,889,5619,5625,2536,890,891,5620,5626,2538,892,893,5621,5627,2540,78,4160"
|
||||
},
|
||||
{
|
||||
"itemId": "14671",
|
||||
"name": "Armadyl crossbow",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236,9141,9288,9295,9302,9336,9239,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9143,9290,9297,9304,9339,9242,9340,9243,9144,9291,9298,9305,9341,9244,9342,9245,9140,13280"
|
||||
},
|
||||
{
|
||||
"itemId": "14684",
|
||||
"name": "Odium ward",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "8882,877,878,6061,6062,879,9236,9141,9288,9295,9302,9336,9239,13083,13084,13085,13086,9142,9289,9296,9303,9337,9240,9338,9241,9143,9290,9297,9304,9339,9242,9340,9243"
|
||||
},
|
||||
{
|
||||
"itemId": "14685",
|
||||
"name": "Odium shard 1",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "1",
|
||||
"animation": "4230",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "877,878,6061,6062,879,9236"
|
||||
},
|
||||
{
|
||||
"itemId": "14803",
|
||||
"name": "Dark bow",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "2",
|
||||
"animation": "426",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "882,883,5616,5622,598,884,885,5617,5623,2532,886,887,5618,5624,2534,888,889,5619,5625,2536,890,891,5620,5626,2538,892,893,5621,5627,2540,11212,11227,11228,11229,11217,78,4160"
|
||||
},
|
||||
{
|
||||
"itemId": "14804",
|
||||
"name": "Dark bow",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "2",
|
||||
"animation": "426",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "882,883,5616,5622,598,884,885,5617,5623,2532,886,887,5618,5624,2534,888,889,5619,5625,2536,890,891,5620,5626,2538,892,893,5621,5627,2540,11212,11227,11228,11229,11217,78,4160"
|
||||
},
|
||||
{
|
||||
"itemId": "14805",
|
||||
"name": "Dark bow",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "2",
|
||||
"animation": "426",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "882,883,5616,5622,598,884,885,5617,5623,2532,886,887,5618,5624,2534,888,889,5619,5625,2536,890,891,5620,5626,2538,892,893,5621,5627,2540,11212,11227,11228,11229,11217,78,4160"
|
||||
},
|
||||
{
|
||||
"itemId": "14806",
|
||||
"name": "Dark bow",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "2",
|
||||
"animation": "426",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "882,883,5616,5622,598,884,885,5617,5623,2532,886,887,5618,5624,2534,888,889,5619,5625,2536,890,891,5620,5626,2538,892,893,5621,5627,2540,11212,11227,11228,11229,11217,78,4160"
|
||||
},
|
||||
{
|
||||
"itemId": "14192",
|
||||
"name": "Bow (class 1)",
|
||||
|
|
@ -1609,5 +1546,41 @@
|
|||
"animation": "426",
|
||||
"drop_ammo": "true",
|
||||
"ammunition": "14202,14203,14204,14205,14206"
|
||||
},
|
||||
{
|
||||
"itemId": "10149",
|
||||
"name": "Swamp lizard",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10142"
|
||||
},
|
||||
{
|
||||
"itemId": "10146",
|
||||
"name": "Orange salamander",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10143"
|
||||
},
|
||||
{
|
||||
"itemId": "10147",
|
||||
"name": "Red salamander",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10144"
|
||||
},
|
||||
{
|
||||
"itemId": "10148",
|
||||
"name": "Black salamander",
|
||||
"ammo_slot": "13",
|
||||
"weapon_type": "0",
|
||||
"animation": "5247",
|
||||
"drop_ammo": "false",
|
||||
"ammunition": "10145"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
9
Server/data/configs/shared_tables/ASDT.xml
Normal file
9
Server/data/configs/shared_tables/ASDT.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<ASDT>
|
||||
<item id="5318" minAmt="1" maxAmt="4" weight="64"/>
|
||||
<item id="5319" minAmt="1" maxAmt="3" weight="32"/>
|
||||
<item id="5324" minAmt="1" maxAmt="3" weight="16"/>
|
||||
<item id="5322" minAmt="1" maxAmt="2" weight="8"/>
|
||||
<item id="5320" minAmt="1" maxAmt="2" weight="4"/>
|
||||
<item id="5323" minAmt="1" maxAmt="1" weight="2"/>
|
||||
<item id="5321" minAmt="1" maxAmt="1" weight="2"/>
|
||||
</ASDT>
|
||||
12
Server/data/configs/shared_tables/CELEDT.xml
Normal file
12
Server/data/configs/shared_tables/CELEDT.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<CELEDT>
|
||||
<item id="2289" minAmt="3" maxAmt="3" weight="10"/>
|
||||
<item id="534" minAmt="2" maxAmt="2" weight="10"/>
|
||||
<item id="530" minAmt="5" maxAmt="5" weight="10"/>
|
||||
<item id="532" minAmt="3" maxAmt="3" weight="10"/>
|
||||
<item id="526" minAmt="4" maxAmt="4" weight="10"/>
|
||||
<item id="536" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="125" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="119" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="137" minAmt="1" maxAmt="1" weight="10"/>
|
||||
<item id="361" minAmt="5" maxAmt="5" weight="10"/>
|
||||
</CELEDT>
|
||||
12
Server/data/configs/shared_tables/GDT.xml
Normal file
12
Server/data/configs/shared_tables/GDT.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<GDT>
|
||||
<item id="0" minAmt="1" maxAmt="1" weight="128"/>
|
||||
<item id="1623" minAmt="1" maxAmt="1" weight="64"/>
|
||||
<item id="1621" minAmt="1" maxAmt="1" weight="32"/>
|
||||
<item id="1619" minAmt="1" maxAmt="1" weight="16"/>
|
||||
<item id="1617" minAmt="1" maxAmt="1" weight="4"/>
|
||||
<item id="1452" minAmt="1" maxAmt="1" weight="3"/>
|
||||
<item id="1462" minAmt="1" maxAmt="1" weight="3"/>
|
||||
<item id="830" minAmt="5" maxAmt="5" weight="2"/>
|
||||
<item id="985" minAmt="1" maxAmt="1" weight="2"/>
|
||||
<item id="987" minAmt="1" maxAmt="1" weight="2"/>
|
||||
</GDT>
|
||||
13
Server/data/configs/shared_tables/HDT.xml
Normal file
13
Server/data/configs/shared_tables/HDT.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<HDT>
|
||||
<item id="199" minAmt="1" maxAmt="1" weight="32"/>
|
||||
<item id="201" minAmt="1" maxAmt="1" weight="24"/>
|
||||
<item id="203" minAmt="1" maxAmt="1" weight="18"/>
|
||||
<item id="205" minAmt="1" maxAmt="1" weight="14"/>
|
||||
<item id="207" minAmt="1" maxAmt="1" weight="11"/>
|
||||
<item id="209" minAmt="1" maxAmt="1" weight="8"/>
|
||||
<item id="211" minAmt="1" maxAmt="1" weight="6"/>
|
||||
<item id="213" minAmt="1" maxAmt="1" weight="5"/>
|
||||
<item id="215" minAmt="1" maxAmt="1" weight="4"/>
|
||||
<item id="2485" minAmt="1" maxAmt="1" weight="3"/>
|
||||
<item id="217" minAmt="1" maxAmt="1" weight="3"/>
|
||||
</HDT>
|
||||
|
|
@ -26,4 +26,5 @@
|
|||
<item id="1247" minAmt="1" maxAmt="1" weight="1"/>
|
||||
<item id="2366" minAmt="1" maxAmt="1" weight="1"/>
|
||||
<item id="1249" minAmt="1" maxAmt="1" weight="1"/>
|
||||
<item id="0" minAmt="1" maxAmt="1" weight="171"/>
|
||||
</RDT>
|
||||
15
Server/data/configs/shared_tables/RSDT.xml
Normal file
15
Server/data/configs/shared_tables/RSDT.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<RSDT>
|
||||
<item id="5282" minAmt="1" maxAmt="1" weight="28"/>
|
||||
<item id="5296" minAmt="1" maxAmt="1" weight="26"/>
|
||||
<item id="5281" minAmt="1" maxAmt="1" weight="18"/>
|
||||
<item id="5297" minAmt="1" maxAmt="1" weight="18"/>
|
||||
<item id="5106" minAmt="1" maxAmt="1" weight="13"/>
|
||||
<item id="5298" minAmt="1" maxAmt="1" weight="12"/>
|
||||
<item id="5280" minAmt="1" maxAmt="1" weight="11"/>
|
||||
<item id="5299" minAmt="1" maxAmt="1" weight="9"/>
|
||||
<item id="5300" minAmt="1" maxAmt="1" weight="5"/>
|
||||
<item id="5301" minAmt="1" maxAmt="1" weight="4"/>
|
||||
<item id="5302" minAmt="1" maxAmt="1" weight="3"/>
|
||||
<item id="5303" minAmt="1" maxAmt="1" weight="2"/>
|
||||
<item id="5304" minAmt="1" maxAmt="1" weight="1"/>
|
||||
</RSDT>
|
||||
26
Server/data/configs/shared_tables/USDT.xml
Normal file
26
Server/data/configs/shared_tables/USDT.xml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<USDT>
|
||||
<item id="5100" minAmt="1" maxAmt="1" weight="136"/>
|
||||
<item id="5323" minAmt="1" maxAmt="1" weight="130"/>
|
||||
<item id="5292" minAmt="1" maxAmt="1" weight="122"/>
|
||||
<item id="5104" minAmt="1" maxAmt="1" weight="91"/>
|
||||
<item id="5293" minAmt="1" maxAmt="1" weight="83"/>
|
||||
<item id="5311" minAmt="1" maxAmt="1" weight="82"/>
|
||||
<item id="5321" minAmt="1" maxAmt="1" weight="62"/>
|
||||
<item id="5294" minAmt="1" maxAmt="1" weight="57"/>
|
||||
<item id="5295" minAmt="1" maxAmt="1" weight="39"/>
|
||||
<item id="12176" minAmt="1" maxAmt="1" weight="38"/>
|
||||
<item id="5105" minAmt="1" maxAmt="1" weight="33"/>
|
||||
<item id="5282" minAmt="1" maxAmt="1" weight="28"/>
|
||||
<item id="5296" minAmt="1" maxAmt="1" weight="26"/>
|
||||
<item id="5281" minAmt="1" maxAmt="1" weight="18"/>
|
||||
<item id="5297" minAmt="1" maxAmt="1" weight="18"/>
|
||||
<item id="5106" minAmt="1" maxAmt="1" weight="13"/>
|
||||
<item id="5298" minAmt="1" maxAmt="1" weight="12"/>
|
||||
<item id="5280" minAmt="1" maxAmt="1" weight="11"/>
|
||||
<item id="5299" minAmt="1" maxAmt="1" weight="9"/>
|
||||
<item id="5300" minAmt="1" maxAmt="1" weight="5"/>
|
||||
<item id="5301" minAmt="1" maxAmt="1" weight="4"/>
|
||||
<item id="5302" minAmt="1" maxAmt="1" weight="3"/>
|
||||
<item id="5303" minAmt="1" maxAmt="1" weight="2"/>
|
||||
<item id="5304" minAmt="1" maxAmt="1" weight="1"/>
|
||||
</USDT>
|
||||
|
|
@ -45,22 +45,13 @@
|
|||
"stock": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "590",
|
||||
"npcs": "590,591",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "true",
|
||||
"id": "6",
|
||||
"title": "Aemad's Adventuring Supplies Store",
|
||||
"stock": "{1759,100,100}-{882,1000,100}-{1265,10,100}-{2142,10,100}-{1349,10,100}-{946,10,100}-{970,10,100}-{954,10,100}-{590,10,100}-{227,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "591",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "true",
|
||||
"id": "7",
|
||||
"title": "Kortan General Store",
|
||||
"stock": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}"
|
||||
"title": "Aemad's Adventuring Supplies",
|
||||
"stock": "{227,10,100}-{1265,10,100}-{1349,10,100}-{2142,10,100}-{590,10,100}-{1759,100,100}-{882,1000,100}-{954,10,100}-{970,10,100}-{946,10,100}-{1935,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "971",
|
||||
|
|
@ -186,7 +177,7 @@
|
|||
"general_store": "true",
|
||||
"id": "21",
|
||||
"title": "Gunslik's Assorted Items",
|
||||
"stock": "{1931,30,100}-{1935,30,100}-{1735,10,100}-{1925,10,100}-{1923,10,100}-{1887,10,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{550,10,100}-{9003,10,100}"
|
||||
"stock": "{1935,10,100}-{1925,30,100}-{590,10,100}-{1755,10,100}-{2347,10,100}-{36,10,100}-{596,10,100}-{973,10,100}-{1059,10,100}-{229,300,100}-{233,10,100}-{954,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "1334",
|
||||
|
|
@ -312,7 +303,7 @@
|
|||
"general_store": "true",
|
||||
"id": "36",
|
||||
"title": "Obli's General Store",
|
||||
"stock": "{590,2,100}-{229,10,100}-{233,3,100}-{1931,3,100}-{1351,3,100}-{1265,2,100}-{1349,5,100}-{1129,12,100}-{1059,10,100}-{1061,10,100}-{2142,2,100}-{2309,10,100}-{2349,10,100}-{952,10,100}-{36,10,100}-{596,10,100}-{1755,10,100}-{2347,10,100}-{970,50,100}-{973,50,100}-{227,50,100}-{975,50,100}-{954,10,100}"
|
||||
"stock": "{590,10,100}-{229,1000,100}-{233,10,100}-{1931,30,100}-{1351,10,100}-{1265,10,100}-{1349,10,100}-{1129,10,100}-{1059,10,100}-{1061,10,100}-{2142,10,100}-{2309,10,100}-{952,10,100}-{36,10,100}-{596,10,100}-{1755,10,100}-{2347,10,100}-{970,10,100}-{973,10,100}-{227,1000,100}-{975,10,100}-{954,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "560",
|
||||
|
|
@ -519,7 +510,7 @@
|
|||
"general_store": "false",
|
||||
"id": "59",
|
||||
"title": "Fancy Clothes Store",
|
||||
"stock": "{1949,10,100}-{958,10,100}-{948,10,100}-{1733,10,100}-{1734,1000,100}-{1059,30,100}-{1061,10,100}-{1757,10,100}-{1013,10,100}-{1025,10,100}-{10088,0,100}-{10090,0,100}-{10091,0,100}-{10089,0,100}-{10087,0,100}-{11525,0,100}"
|
||||
"stock": "{1949,0,100}-{579,10,100}-{1023,10,100}-{958,10,100}-{948,10,100}-{1733,10,100}-{1734,1000,100}-{1059,30,100}-{1061,10,100}-{428,10,100}-{426,10,100}-{1757,10,100}-{1013,10,100}-{1015,10,100}-{1011,10,100}-{1007,10,100}-{1025,10,100}-{10088,0,100}-{10090,0,100}-{10091,0,100}-{10089,0,100}-{10087,0,100}-{11525,0,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "548",
|
||||
|
|
@ -573,7 +564,7 @@
|
|||
"general_store": "false",
|
||||
"id": "65",
|
||||
"title": "Dodgy Mikes Second-hand Clothing",
|
||||
"stock": "{7114,10,100}"
|
||||
"stock": "{7114,10,100}-{7122,10,100}-{7128,10,100}-{7134,10,100}-{7110,10,100}-{7126,10,100}-{7132,10,100}-{7138,10,100}-{7116,10,100}-{7124,10,100}-{7130,10,100}-{7112,10,100}-{7136,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "2161",
|
||||
|
|
@ -906,7 +897,7 @@
|
|||
"general_store": "false",
|
||||
"id": "103",
|
||||
"title": "Jatix's Herblore Shop",
|
||||
"stock": "{229,300,100}-{233,10,100}-{221,1000,100}"
|
||||
"stock": "{229,300,480}-{233,10,100}-{221,1000,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "5110",
|
||||
|
|
@ -1112,7 +1103,7 @@
|
|||
"currency": "995",
|
||||
"general_store": "false",
|
||||
"id": "126",
|
||||
"title": "Pickaxe-is-mine",
|
||||
"title": "Pickaxe-Is-Mine",
|
||||
"stock": "{1265,10,100}-{1269,10,100}-{1273,10,100}-{1271,10,100}-{1275,10,100}"
|
||||
},
|
||||
{
|
||||
|
|
@ -1239,7 +1230,7 @@
|
|||
"general_store": "false",
|
||||
"id": "140",
|
||||
"title": "Staff Shop",
|
||||
"stock": "{1379,10,100}-{1389,10,100}-{1381,10,100}-{1383,10,100}-{1385,10,100}-{1387,10,100}-{2890,10,100}"
|
||||
"stock": "{1379,10,100}-{1389,10,100}-{1381,10,100}-{1383,10,100}-{1385,10,100}-{1387,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "6971",
|
||||
|
|
@ -1251,13 +1242,13 @@
|
|||
"stock": "{12204,10,100}-{12207,10,100}-{12210,10,100}-{12213,10,100}-{12216,10,100}-{12219,10,100}-{12222,10,100}-{12183,125000,100}-{12155,5000,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "6996",
|
||||
"npcs": "4472",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "false",
|
||||
"id": "142",
|
||||
"title": "Bogrog's Summoning Shop",
|
||||
"stock": "{12204,10,100}-{12207,10,100}-{12210,10,100}-{12213,10,100}-{12216,10,100}-{12219,10,100}-{12222,10,100}-{12183,125000,100}-{12155,5000,100}"
|
||||
"stock": "{12204,10,100}-{12207,10,100}-{12210,0,100}-{12213,0,100}-{12216,0,100}-{12219,0,100}-{12222,0,100}-{12183,65000,100}-{12155,5000,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "3671",
|
||||
|
|
@ -1266,7 +1257,7 @@
|
|||
"general_store": "false",
|
||||
"id": "143",
|
||||
"title": "Fortunato's Fine Wine",
|
||||
"stock": "{1993,10,100}-{1937,10,100}-{7919,10,100}-{1935,10,100}"
|
||||
"stock": "{1993,10,100}-{7810,10,100}-{7919,10,100}-{1935,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "558",
|
||||
|
|
@ -1476,7 +1467,7 @@
|
|||
"stock": "{8794,10,100}-{8790,300,100}-{4819,300,100}-{4820,300,100}-{1539,300,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "1079",
|
||||
"npcs": "1079,1357,1358",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "false",
|
||||
|
|
@ -1662,7 +1653,7 @@
|
|||
"general_store": "false",
|
||||
"id": "187",
|
||||
"title": "William's Wilderness Cape Shop",
|
||||
"stock": "{4315,100,100}-{4335,100,100}-{4375,100,100}-{4395,100,100}"
|
||||
"stock": "{4315,100,100}-{4335,100,100}-{4355,100,100}-{4375,100,100}-{4395,100,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "1779",
|
||||
|
|
@ -1842,7 +1833,7 @@
|
|||
"general_store": "false",
|
||||
"id": "216",
|
||||
"title": "Ore Store",
|
||||
"stock": "{436,20,100}-{438,10,100}-{440,10,100}-{442,5,100}-{453,10,100}-{444,5,100}-{447,0,100}-{449,0,100}"
|
||||
"stock": "{436,10,100}-{438,10,100}-{440,0,100}-{442,0,100}-{453,0,100}-{444,0,100}-{447,0,100}-{449,0,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "596",
|
||||
|
|
@ -1891,12 +1882,13 @@
|
|||
},
|
||||
{
|
||||
"npcs": "2564",
|
||||
"force_shared": "true",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "false",
|
||||
"id": "222",
|
||||
"title": "Ore Shop\b",
|
||||
"stock": "{436,1500,100}-{438,1500,100}-{440,1500,100}-{442,1500,100}-{444,1500,100}-{447,1500,100}-{453,1500,100}"
|
||||
"stock": "{436,0,0}-{438,0,0}-{440,0,0}-{442,0,0}-{444,0,0}-{447,0,0}-{453,0,0}"
|
||||
},
|
||||
{
|
||||
"npcs": "603",
|
||||
|
|
@ -1977,7 +1969,7 @@
|
|||
"general_store": "false",
|
||||
"id": "232",
|
||||
"title": "Sigmund the Merchant",
|
||||
"stock": "{590,2,100}-{954,10,100}-{233,3,100}-{1931,3,100}-{2142,2,100}-{2309,10,100}-{952,10,100}-{36,10,100}-{1755,10,100}-{2347,10,100}-{229,10,100}-{227,10,100}-{1925,10,100}-{1929,10,100}-{1944,10,100}-{1942,10,100}-{1965,10,100}"
|
||||
"stock": "{590,10,100}-{954,10,100}-{1931,30,100}-{2142,10,100}-{2309,10,100}-{952,10,100}-{36,10,100}-{1755,10,100}-{229,310,100}-{227,310,100}-{1925,30,100}-{1944,10,100}-{1942,10,100}-{233,10,100}-{2347,10,100}-{1929,10,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "1315",
|
||||
|
|
@ -2167,5 +2159,41 @@
|
|||
"id": "253",
|
||||
"title": "Fremennik Fur Trader",
|
||||
"stock": "{948,10,100}-{958,10,100}-{10117,0,100}-{10121,0,100}-{10119,0,100}-{10123,0,100}-{10093,0,100}-{10095,0,100}-{10097,0,100}-{10099,0,100}-{10101,0,100}-{10103,0,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "",
|
||||
"high_alch": "0",
|
||||
"currency": "6306",
|
||||
"general_store": "false",
|
||||
"id": "254",
|
||||
"title": "Gabooty's Tai Bwo Wannai Drinky Store",
|
||||
"stock": "{2084,0,100}-{2092,0,100}-{2048,0,100}-{2054,0,100}-{2064,0,100}-{2074,0,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "1526",
|
||||
"high_alch": "0",
|
||||
"currency": "4067",
|
||||
"general_store": "false",
|
||||
"id": "255",
|
||||
"title": "Castle Wars Ticket Exchange",
|
||||
"stock": "{4068,1,100}-{4069,1,100}-{4070,1,100}-{4071,1,100}-{4072,1,100}-{4503,1,100}-{4504,1,100}-{4505,1,100}-{4506,1,100}-{4507,1,100}-{4508,1,100}-{4509,1,100}-{4510,1,100}-{4511,1,100}-{4512,1,100}-{4513,1,100}-{4514,1,100}-{4515,1,100}-{4516,1,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "5111",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "false",
|
||||
"id": "256",
|
||||
"title": "Leon's Prototype Crossbow",
|
||||
"stock": "{10156,2,100}"
|
||||
},
|
||||
{
|
||||
"npcs": "2039",
|
||||
"high_alch": "0",
|
||||
"currency": "995",
|
||||
"general_store": "false",
|
||||
"id": "256",
|
||||
"title": "Uglug's Stuffsies",
|
||||
"stock": "{4844,100,10}-{10927,0,100}-{2862,100,100}-{1777,10,200}-{2876,0,500}-{2878,10,100}-{4850,0,100}-{946,5,100}-{4773,0,1000}-{4778,0,1000}-{4783,0,1000}-{4788,0,1500}-{4793,0,2000}-{4798,0,3000}-{4803,0,4000}-{4827,0,2000}"
|
||||
}
|
||||
]
|
||||
]
|
||||
File diff suppressed because it is too large
Load diff
4
Server/data/eco/.gitignore
vendored
Normal file
4
Server/data/eco/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
{
|
||||
"offers": [
|
||||
{
|
||||
"__comment" : "coal",
|
||||
"item" : "453",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "vial",
|
||||
"item" : "227",
|
||||
"qty" : "10000"
|
||||
},
|
||||
{
|
||||
"__comment" : "water vial",
|
||||
"item" : "229",
|
||||
"qty" : "10000"
|
||||
},
|
||||
{
|
||||
"__comment" : "cooked lobster",
|
||||
"item" : "379",
|
||||
"qty" : "10000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Ashes",
|
||||
"item" : "592",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Mort myre fungi",
|
||||
"item" : "2970",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Poison ivy berries",
|
||||
"item" : "6018",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Potato cactus",
|
||||
"item" : "3138",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Unicorn horn",
|
||||
"item" : "237",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Red spider eggs",
|
||||
"item" : "223",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Bird nest",
|
||||
"item" : "6693",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Chocolate dust",
|
||||
"item" : "1975",
|
||||
"qty" : "1000"
|
||||
},
|
||||
{
|
||||
"__comment" : "Limpwurt root",
|
||||
"item" : "225",
|
||||
"qty" : "10000"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue