mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-13 12:55:06 +00:00
Compare commits
839 Commits
Alpha_1.2
...
Alpha_1.3.
Author | SHA1 | Date | |
---|---|---|---|
5683dca9f6 | |||
b5c935559f | |||
7a37b0e4bf | |||
19b3ac4a99 | |||
bf1b00f0e6 | |||
7102787aa9 | |||
d26d657b95 | |||
3374bbcc9e | |||
8d408996f4 | |||
68e78ba40b | |||
a7b739d17f | |||
78c242eac4 | |||
7e6758fb60 | |||
39658ef63f | |||
4f1ce9adee | |||
87a67804c4 | |||
04c641b79b | |||
9c9939440f | |||
ba9b800eff | |||
62b589295e | |||
b6d86c287c | |||
792a4bd98e | |||
28790e0fb3 | |||
b77e7dd05c | |||
4c73629b9e | |||
330e06b892 | |||
f3f6828699 | |||
c1e1f5195b | |||
a60d41d489 | |||
5975bd9d32 | |||
e67b583cbe | |||
4755dee47d | |||
fd5d981aa5 | |||
a93b2cf954 | |||
16e65560a8 | |||
32d658122b | |||
1cf2741f96 | |||
47c934cee2 | |||
3606c392f2 | |||
6d4465eb67 | |||
08000257fb | |||
ed9eadd1a0 | |||
b42222c461 | |||
635cd677eb | |||
56f500d520 | |||
3202678594 | |||
a68676a247 | |||
7efed17b74 | |||
b776d9d5fc | |||
5237867319 | |||
402fc087ca | |||
1727e18e31 | |||
03b4e40bf4 | |||
8f1c34fdc5 | |||
84bb66357e | |||
c00bfe3908 | |||
3fb99e118c | |||
1d2de1f038 | |||
d177af3297 | |||
8dcdf55264 | |||
5a168836c5 | |||
ce1e95195b | |||
cf5e2f63db | |||
d4c4f8817d | |||
b6a1d42870 | |||
84a5f0fce5 | |||
c136eb2b2e | |||
d0a021de73 | |||
155c918bb8 | |||
19d0c70669 | |||
02721c09a4 | |||
204a4ce831 | |||
a118e626c2 | |||
01d5612ed8 | |||
59aa317546 | |||
4c9cbaf1ee | |||
18562317c3 | |||
f51630c572 | |||
847590645d | |||
fbf22cec39 | |||
0dd3d4a457 | |||
f521d16ce3 | |||
72ec318481 | |||
99554caa69 | |||
bfffa35246 | |||
09a388f8de | |||
a7149ad9ef | |||
471de2d1c5 | |||
aa7d9b5e05 | |||
2e23ce8beb | |||
e4871ee0c4 | |||
86469a1031 | |||
533c179622 | |||
4321a03935 | |||
68f0a91d56 | |||
5e231c846c | |||
7d3992bcc2 | |||
c83d4d955f | |||
ff7fa066a5 | |||
9619ebc2af | |||
0a4beaf051 | |||
2957f35194 | |||
5afd26b1b6 | |||
152ebcbc17 | |||
73c155090c | |||
89cb879f1f | |||
a45858ad94 | |||
c8e157156e | |||
6563169527 | |||
7e67f50da5 | |||
393b57c535 | |||
bda5e62788 | |||
579175b3bc | |||
808f5473d0 | |||
4284211bd1 | |||
33733cd608 | |||
1e14485444 | |||
c42fd790ff | |||
2ef1f0c9d0 | |||
abcb5828ed | |||
ee7c767c16 | |||
affd67debe | |||
79555e4029 | |||
e1c0139ab3 | |||
ca8be7b047 | |||
3ab3526404 | |||
523c4390fa | |||
508ee7e1d6 | |||
4a5783b57b | |||
31490576d2 | |||
b4f95fad11 | |||
8c190ead7f | |||
fef0b27f7c | |||
cbe0692696 | |||
1cc19ae1e8 | |||
2976db25c3 | |||
2f6ddb6aa4 | |||
099bedf8ee | |||
bd1875f5e4 | |||
d82399e686 | |||
4f10b1cb7c | |||
ba53a0927f | |||
9b88a4a73f | |||
715b92b681 | |||
1014052a57 | |||
ac486ec970 | |||
5a278f8a16 | |||
7404279f15 | |||
5f40ab84f0 | |||
3061b8eb3c | |||
e58ef1f62c | |||
4803f14a21 | |||
409cc0931f | |||
9874bd199e | |||
1a822460d8 | |||
8d2862a744 | |||
4f3e49b6a9 | |||
f1c278915d | |||
169d122774 | |||
ccc5e1b628 | |||
5786ba7a35 | |||
cd932d5c07 | |||
bfa65e1e7d | |||
16a8566fca | |||
28480424c5 | |||
54227b1d86 | |||
04390e758d | |||
3e46fc1fdd | |||
97dd718e4f | |||
883b18078f | |||
8bef816061 | |||
13bfaaf7b8 | |||
164b420af6 | |||
38c50c2fec | |||
157237e3ef | |||
20b83319de | |||
1ce23ab8d7 | |||
4f3700f13a | |||
129e099f88 | |||
9d1369bfe9 | |||
6fa0ef652e | |||
71e556a181 | |||
51f4faf22e | |||
8e127e60a0 | |||
3023df2033 | |||
3463db04a6 | |||
e9683ff5d2 | |||
64dca86342 | |||
6a13705970 | |||
afbde5c7ac | |||
6f2b2f98d6 | |||
05ae6cdef3 | |||
e7c6a0c817 | |||
81524362c0 | |||
35c0c21c8d | |||
c37c6da42d | |||
3fa1bd3a05 | |||
fdb7af5df2 | |||
a463e0c09e | |||
67919a68e1 | |||
45ee7ea7ae | |||
e3e7919652 | |||
139d8b38b5 | |||
96c11adc89 | |||
82aa76be17 | |||
7970b8aeed | |||
ab3fcfc148 | |||
28f6a964d4 | |||
306cc9f00c | |||
c1f79fa2f8 | |||
1179369666 | |||
0bd8d0b0d0 | |||
67b0b97005 | |||
5e45567c1d | |||
adce1ad920 | |||
8b1c251a59 | |||
8b9b05991d | |||
5cb06579cd | |||
63933ed1fc | |||
4b408675cf | |||
1f4df559e0 | |||
89ef299333 | |||
3d3383bea7 | |||
c95c231cfc | |||
d614f3c9da | |||
6993528af2 | |||
18b437eec9 | |||
67b533a44d | |||
5def864aca | |||
911577e9b8 | |||
fbf897d1be | |||
a5bc95e733 | |||
2dd188a0bd | |||
a830555d90 | |||
8bf10c523e | |||
7e13ae2bda | |||
7527c57e1e | |||
06a0f169dd | |||
f12620f376 | |||
dce9b3140a | |||
be9676ebe5 | |||
bd6e3901a6 | |||
6f8963bdcd | |||
033a1673f0 | |||
0c7c36cc03 | |||
e01a3e6811 | |||
566cee2b0b | |||
03e059a190 | |||
f80326b714 | |||
1935e2bbf7 | |||
e43b4e67c6 | |||
45267ea074 | |||
45efcc5faa | |||
15c9b7214d | |||
be83eaf521 | |||
f2927df2b3 | |||
5bba03eb09 | |||
588379a430 | |||
dc22e1b81c | |||
f55fb8d490 | |||
d1f2f82c6d | |||
4b6e456c65 | |||
a8b8427065 | |||
ec22034ad7 | |||
c7a3fc4931 | |||
91e414fb87 | |||
1b50bd6e0f | |||
ffd8ac2879 | |||
9ead05a6fa | |||
4f39818cae | |||
15ab47070a | |||
b72d4ac407 | |||
0ca18864f3 | |||
54b73e5f82 | |||
24ba7cbbd1 | |||
722eb6d1f9 | |||
1638e68c53 | |||
75bb2a6399 | |||
a890cdc023 | |||
66fc483156 | |||
1376cc860d | |||
732f5f5168 | |||
66e635daeb | |||
3ac4b0af68 | |||
d7f74a6725 | |||
0522052c75 | |||
e6dbd61308 | |||
848554bc0c | |||
fc02572065 | |||
09efcec605 | |||
4507072980 | |||
2c8d527025 | |||
9919a709e9 | |||
3825edaaab | |||
6e5924a183 | |||
a795b64bab | |||
8d00ef381d | |||
b564868467 | |||
450b5d9560 | |||
25de7a68d5 | |||
6e2f7af6b4 | |||
2f05a03e51 | |||
ddec63c4d4 | |||
6242089b28 | |||
1fbf475ace | |||
2271d45fd9 | |||
f6ab39a526 | |||
71584288dc | |||
e67a7a510e | |||
8192b41693 | |||
4a969257d1 | |||
fde93debb4 | |||
620486a4a0 | |||
0d12039623 | |||
00427a076e | |||
58fd67d2ed | |||
cb03daf28a | |||
3d28f519c7 | |||
6b61bc11d0 | |||
c9d0cf3698 | |||
5d6669201b | |||
d8f6e9ff0e | |||
929c27e339 | |||
a92e4f6acd | |||
b7bc0826af | |||
044b25ccd2 | |||
90effd173b | |||
fc80a85c8c | |||
06c57a3aae | |||
6d54495402 | |||
838e7ad010 | |||
6262fbffcb | |||
7622151a21 | |||
aefcfad296 | |||
424dba2fdd | |||
7c3b8807e9 | |||
f6a395e7b7 | |||
d92056fe77 | |||
161a271127 | |||
8ec11b35ad | |||
df4a29d7d6 | |||
00de63986b | |||
60c0345c81 | |||
b39677cc96 | |||
72f8f00c5d | |||
ce391160f4 | |||
7111bc5e64 | |||
7a5df07ee5 | |||
7ade4762b9 | |||
a153f2ebdc | |||
a538543e4c | |||
5e1dddaba0 | |||
f224c26084 | |||
221da1685e | |||
e34b407538 | |||
b8834890b6 | |||
03062c4e54 | |||
929aebc1bf | |||
363501d988 | |||
9857f40175 | |||
29b96fa855 | |||
49716cfb18 | |||
acc373525f | |||
c29d3a3e56 | |||
b7083032f3 | |||
c9cecaf218 | |||
9dbdab8060 | |||
8c5d0f070d | |||
73c5e7d7bc | |||
4766424cb3 | |||
8e8002c479 | |||
409f0670bd | |||
ee12b41c39 | |||
cd30f51979 | |||
6dc1e99f5a | |||
cca453cc06 | |||
ff8de264c0 | |||
c6121e88bf | |||
27050b9ec4 | |||
43071dd0ac | |||
281d3b037f | |||
13b00988f0 | |||
228075851c | |||
47b54cfd28 | |||
8336b4c91b | |||
713f16771f | |||
aa14539274 | |||
98c790d731 | |||
00a41e7e11 | |||
ae13512627 | |||
95f2f347ff | |||
48b5afac46 | |||
b9e3acd017 | |||
2fc542d93d | |||
a7a45dfe96 | |||
bb9067acd7 | |||
68855bdd4f | |||
10ed95a469 | |||
04f0500822 | |||
e3de52ba8b | |||
2c4a428698 | |||
b481c26839 | |||
e163223134 | |||
295363a381 | |||
db97c0c5f7 | |||
d28780fa05 | |||
a7709f827f | |||
22cc3d4d83 | |||
f485124190 | |||
b48f486620 | |||
e3bf38e0b2 | |||
7297f8d2c0 | |||
c408ee07b1 | |||
6adc41f301 | |||
af85c7ce45 | |||
22d9cefe96 | |||
5faeff9e16 | |||
e81d68c8d0 | |||
3c4d4f5cff | |||
5ea6052a8a | |||
edb93d6312 | |||
3bb7114e7c | |||
d71a088460 | |||
6db36c238f | |||
09fabfc87e | |||
2377cf7199 | |||
b82e9b2895 | |||
651398e500 | |||
2b89b51621 | |||
f3fe0a6d27 | |||
4678b57c75 | |||
7bbda6dd67 | |||
4564765470 | |||
2305322ed0 | |||
848a69b28a | |||
6a0cc4e122 | |||
beb84ca013 | |||
9dd1568c40 | |||
66322d7719 | |||
ad4959f8c0 | |||
fceb076b9b | |||
1dbbf08f1b | |||
5277555d33 | |||
7d49847ae7 | |||
3cc4546f93 | |||
9a3f887f44 | |||
1f8987183b | |||
072e1328f1 | |||
d071497747 | |||
e0e724bcc3 | |||
fb69cf3392 | |||
f1e4bb0f62 | |||
244fde8143 | |||
3f532d419c | |||
6f59e2eaad | |||
5ee2cda4a6 | |||
e63677a23d | |||
78baa237e3 | |||
3fca7ab6a5 | |||
9e55de134f | |||
bcbc65ed5e | |||
838e08b33b | |||
991436993f | |||
cef4347a02 | |||
de5be4168d | |||
33bd66c1da | |||
7de0835ad9 | |||
d0d5c1bb79 | |||
c6c82f7e55 | |||
5dade755eb | |||
24c0e2742a | |||
c27cca6741 | |||
7236f4aad6 | |||
2254e87ce4 | |||
5938747083 | |||
9b212ae034 | |||
db8f50f408 | |||
bbbc54f606 | |||
703803eb6b | |||
60b559d64b | |||
6610f82ceb | |||
73867f1f80 | |||
cfb2d939a4 | |||
5b6724a452 | |||
4ec2bed44d | |||
2a4d2a92ab | |||
47e9a7b6a1 | |||
d7a54123e2 | |||
3cae25cebd | |||
e0727d2e57 | |||
77ecdb8727 | |||
21150cd239 | |||
cea84879e7 | |||
e43c45768d | |||
d48a1a6ce3 | |||
83cce9cdf3 | |||
d56328b16a | |||
8aa047b3f0 | |||
c4ff8921f1 | |||
6a4010a9af | |||
8149c9e7ca | |||
a3a2155026 | |||
173784752e | |||
33a614c615 | |||
515fcf0890 | |||
72208d9159 | |||
31ffe8017f | |||
9624b9c35e | |||
9b07994913 | |||
fea6e9c432 | |||
13aa73d26e | |||
dffbfa0754 | |||
2e4724c596 | |||
3378c44542 | |||
093bf3ddee | |||
85e3c08aa9 | |||
8345fd02c4 | |||
1c03fb0de9 | |||
2ae0cf65c5 | |||
cb42e5832b | |||
ee73ccc0e2 | |||
cc2addfe92 | |||
be7e5cd67a | |||
e428b4cfc4 | |||
f466e1f791 | |||
bb9a6146fd | |||
34ca8baa29 | |||
d552042094 | |||
6457055be3 | |||
02bbfb60b6 | |||
b759863bb1 | |||
e81793174b | |||
d08807abaf | |||
1cb3e25bf9 | |||
70056b8d1f | |||
2f1e37ce6c | |||
80488784f9 | |||
55b8401967 | |||
269e63ab50 | |||
d0d8d281d2 | |||
4434fe2a5b | |||
82c72f8beb | |||
083110ffd0 | |||
0bea234788 | |||
e444f2a9e0 | |||
38950969dd | |||
9a4c3f8c9f | |||
c3a0600ffd | |||
78167a3cd4 | |||
724e9d9bb2 | |||
8b41246f2d | |||
e4e649ec49 | |||
639ca67a10 | |||
96baeaaad2 | |||
bcb76b51f4 | |||
3577667039 | |||
5848d283da | |||
8f724ffc46 | |||
26c2f61da0 | |||
fd8166c836 | |||
bc80c01348 | |||
e0a59486eb | |||
393f54fe28 | |||
1885cdf3a2 | |||
e65731e3ec | |||
f7f05d4175 | |||
cd8211a9d3 | |||
09301f0e5f | |||
5e4ef9732b | |||
44cb66837e | |||
f195168132 | |||
32e0085c1e | |||
b34e55eec5 | |||
758070e478 | |||
2790f60491 | |||
d8bf5ce711 | |||
bbbdaa30d1 | |||
2438c9535b | |||
3d48eec887 | |||
f1cb29cc8b | |||
710ed5c704 | |||
3c40c8734f | |||
80aaf9923c | |||
cad9908f94 | |||
9ad73b00c8 | |||
fb805f2b0f | |||
e0791b9bae | |||
10d34a7ce6 | |||
69b78a9dd6 | |||
8442c0529e | |||
77da9d3a7c | |||
5e9e2b2a7d | |||
88a4116398 | |||
633f7233b4 | |||
a92518ef9e | |||
0c051fb02e | |||
e71b6946f3 | |||
d157299c7a | |||
82d49b0343 | |||
790b9c19b6 | |||
439d0ead4f | |||
3ae18c85b1 | |||
74c4fab58d | |||
199fbb644b | |||
4867533ab7 | |||
452df5b2f8 | |||
c334bbce12 | |||
8d7fafe167 | |||
996bf6b366 | |||
1cf61fc829 | |||
75a2bf122f | |||
159d1c5024 | |||
e2b68a01d1 | |||
bab3b8274a | |||
a6615560bc | |||
62735c8e41 | |||
5c2a2ecd6d | |||
432eb36b83 | |||
7388a32869 | |||
83a63ef805 | |||
c45cd5e12a | |||
c138cb2797 | |||
feaecbcd60 | |||
3e4efbb26a | |||
b9498275a4 | |||
f7af97c651 | |||
076691ec52 | |||
2763401be3 | |||
a3b7f12803 | |||
eac72bb8ae | |||
7b8a27f7b0 | |||
6ba7486097 | |||
4dd66b450c | |||
2b741a2913 | |||
2043534003 | |||
7e37a60a67 | |||
f093286fb2 | |||
7c9eec7869 | |||
79ca735fb0 | |||
533b175b66 | |||
2c81518c5d | |||
dccfbfd572 | |||
e88c337229 | |||
5f55cdf26a | |||
3e3521086b | |||
01e31fc82e | |||
b66e784a12 | |||
20694f2c77 | |||
539c8046d8 | |||
1d32e82265 | |||
12f9c12fe4 | |||
0060c3f10d | |||
6456d2383b | |||
793aaf87c0 | |||
f7de979de1 | |||
82a789687c | |||
026353399b | |||
febfbb19c4 | |||
45bbc86830 | |||
3d8c9db430 | |||
8405c74b42 | |||
93cfa035d4 | |||
463e82a1e7 | |||
cd946a7273 | |||
074c1b5295 | |||
ad6b48a599 | |||
e77db15c21 | |||
683fd03f45 | |||
dbc357c266 | |||
e0747a9c44 | |||
cdc164729c | |||
4e8e132fcf | |||
77fa1608c1 | |||
e3a858a089 | |||
eeb9b925a5 | |||
082c4429cd | |||
314da7b30e | |||
1129df6194 | |||
1ef0a41944 | |||
1cb30601b5 | |||
534898167e | |||
f53877c070 | |||
ecc2faffea | |||
66169d63c4 | |||
b83ef4e70b | |||
e2d4b49266 | |||
1b92b1177c | |||
251b88f8ba | |||
f8c6921ac4 | |||
2b03e71c97 | |||
263824fa01 | |||
abf52079fc | |||
7312c57123 | |||
f7a12b09f7 | |||
949ab34b42 | |||
121fd51dc6 | |||
44fcf4a6ed | |||
a6cc0f8261 | |||
bd196c0fcb | |||
caa32edf6f | |||
87ebe7fac4 | |||
8c9f07f737 | |||
cbe160e655 | |||
efa8692bfa | |||
3f2cb86859 | |||
6d39f54591 | |||
af52b0a5b5 | |||
257b330a53 | |||
8a9e6426ca | |||
3f820d18d2 | |||
677e1f8ce0 | |||
822adcae2d | |||
4ea4431986 | |||
e392a35598 | |||
912e35f202 | |||
f1a28f23ae | |||
c68b4ebda6 | |||
98976ac56c | |||
42d5296533 | |||
6260d66bde | |||
2861fe0703 | |||
012ecbe40a | |||
c5326131a2 | |||
174160c65c | |||
a5998ff9a2 | |||
ec5f255a71 | |||
e7fcbe206f | |||
89b38c25ce | |||
88a1f83545 | |||
14ab386b0f | |||
7dbf421e99 | |||
0d3624e6a7 | |||
14ff3e0a9b | |||
ae731c9093 | |||
d613fa2138 | |||
5e52bbdd16 | |||
0b6ff03d5a | |||
1ff8945015 | |||
a603732bb4 | |||
23a7847350 | |||
f07cd21dd1 | |||
8bbd899689 | |||
2a8c72dfc2 | |||
59763a35c7 | |||
2e0d49a2ba | |||
6e4141f140 | |||
75a42ce26c | |||
38d361bb07 | |||
13ae305bdd | |||
ec55ebc14e | |||
698515f31b | |||
58c258d422 | |||
eb90c777f3 | |||
7a0ff2a1c0 | |||
57df6e61aa | |||
5e44ecf63b | |||
4a9374a58c | |||
f936e29d34 | |||
6dba82c695 | |||
df77f725fd | |||
2c952a5a4f | |||
9ee7180681 | |||
65110d5358 | |||
da849a7251 | |||
28d431e497 | |||
9bd4b02908 | |||
4ff9753ede | |||
518902caf4 | |||
2c3ab413f5 | |||
3ba56c3e81 | |||
49d2723806 | |||
70b86061f6 | |||
6a29dd5a8d | |||
58631ba1d0 | |||
fe2b9a6ac5 | |||
4d2835a37a | |||
e1c5d965a0 | |||
a3268d2405 | |||
5eaa432ddb | |||
acc0311386 | |||
8842d8d772 | |||
6fb8e754d6 | |||
6763e93a8d | |||
40b43a911e | |||
012c86ef00 | |||
5fedf27255 | |||
3967c8eec1 | |||
23ca20855a | |||
01628b88b7 | |||
b5cd877b3e | |||
c536a35beb | |||
bb968451ba | |||
a5e52e7b9a | |||
47af98a875 | |||
ed003cd207 | |||
3bf9d5b911 | |||
db4bdcd2bd | |||
ce8724c5ed | |||
d46a61d0c4 | |||
1bfef261ab | |||
6dfe348767 | |||
3f10e11ddf | |||
5b79722fa9 | |||
fc06e1bcaf | |||
ffaaca6f2d | |||
0660409987 | |||
bbc925b188 | |||
6f7268902d | |||
6851f9c7b1 | |||
9ec9d22bbc | |||
40842ec794 | |||
ab1c28fc57 | |||
a9f7d47c25 | |||
5241f0527b | |||
5c7f397bde | |||
84ac13d591 | |||
8bf4b5cafa | |||
7acbf13a8a | |||
fa4813d335 | |||
3432a69a41 | |||
bc5516867c | |||
5c17f77bcc | |||
5fab555c48 | |||
ba3dfd91db | |||
8f21eb41ee | |||
d90e41c0d5 | |||
aecfbbbdc1 | |||
1c63448c6c | |||
8253d63d9b | |||
a7d8e22e7e | |||
ad11851c61 | |||
b259ed2532 | |||
9510cbd716 | |||
8a345e6582 | |||
66fe5d2a3e | |||
7f88ab95e2 | |||
3355f71ab3 | |||
e8c2662258 | |||
6c4900cd32 |
157
.gitignore
vendored
157
.gitignore
vendored
@ -2,129 +2,11 @@ players/*
|
||||
worlds/*
|
||||
plugins/*
|
||||
logs/*
|
||||
bin/*
|
||||
*.log
|
||||
*.pmf
|
||||
*.txt
|
||||
server.properties
|
||||
white-list.txt
|
||||
banned-ips.txt
|
||||
banned.txt
|
||||
ops.txt
|
||||
|
||||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.vspscc
|
||||
.builds
|
||||
*.dotCover
|
||||
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment this
|
||||
#packages/
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish
|
||||
|
||||
# Others
|
||||
[Bb]in
|
||||
[Oo]bj
|
||||
sql
|
||||
TestResults
|
||||
*.Cache
|
||||
ClientBin
|
||||
stylecop.*
|
||||
~$*
|
||||
*.dbmdl
|
||||
Generated_Code #added for RIA/Silverlight projects
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
|
||||
|
||||
|
||||
############
|
||||
@ -137,38 +19,5 @@ Thumbs.db
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
|
||||
*.py[co]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
10
.travis.yml
10
.travis.yml
@ -4,16 +4,12 @@ php:
|
||||
- 5.4
|
||||
|
||||
before_script:
|
||||
- pecl install channel://pecl.php.net/pthreads-0.0.42
|
||||
- git clone --depth=100 --quiet --branch=tests git://github.com/shoghicp/PocketMine-MP.git $(pwd)/tests/
|
||||
- pecl install channel://pecl.php.net/pthreads-0.0.44
|
||||
- git clone --depth=100 --quiet --branch=tests git://github.com/PocketMine/PocketMine-MP.git $(pwd)/tests/
|
||||
|
||||
script:
|
||||
- phpunit tests/
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#mcpedevs"
|
||||
template:
|
||||
- "PocketMine-MP #%{build_number} %{commit}: %{message} (%{build_url})"
|
||||
webhooks: http://n.tkte.ch/h/214/wsNvmG43-ncxUVRrFPwSM-r0
|
||||
|
27
CONTRIBUTING.md
Normal file
27
CONTRIBUTING.md
Normal file
@ -0,0 +1,27 @@
|
||||

|
||||
|
||||
# PocketMine-MP Contribution Gidelines
|
||||
|
||||
Before contributing to PocketMine-MP, please read this.
|
||||
|
||||
|
||||
## I've a question
|
||||
* For questions, please refer to the _#mcpedevs_ IRC
|
||||
channel on Freenode. There is a [WebIRC](http://webchat.freenode.net?channels=mcpedevs&uio=d4) if you want.
|
||||
* You can ask directly to _[@PocketMine](https://twitter.com/PocketMine)_ in Twitter.
|
||||
|
||||
## I want to create an issue
|
||||
* First, use the [Issue Search](https://github.com/PocketMine/PocketMine-MP/search?ref=cmdform&type=Issues) to check if anyone has reported it.
|
||||
* Is your issue related to a Plugin? If so, please contact their original author instead of reporting it here.
|
||||
* And no, we won't update a Plugin because you need it.
|
||||
* When reporting, give as much info as you can, and if the Issue is a crash, give the Crash Dump.
|
||||
* Issues should be written in English.
|
||||
|
||||
## I want to contribute code
|
||||
* Use the [Pull Request](https://github.com/PocketMine/PocketMine-MP/pull/new) system, your request will be checked and discussed.
|
||||
* If you want to be part of PocketMine-MP, we will ask you to.
|
||||
* Code using the syntax as in PocketMine-MP.
|
||||
* The code must be clear and written in English, comments included.
|
||||
|
||||
|
||||
__Thanks for contributing to PocketMine-MP!__
|
@ -33,6 +33,7 @@ require_once(FILE_PATH."/src/dependencies.php");
|
||||
/***REM_END***/
|
||||
|
||||
$server = new ServerAPI();
|
||||
$server->run();
|
||||
$server->start();
|
||||
|
||||
kill(getmypid()); //Fix for segfault
|
||||
kill(getmypid()); //Fix for ConsoleAPI being blocked
|
||||
exit(0);
|
28
README.md
28
README.md
@ -1,6 +1,6 @@
|
||||

|
||||

|
||||
|
||||
# PocketMine-MP [](https://travis-ci.org/shoghicp/PocketMine-MP)
|
||||
# PocketMine-MP [](https://travis-ci.org/PocketMine/PocketMine-MP)
|
||||
|
||||
```
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@ -17,29 +17,33 @@ You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
```
|
||||
|
||||
__PocketMine-MP is a Server for Minecraft Pocket Edition__. It has a Plugin API that enables a developer to extend it and add new features, or change default ones.
|
||||
__PocketMine-MP is a sofware for creating Minecraft Pocket Edition servers__. It has a Plugin API that enables a developer to extend it and add new features, or change default ones.
|
||||
|
||||
The entire server is done in PHP, and has been tested, profiled and optimized to run smoothly.
|
||||
|
||||
### [Homepage](http://www.pocketmine.org/)
|
||||
### [Homepage](http://www.pocketmine.net/)
|
||||
|
||||
### [FAQ: Frequently Asked Questions](https://github.com/shoghicp/PocketMine-MP/wiki/Frequently-Asked-Questions)
|
||||
### [Plugin Repository](http://plugins.pocketmine.net/)
|
||||
|
||||
### [Help Page](http://www.pocketmine.org/help.php)
|
||||
### [FAQ: Frequently Asked Questions](https://github.com/PocketMine/PocketMine-MP/wiki/Frequently-Asked-Questions)
|
||||
|
||||
### [Help Page](http://www.pocketmine.net/help.php)
|
||||
|
||||
### [Twitter @PocketMine](https://twitter.com/PocketMine)
|
||||
|
||||
## IRC #mcpedevs @ irc.freenode.net
|
||||
* [WebIRC](http://webchat.freenode.net?channels=mcpedevs&uio=d4)
|
||||
## IRC #pocketmine @ irc.freenode.net
|
||||
* [WebIRC](http://webchat.freenode.net?channels=pocketmine,mcpedevs&uio=d4)
|
||||
|
||||
|
||||
## Third-party Libraries Used
|
||||
## Third-party Libraries/Protocols Used
|
||||
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__
|
||||
* __[PHP SQLite3](http://php.net/manual/en/book.sqlite3.php)__
|
||||
* __[cURL](http://curl.haxx.se/)__: cURL is a command line tool for transferring data with URL syntax
|
||||
* __[GMP](http://gmplib.org/)__: Arithmetic without limitations
|
||||
* __[Zlib](http://www.zlib.net/)__: A Massively Spiffy Yet Delicately Unobtrusive Compression Library
|
||||
* __[PHP BCMath](http://php.net/manual/en/book.bc.php)__
|
||||
* __[PHP pthreads](https://github.com/krakjoe/pthreads)__ by _[krakjoe](https://github.com/krakjoe)_: Threading for PHP - Share Nothing, Do Everything.
|
||||
* __[PHP NBT](https://github.com/TheFrozenFire/PHP-NBT-Decoder-Encoder/blob/master/nbt.class.php)__ by _[TheFrozenFire](https://github.com/TheFrozenFire)_: Class for reading in NBT-format files (modified to handle Little-Endian files).
|
||||
* __[Spyc](https://github.com/mustangostang/spyc/blob/master/Spyc.php)__ by _[Vlad Andersen](https://github.com/mustangostang)_: A simple YAML loader/dumper class for PHP.
|
||||
* __[ANSICON](https://github.com/adoxa/ansicon)__ by _[Jason Hood](https://github.com/adoxa)_: Process ANSI escape sequences for Windows console programs.
|
||||
* __[cURL](http://curl.haxx.se/)__: cURL is a command line tool for transferring data with URL syntax
|
||||
* __[Zlib](http://www.zlib.net/)__: A Massively Spiffy Yet Delicately Unobtrusive Compression Library
|
||||
* __[Source RCON Protocol](https://developer.valvesoftware.com/wiki/Source_RCON_Protocol)__
|
||||
* __[UT3 Query Protocol](http://wiki.unrealadmin.org/UT3_query_protocol)__
|
175
compile_php.sh
175
compile_php.sh
@ -1,175 +0,0 @@
|
||||
#!/bin/bash
|
||||
COMPILER_VERSION="0.9"
|
||||
|
||||
PHP_VERSION="5.4.12"
|
||||
ZEND_VM="GOTO"
|
||||
|
||||
ZLIB_VERSION="1.2.7"
|
||||
GMP_VERSION="5.1.1"
|
||||
PTHREADS_VERSION="fc8622882bed09aa181b3eb1cb33c046ce11199b"
|
||||
CURL_VERSION="curl-7_29_0"
|
||||
#READLINE_VERSION="6.2"
|
||||
|
||||
echo "[PocketMine] PHP installer and compiler for Linux & Mac - by @shoghicp v$COMPILER_VERSION"
|
||||
DIR=`pwd`
|
||||
date > "$DIR/install.log" 2>&1
|
||||
uname -a >> "$DIR/install.log" 2>&1
|
||||
echo "[INFO] Checking dependecies"
|
||||
type make >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"make\""; exit 1; }
|
||||
type autoconf >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"autoconf\""; exit 1; }
|
||||
type automake >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"automake\""; exit 1; }
|
||||
type gcc >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"gcc\""; exit 1; }
|
||||
type m4 >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"m4\""; exit 1; }
|
||||
|
||||
rm -r -f install_data/ >> "$DIR/install.log" 2>&1
|
||||
rm -r -f php5/ >> "$DIR/install.log" 2>&1
|
||||
mkdir -m 0777 install_data >> "$DIR/install.log" 2>&1
|
||||
mkdir -m 0777 php5 >> "$DIR/install.log" 2>&1
|
||||
cd install_data
|
||||
set -e
|
||||
|
||||
#PHP 5
|
||||
echo -n "[PHP] downloading $PHP_VERSION..."
|
||||
wget http://php.net/get/php-$PHP_VERSION.tar.gz/from/this/mirror -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv php-$PHP_VERSION php
|
||||
echo " done!"
|
||||
|
||||
#zlib
|
||||
echo -n "[zlib] downloading $ZLIB_VERSION..."
|
||||
wget http://zlib.net/zlib-$ZLIB_VERSION.tar.gz -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv zlib-$ZLIB_VERSION zlib
|
||||
echo -n " checking..."
|
||||
cd zlib
|
||||
./configure --prefix="$DIR/install_data/php/ext/zlib" \
|
||||
--static >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
make >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./zlib
|
||||
echo " done!"
|
||||
|
||||
#Readline
|
||||
#echo -n "[Readline] downloading $READLINE_VERSION..."
|
||||
#wget ftp://ftp.cwru.edu/pub/bash/readline-$READLINE_VERSION.tar.gz -q -O - | tar -xz >> "$DIR/install.log" 2>&1
|
||||
#mv readline-$READLINE_VERSION readline
|
||||
#echo -n " checking..."
|
||||
#cd readline
|
||||
#./configure --prefix="$DIR/install_data/php/ext/readline" \
|
||||
#--disable-shared >> "$DIR/install.log" 2>&1
|
||||
#echo -n " compiling..."
|
||||
#make >> "$DIR/install.log" 2>&1
|
||||
#echo -n " installing..."
|
||||
#make install >> "$DIR/install.log" 2>&1
|
||||
#echo -n " cleaning..."
|
||||
#cd ..
|
||||
#rm -r -f ./readine
|
||||
#echo " done!"
|
||||
|
||||
#--with-readline=$DIR/install_data/php/ext/readline
|
||||
|
||||
#GMP
|
||||
echo -n "[GMP] downloading $GMP_VERSION..."
|
||||
wget ftp://ftp.gmplib.org/pub/gmp-$GMP_VERSION/gmp-$GMP_VERSION.tar.bz2 -q -O - | tar -xj >> "$DIR/install.log" 2>&1
|
||||
mv gmp-$GMP_VERSION gmp
|
||||
echo -n " checking..."
|
||||
cd gmp
|
||||
./configure --prefix="$DIR/install_data/php/ext/gmp" \
|
||||
--disable-assembly \
|
||||
--disable-shared >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
make >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./gmp
|
||||
echo " done!"
|
||||
|
||||
|
||||
echo -n "[cURL] downloading $CURL_VERSION..."
|
||||
wget https://github.com/bagder/curl/archive/$CURL_VERSION.tar.gz --no-check-certificate -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv curl-$CURL_VERSION curl
|
||||
echo -n " checking..."
|
||||
cd curl
|
||||
./buildconf >> "$DIR/install.log" 2>&1
|
||||
./configure --prefix="$DIR/install_data/php/ext/curl" \
|
||||
--disable-shared >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
make >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./curl
|
||||
echo " done!"
|
||||
|
||||
#pthreads
|
||||
echo -n "[PHP pthreads] downloading $PTHREADS_VERSION..."
|
||||
wget https://github.com/krakjoe/pthreads/archive/$PTHREADS_VERSION.tar.gz --no-check-certificate -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv pthreads-$PTHREADS_VERSION "$DIR/install_data/php/ext/pthreads"
|
||||
echo " done!"
|
||||
|
||||
echo -n "[PHP]"
|
||||
set +e
|
||||
if which free >/dev/null; then
|
||||
MAX_MEMORY=$(free -m | awk '/^Mem:/{print $2}')
|
||||
else
|
||||
MAX_MEMORY=$(top -l 1 | grep PhysMem: | awk '{print $10}' | tr -d 'a-zA-Z')
|
||||
fi
|
||||
if [ $MAX_MEMORY -gt 2048 ]
|
||||
then
|
||||
echo -n " enabling optimizations..."
|
||||
OPTIMIZATION="--enable-inline-optimization "
|
||||
else
|
||||
OPTIMIZATION=""
|
||||
fi
|
||||
set -e
|
||||
echo -n " checking..."
|
||||
cd php
|
||||
rm -rf ./aclocal.m4 >> "$DIR/install.log" 2>&1
|
||||
rm -rf ./autom4te.cache/ >> "$DIR/install.log" 2>&1
|
||||
rm -f ./configure >> "$DIR/install.log" 2>&1
|
||||
./buildconf --force >> "$DIR/install.log" 2>&1
|
||||
./configure $OPTIMIZATION--prefix="$DIR/php5" \
|
||||
--exec-prefix="$DIR/php5" \
|
||||
--enable-embedded-mysqli \
|
||||
--enable-bcmath \
|
||||
--with-gmp="$DIR/install_data/php/ext/gmp" \
|
||||
--with-curl="$DIR/install_data/php/ext/curl" \
|
||||
--with-zlib="$DIR/install_data/php/ext/zlib" \
|
||||
--disable-libxml \
|
||||
--disable-xml \
|
||||
--disable-dom \
|
||||
--disable-simplexml \
|
||||
--disable-xmlreader \
|
||||
--disable-xmlwriter \
|
||||
--without-pear \
|
||||
--disable-cgi \
|
||||
--disable-session \
|
||||
--enable-ctype \
|
||||
--without-iconv \
|
||||
--without-pdo-sqlite \
|
||||
--enable-sockets \
|
||||
--enable-shared=no \
|
||||
--enable-static=yes \
|
||||
--enable-pcntl \
|
||||
--enable-pthreads \
|
||||
--enable-maintainer-zts \
|
||||
--enable-zend-signals \
|
||||
--with-zend-vm=$ZEND_VM \
|
||||
--enable-cli >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
make >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo " done!"
|
||||
cd "$DIR"
|
||||
echo -n "[INFO] Cleaning up..."
|
||||
rm -r -f install_data/ >> "$DIR/install.log" 2>&1
|
||||
date >> "$DIR/install.log" 2>&1
|
||||
echo " done!"
|
||||
echo "[PocketMine] You should start the server now using \"./start.sh\""
|
||||
echo "[PocketMine] If it doesn't works, please send the \"install.log\" file to the Bug Tracker"
|
@ -31,31 +31,40 @@ class BanAPI{
|
||||
private $banned;
|
||||
private $ops;
|
||||
private $bannedIPs;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
private $cmdWL = array();//Command WhiteList
|
||||
function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function init(){
|
||||
console("[INFO] Loading authentication lists...");
|
||||
$this->whitelist = new Config(DATA_PATH."white-list.txt", CONFIG_LIST);
|
||||
$this->bannedIPs = new Config(DATA_PATH."banned-ips.txt", CONFIG_LIST);
|
||||
$this->banned = new Config(DATA_PATH."banned.txt", CONFIG_LIST);
|
||||
$this->ops = new Config(DATA_PATH."ops.txt", CONFIG_LIST);
|
||||
$this->server->api->console->register("banip", "Manages IP Banning", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("ban", "Manages Bannning", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("kick", "Kicks a player", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("whitelist", "Manages White-listing", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("op", "Ops a player", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("deop", "Deops a player", array($this, "commandHandler"));
|
||||
$this->whitelist = new Config(DATA_PATH."white-list.txt", CONFIG_LIST);//Open whitelist list file
|
||||
$this->bannedIPs = new Config(DATA_PATH."banned-ips.txt", CONFIG_LIST);//Open Banned IPs list file
|
||||
$this->banned = new Config(DATA_PATH."banned.txt", CONFIG_LIST);//Open Banned Usernames list file
|
||||
$this->ops = new Config(DATA_PATH."ops.txt", CONFIG_LIST);//Open list of OPs
|
||||
$this->server->api->console->register("banip", "<add|remove|list|reload> [IP|player]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("ban", "<add|remove|list|reload> [username]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("kick", "<player> [reason ...]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("whitelist", "<on|off|list|add|remove|reload> [username]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("op", "<player>", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("deop", "<player>", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("sudo", "<player>", array($this, "commandHandler"));
|
||||
$this->server->api->console->alias("ban-ip", "banip add");
|
||||
$this->server->api->console->alias("banlist", "ban list");
|
||||
$this->server->api->console->alias("pardon", "ban remove");
|
||||
$this->server->api->console->alias("pardon-ip", "banip remove");
|
||||
$this->server->addHandler("console.command", array($this, "opCheck"), 1);
|
||||
$this->server->addHandler("console.command", array($this, "permissionsCheck"), 1);//Event handler when commands are issued. Used to check permissions of commands that go through the server.
|
||||
$this->server->addHandler("player.block.break", array($this, "permissionsCheck"), 1);//Event handler for blocks
|
||||
$this->server->addHandler("player.block.place", array($this, "permissionsCheck"), 1);//Event handler for blocks
|
||||
$this->server->addHandler("player.flying", array($this, "permissionsCheck"), 1);//Flying Event
|
||||
}
|
||||
|
||||
public function isOp($username){
|
||||
if($this->server->api->dhandle("api.op.check", $username) === false){
|
||||
public function cmdWhitelist($cmd){//Whitelists a CMD so everyone can issue it - Even non OPs.
|
||||
$this->cmdWhitelist[strtolower(trim($cmd))] = true;
|
||||
}
|
||||
|
||||
public function isOp($username){//Is a player op?
|
||||
$username = strtolower($username);
|
||||
if($this->server->api->dhandle("op.check", $username) === true){
|
||||
return true;
|
||||
}elseif($this->ops->exists($username)){
|
||||
return true;
|
||||
@ -63,50 +72,87 @@ class BanAPI{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function opCheck($data, $event){
|
||||
$whitelist = array(
|
||||
"help",
|
||||
);
|
||||
if(in_array($data["cmd"], $whitelist, true)){
|
||||
public function permissionsCheck($data, $event){
|
||||
switch($event){
|
||||
case "player.flying"://OPs can fly around the server.
|
||||
if($this->isOp($data->iusername)){
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "player.block.break":
|
||||
case "player.block.place"://Spawn protection detection. Allows OPs to place/break blocks in the spawn area.
|
||||
if(!$this->isOp($data["player"]->iusername)){
|
||||
$t = new Vector2($data["target"]->x, $data["target"]->z);
|
||||
$s = new Vector2($this->server->spawn->x, $this->server->spawn->z);
|
||||
if($t->distance($s) <= $this->server->api->getProperty("spawn-protection") and $this->server->api->dhandle($event.".spawn", $data) !== true){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case "console.command"://Checks if a command is allowed with the current user permissions.
|
||||
if(isset($this->cmdWhitelist[$data["cmd"]])){
|
||||
return;
|
||||
}
|
||||
|
||||
if($data["issuer"] instanceof Player){
|
||||
if($this->isOp($data["issuer"]->username)){
|
||||
return true;
|
||||
if($this->server->api->handle("console.check", $data) === true or $this->isOp($data["issuer"]->iusername)){
|
||||
return;
|
||||
}
|
||||
}elseif($data["issuer"] === "console"){
|
||||
return true;
|
||||
}elseif($data["issuer"] === "console" or $data["issuer"] === "rcon"){
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||
$output = "";
|
||||
switch($cmd){
|
||||
case "op":
|
||||
$user = trim(implode(" ", $params));
|
||||
if($user == ""){
|
||||
case "sudo":
|
||||
$target = strtolower(array_shift($params));
|
||||
$player = $this->server->api->player->get($target);
|
||||
if(!($player instanceof Player)){
|
||||
$output .= "Player not connected.\n";
|
||||
break;
|
||||
}
|
||||
$this->server->api->console->run(implode(" ", $params), $player);
|
||||
$output .= "Command ran as ".$player->username.".\n";
|
||||
break;
|
||||
case "op":
|
||||
$user = strtolower($params[0]);
|
||||
$player = $this->server->api->player->get($user);
|
||||
if(!($player instanceof Player)){
|
||||
$this->ops->set($user);
|
||||
$this->ops->save();
|
||||
$this->ops->save($user);
|
||||
$output .= $user." is now op\n";
|
||||
break;
|
||||
}
|
||||
$this->ops->set($player->iusername);
|
||||
$this->ops->save();
|
||||
$output .= $player->iusername." is now op\n";
|
||||
$this->server->api->chat->sendTo(false, "You are now op.", $player->iusername);
|
||||
break;
|
||||
case "deop":
|
||||
$user = trim(implode(" ", $params));
|
||||
if($user == ""){
|
||||
$user = strtolower($params[0]);
|
||||
$player = $this->server->api->player->get($user);
|
||||
if(!($player instanceof Player)){
|
||||
$this->ops->set($user, false);
|
||||
$this->ops->save($user);
|
||||
$output .= $user." is no longer op\n";
|
||||
break;
|
||||
}
|
||||
$this->ops->remove($user);
|
||||
$this->ops->remove($player->iusername);
|
||||
$this->ops->save();
|
||||
$output .= $user." is not longer op\n";
|
||||
$output .= $player->iusername." is not longer op\n";
|
||||
$this->server->api->chat->sendTo(false, "You are no longer op.", $player->iusername);
|
||||
break;
|
||||
case "kick":
|
||||
if(!isset($params[0])){
|
||||
$output .= "Usage: /kick <playername> [reason]\n";
|
||||
$output .= "Usage: /kick <player> [reason ...]\n";
|
||||
}else{
|
||||
$name = array_shift($params);
|
||||
$name = strtolower(array_shift($params));
|
||||
$player = $this->server->api->player->get($name);
|
||||
if($player === false){
|
||||
$output .= "Player \"".$name."\" does not exist\n";
|
||||
@ -126,13 +172,13 @@ class BanAPI{
|
||||
$p = strtolower(array_shift($params));
|
||||
switch($p){
|
||||
case "remove":
|
||||
$user = trim(implode(" ", $params));
|
||||
$user = strtolower($params[0]);
|
||||
$this->whitelist->remove($user);
|
||||
$this->whitelist->save();
|
||||
$output .= "Player \"$user\" removed from white-list\n";
|
||||
break;
|
||||
case "add":
|
||||
$user = trim(implode(" ", $params));
|
||||
$user = strtolower($params[0]);
|
||||
$this->whitelist->set($user);
|
||||
$this->whitelist->save();
|
||||
$output .= "Player \"$user\" added to white-list\n";
|
||||
@ -156,7 +202,7 @@ class BanAPI{
|
||||
$this->server->api->setProperty("white-list", false);
|
||||
break;
|
||||
default:
|
||||
$output .= "Usage: /whitelist <on | off | add | remove | reload | list> [username]\n";
|
||||
$output .= "Usage: /whitelist <on|off|list|add|remove|reload> [username]\n";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -165,14 +211,19 @@ class BanAPI{
|
||||
switch($p){
|
||||
case "pardon":
|
||||
case "remove":
|
||||
$ip = trim(implode($params));
|
||||
$ip = strtolower($params[0]);
|
||||
$this->bannedIPs->remove($ip);
|
||||
$this->bannedIPs->save();
|
||||
$output .= "IP \"$ip\" removed from ban list\n";
|
||||
break;
|
||||
case "add":
|
||||
case "ban":
|
||||
$ip = trim(implode($params));
|
||||
$ip = strtolower($params[0]);
|
||||
$player = $this->server->api->player->get($ip);
|
||||
if($player instanceof Player){
|
||||
$ip = $player->ip;
|
||||
$player->close("banned");
|
||||
}
|
||||
$this->bannedIPs->set($ip);
|
||||
$this->bannedIPs->save();
|
||||
$output .= "IP \"$ip\" added to ban list\n";
|
||||
@ -184,7 +235,7 @@ class BanAPI{
|
||||
$output .= "IP ban list: ".implode(", ", $this->bannedIPs->getAll(true))."\n";
|
||||
break;
|
||||
default:
|
||||
$output .= "Usage: /banip <add | remove | list | reload> [IP]\n";
|
||||
$output .= "Usage: /banip <add|remove|list|reload> [IP|player]\n";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -193,26 +244,26 @@ class BanAPI{
|
||||
switch($p){
|
||||
case "pardon":
|
||||
case "remove":
|
||||
$user = trim(implode($params));
|
||||
$user = strtolower($params[0]);
|
||||
$this->banned->remove($user);
|
||||
$this->banned->save();
|
||||
$output .= "Player \"$user\" removed from ban list\n";
|
||||
break;
|
||||
case "add":
|
||||
case "ban":
|
||||
$user = trim(implode($params));
|
||||
$user = strtolower($params[0]);
|
||||
$this->banned->set($user);
|
||||
$this->banned->save();
|
||||
$player = $this->server->api->player->get($user);
|
||||
if($player !== false){
|
||||
$player->close("You have been banned");
|
||||
}
|
||||
$this->server->api->chat->broadcast("$user has been banned");
|
||||
if($issuer instanceof Player){
|
||||
$this->server->api->chat->broadcast($user." has been banned by ".$issuer->username."\n");
|
||||
}else{
|
||||
$this->server->api->chat->broadcast($user." has been banned\n");
|
||||
}
|
||||
$this->kick($user, "Banned");
|
||||
$output .= "Player \"$user\" added to ban list\n";
|
||||
break;
|
||||
case "reload":
|
||||
@ -222,7 +273,7 @@ class BanAPI{
|
||||
$output .= "Ban list: ".implode(", ", $this->banned->getAll(true))."\n";
|
||||
break;
|
||||
default:
|
||||
$output .= "Usage: /ban <add | remove | list | reload> [player]\n";
|
||||
$output .= "Usage: /ban <add|remove|list|reload> [username]\n";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -231,29 +282,29 @@ class BanAPI{
|
||||
}
|
||||
|
||||
public function ban($username){
|
||||
$this->commandHandler("ban", array("add", $username));
|
||||
$this->commandHandler("ban", array("add", $username), "console", "");
|
||||
}
|
||||
|
||||
public function pardon($username){
|
||||
$this->commandHandler("ban", array("pardon", $username));
|
||||
$this->commandHandler("ban", array("pardon", $username), "console", "");
|
||||
}
|
||||
|
||||
public function banIP($ip){
|
||||
$this->commandHandler("banip", array("add", $ip));
|
||||
$this->commandHandler("banip", array("add", $ip), "console", "");
|
||||
}
|
||||
|
||||
public function pardonIP($ip){
|
||||
$this->commandHandler("banip", array("pardon", $ip));
|
||||
$this->commandHandler("banip", array("pardon", $ip), "console", "");
|
||||
}
|
||||
|
||||
public function kick($username, $reason){
|
||||
$this->commandHandler("kick", array($username, $reason));
|
||||
public function kick($username, $reason = "No Reason"){
|
||||
$this->commandHandler("kick", array($username, $reason), "console", "");
|
||||
}
|
||||
|
||||
public function reload(){
|
||||
$this->commandHandler("ban", array("reload"));
|
||||
$this->commandHandler("banip", array("reload"));
|
||||
$this->commandHandler("whitelist", array("reload"));
|
||||
$this->commandHandler("ban", array("reload"), "console", "");
|
||||
$this->commandHandler("banip", array("reload"), "console", "");
|
||||
$this->commandHandler("whitelist", array("reload"), "console", "");
|
||||
}
|
||||
|
||||
public function isIPBanned($ip){
|
||||
@ -266,6 +317,7 @@ class BanAPI{
|
||||
}
|
||||
|
||||
public function isBanned($username){
|
||||
$username = strtolower($username);
|
||||
if($this->server->api->dhandle("api.ban.check", $username) === false){
|
||||
return true;
|
||||
}elseif($this->banned->exists($username)){
|
||||
@ -275,7 +327,10 @@ class BanAPI{
|
||||
}
|
||||
|
||||
public function inWhitelist($username){
|
||||
if($this->server->api->dhandle("api.ban.whitelist.check", $ip) === false){
|
||||
$username = strtolower($username);
|
||||
if($this->isOp($username)){
|
||||
return true;
|
||||
}elseif($this->server->api->dhandle("api.ban.whitelist.check", $username) === false){
|
||||
return true;
|
||||
}elseif($this->whitelist->exists($username)){
|
||||
return true;
|
||||
|
@ -25,20 +25,134 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
|
||||
define("BLOCK_UPDATE_NORMAL", 0);
|
||||
define("BLOCK_UPDATE_RANDOM", 1);
|
||||
define("BLOCK_UPDATE_SCHEDULED", 2);
|
||||
define("BLOCK_UPDATE_WEAK", 3);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class BlockAPI{
|
||||
private $server;
|
||||
private $scheduledUpdates = array();
|
||||
private $randomUpdates = array();
|
||||
public static $creative = array(
|
||||
array(COBBLESTONE, 0),
|
||||
array(STONE_BRICKS, 0),
|
||||
array(STONE_BRICKS, 1),
|
||||
array(STONE_BRICKS, 2),
|
||||
array(MOSS_STONE, 0),
|
||||
array(WOODEN_PLANKS, 0),
|
||||
array(BRICKS, 0),
|
||||
array(STONE, 0),
|
||||
array(DIRT, 0),
|
||||
array(GRASS, 0),
|
||||
array(CLAY_BLOCK, 0),
|
||||
array(SANDSTONE, 0),
|
||||
array(SANDSTONE, 1),
|
||||
array(SANDSTONE, 2),
|
||||
array(SAND, 0),
|
||||
array(GRAVEL, 0),
|
||||
array(TRUNK, 0),
|
||||
array(TRUNK, 1),
|
||||
array(TRUNK, 2),
|
||||
array(NETHER_BRICKS, 0),
|
||||
array(NETHERRACK, 0),
|
||||
array(COBBLESTONE_STAIRS, 0),
|
||||
array(WOODEN_STAIRS, 0),
|
||||
array(BRICK_STAIRS, 0),
|
||||
array(SANDSTONE_STAIRS, 0),
|
||||
array(STONE_BRICK_STAIRS, 0),
|
||||
array(NETHER_BRICKS_STAIRS, 0),
|
||||
array(QUARTZ_STAIRS, 0),
|
||||
array(SLAB, 0),
|
||||
array(SLAB, 1),
|
||||
array(SLAB, 2),
|
||||
array(SLAB, 3),
|
||||
array(SLAB, 4),
|
||||
array(SLAB, 5),
|
||||
array(SLAB, 6),
|
||||
array(QUARTZ_BLOCK, 0),
|
||||
array(QUARTZ_BLOCK, 1),
|
||||
array(QUARTZ_BLOCK, 2),
|
||||
array(COAL_ORE, 0),
|
||||
array(IRON_ORE, 0),
|
||||
array(GOLD_ORE, 0),
|
||||
array(DIAMOND_ORE, 0),
|
||||
array(LAPIS_ORE, 0),
|
||||
array(REDSTONE_ORE, 0),
|
||||
array(GOLD_BLOCK, 0),
|
||||
array(IRON_BLOCK, 0),
|
||||
array(DIAMOND_BLOCK, 0),
|
||||
array(LAPIS_BLOCK, 0),
|
||||
array(OBSIDIAN, 0),
|
||||
array(SNOW_BLOCK, 0),
|
||||
array(GLASS, 0),
|
||||
array(GLOWSTONE_BLOCK, 0),
|
||||
array(NETHER_REACTOR, 0),
|
||||
array(WOOL, 0),
|
||||
array(WOOL, 7),
|
||||
array(WOOL, 6),
|
||||
array(WOOL, 5),
|
||||
array(WOOL, 4),
|
||||
array(WOOL, 3),
|
||||
array(WOOL, 2),
|
||||
array(WOOL, 1),
|
||||
array(WOOL, 15),
|
||||
array(WOOL, 14),
|
||||
array(WOOL, 13),
|
||||
array(WOOL, 12),
|
||||
array(WOOL, 11),
|
||||
array(WOOL, 10),
|
||||
array(WOOL, 9),
|
||||
array(WOOL, 8),
|
||||
array(LADDER, 0),
|
||||
array(TORCH, 0),
|
||||
array(GLASS_PANE, 0),
|
||||
array(BUCKET, 0),
|
||||
array(BUCKET, 8),
|
||||
array(BUCKET, 10),
|
||||
array(WOODEN_DOOR, 0),
|
||||
array(TRAPDOOR, 0),
|
||||
array(FENCE, 0),
|
||||
array(FENCE_GATE, 0),
|
||||
array(BED, 0),
|
||||
array(BOOKSHELF, 0),
|
||||
array(PAINTING, 0),
|
||||
array(WORKBENCH, 0),
|
||||
array(STONECUTTER, 0),
|
||||
array(CHEST, 0),
|
||||
array(FURNACE, 0),
|
||||
array(TNT, 0),
|
||||
array(DANDELION, 0),
|
||||
array(CYAN_FLOWER, 0),
|
||||
array(BROWN_MUSHROOM, 0),
|
||||
array(RED_MUSHROOM, 0),
|
||||
array(CACTUS, 0),
|
||||
array(MELON_BLOCK, 0),
|
||||
array(SUGARCANE, 0),
|
||||
array(SAPLING, 0),
|
||||
array(SAPLING, 1),
|
||||
array(SAPLING, 2),
|
||||
array(LEAVES, 0),
|
||||
array(LEAVES, 1),
|
||||
array(LEAVES, 2),
|
||||
array(SEEDS, 0),
|
||||
array(MELON_SEEDS, 0),
|
||||
array(DYE, 15), //Bonemeal
|
||||
array(IRON_HOE, 0),
|
||||
array(CAKE, 0),
|
||||
array(EGG, 0),
|
||||
array(IRON_SWORD, 0),
|
||||
array(BOW, 0),
|
||||
array(SIGN, 0),
|
||||
array(SPAWN_EGG, MOB_CHICKEN),
|
||||
array(SPAWN_EGG, MOB_COW),
|
||||
array(SPAWN_EGG, MOB_PIG),
|
||||
array(SPAWN_EGG, MOB_SHEEP),
|
||||
);
|
||||
|
||||
public static function fromString($str){
|
||||
public static function fromString($str, $multiple = false){
|
||||
if($multiple === true){
|
||||
$blocks = array();
|
||||
foreach(explode(",",$str) as $b){
|
||||
$blocks[] = BlockAPI::fromString($b, false);
|
||||
}
|
||||
return $blocks;
|
||||
}else{
|
||||
$b = explode(":", str_replace(" ", "_", trim($str)));
|
||||
if(!isset($b[1])){
|
||||
$meta = 0;
|
||||
@ -56,6 +170,7 @@ class BlockAPI{
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
public static function get($id, $meta = 0, $v = false){
|
||||
$id = (int) $id;
|
||||
@ -65,7 +180,7 @@ class BlockAPI{
|
||||
}else{
|
||||
$b = new GenericBlock($id, $meta);
|
||||
}
|
||||
if($v instanceof Vector3){
|
||||
if($v instanceof Position){
|
||||
$b->position($v);
|
||||
}
|
||||
return $b;
|
||||
@ -82,35 +197,13 @@ class BlockAPI{
|
||||
return $i;
|
||||
}
|
||||
|
||||
public function setBlock($block, $id, $meta, $update = true, $tiles = false){
|
||||
if(($block instanceof Vector3) or (($block instanceof Block) and $block->inWorld === true)){
|
||||
$this->server->api->level->setBlock($block->x, $block->y, $block->z, (int) $id, (int) $meta, $update, $tiles);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBlock($x, $y = 0, $z = 0){
|
||||
if($x instanceof Vector3){
|
||||
$y = $x->y;
|
||||
$z = $x->z;
|
||||
$x = $x->x;
|
||||
}
|
||||
$b = $this->server->api->level->getBlock($x, $y, $z);
|
||||
return BlockAPI::get($b[0], $b[1], new Vector3($b[2][0], $b[2][1], $b[2][2]));
|
||||
}
|
||||
|
||||
public function getBlockFace(Block $block, $face){
|
||||
return $this->getBlock($block->getSide($face));
|
||||
}
|
||||
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->server->addHandler("block.update", array($this, "updateBlockRemote"), 1);
|
||||
$this->server->api->console->register("give", "Give items to a player", array($this, "commandHandler"));
|
||||
$this->server->schedule(1, array($this, "blockUpdateTick"), array(), true);
|
||||
$this->server->api->console->register("give", "<player> <item[:damage]> [amount]", array($this, "commandHandler"));
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||
@ -118,10 +211,10 @@ class BlockAPI{
|
||||
switch($cmd){
|
||||
case "give":
|
||||
if(!isset($params[0]) or !isset($params[1])){
|
||||
$output .= "Usage: /give <username> <item> [amount] [damage]\n";
|
||||
$output .= "Usage: /give <player> <item[:damage]> [amount]\n";
|
||||
break;
|
||||
}
|
||||
$username = $params[0];
|
||||
$player = $this->server->api->player->get($params[0]);
|
||||
$item = BlockAPI::fromString($params[1]);
|
||||
|
||||
if(!isset($params[2])){
|
||||
@ -130,11 +223,19 @@ class BlockAPI{
|
||||
$item->count = (int) $params[2];
|
||||
}
|
||||
|
||||
if(($player = $this->server->api->player->get($username)) !== false){
|
||||
$this->drop(new Vector3($player->entity->x - 0.5, $player->entity->y, $player->entity->z - 0.5), $item, true);
|
||||
$output .= "Giving ".$item->count." of ".$item->getName()." (".$item->getID().":".$item->getMetadata().") to ".$username."\n";
|
||||
if($player instanceof Player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
$output .= "Player is in creative mode.\n";
|
||||
break;
|
||||
}
|
||||
if($item->getID() == 0) {
|
||||
$output .= "You cannot give an air block to a player.\n";
|
||||
break;
|
||||
}
|
||||
$player->addItem($item->getID(), $item->getMetadata(), $item->count);
|
||||
$output .= "Giving ".$item->count." of ".$item->getName()." (".$item->getID().":".$item->getMetadata().") to ".$player->username."\n";
|
||||
}else{
|
||||
$output .= "Unknown player\n";
|
||||
$output .= "Unknown player.\n";
|
||||
}
|
||||
|
||||
break;
|
||||
@ -142,7 +243,7 @@ class BlockAPI{
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function cancelAction(Block $block, Player $player){
|
||||
private function cancelAction(Block $block, Player $player, $send = true){
|
||||
$player->dataPacket(MC_UPDATE_BLOCK, array(
|
||||
"x" => $block->x,
|
||||
"y" => $block->y,
|
||||
@ -150,164 +251,127 @@ class BlockAPI{
|
||||
"block" => $block->getID(),
|
||||
"meta" => $block->getMetadata()
|
||||
));
|
||||
if($send === true){
|
||||
$player->sendInventorySlot($player->slot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function playerBlockBreak(Player $player, Vector3 $vector){
|
||||
|
||||
$target = $this->getBlock($vector);
|
||||
$item = $player->equipment;
|
||||
if(!$target->isBreakable($item, $player) or $player->gamemode === ADVENTURE or ($player->lastBreak + $target->getBreakTime($item, $player)) >= microtime(true)){
|
||||
return $this->cancelAction($target, $player);
|
||||
$target = $player->level->getBlock($vector);
|
||||
$item = $player->getSlot($player->slot);
|
||||
|
||||
if($this->server->api->dhandle("player.block.touch", array("type" => "break", "player" => $player, "target" => $target, "item" => $item)) === false){
|
||||
return $this->cancelAction($target, $player, false);
|
||||
}
|
||||
|
||||
if((!$target->isBreakable($item, $player) and $this->server->api->dhandle("player.block.break.invalid", array("player" => $player, "target" => $target, "item" => $item)) !== true) or ($player->gamemode & 0x02) === 0x02 or (($player->lastBreak - $player->getLag() / 1000) + $target->getBreakTime($item, $player) - 0.1) >= microtime(true)){
|
||||
return $this->cancelAction($target, $player, false);
|
||||
}
|
||||
$player->lastBreak = microtime(true);
|
||||
|
||||
if($this->server->api->dhandle("player.block.break", array("player" => $player, "target" => $target, "item" => $item)) !== false){
|
||||
$player->lastBreak = microtime(true);
|
||||
if($target->onBreak($item, $player) === false){
|
||||
return $this->cancelAction($target, $player, false);
|
||||
}
|
||||
$item->useOn($target);
|
||||
if($item->getMetadata() >= $item->getMaxDurability()){
|
||||
$player->setSlot($player->slot, new Item(AIR, 0, 0), false);
|
||||
}
|
||||
$drops = $target->getDrops($item, $player);
|
||||
$target->onBreak($this, $item, $player);
|
||||
}else{
|
||||
return $this->cancelAction($target, $player);
|
||||
return $this->cancelAction($target, $player, false);
|
||||
}
|
||||
|
||||
|
||||
if(count($drops) > 0){
|
||||
if(($player->gamemode & 0x01) === 0x00 and count($drops) > 0){
|
||||
foreach($drops as $drop){
|
||||
$this->drop($target, BlockAPI::getItem($drop[0] & 0xFFFF, $drop[1] & 0xFFFF, $drop[2] & 0xFF));
|
||||
$this->server->api->entity->drop(new Position($target->x + 0.5, $target->y, $target->z + 0.5, $target->level), BlockAPI::getItem($drop[0] & 0xFFFF, $drop[1] & 0xFFFF, $drop[2]));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function drop(Vector3 $pos, Item $item, $force = false){
|
||||
if($item->getID() === AIR or $item->count <= 0 or ($this->server->gamemode === CREATIVE and $force !== true)){
|
||||
return;
|
||||
}
|
||||
$data = array(
|
||||
"x" => $pos->x + mt_rand(2, 8) / 10,
|
||||
"y" => $pos->y + 0.19,
|
||||
"z" => $pos->z + mt_rand(2, 8) / 10,
|
||||
"item" => $item,
|
||||
);
|
||||
if($this->server->api->handle("block.drop", $data) !== false){
|
||||
for($count = $item->count; $count > 0; ){
|
||||
$item->count = min($item->getMaxStackSize(), $count);
|
||||
$count -= $item->count;
|
||||
$server = ServerAPI::request();
|
||||
$e = $server->api->entity->add(ENTITY_ITEM, $item->getID(), $data);
|
||||
//$e->speedX = mt_rand(-10, 10) / 100;
|
||||
//$e->speedY = mt_rand(0, 5) / 100;
|
||||
//$e->speedZ = mt_rand(-10, 10) / 100;
|
||||
$server->api->entity->spawnToAll($e->eid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function playerBlockAction(Player $player, Vector3 $vector, $face, $fx, $fy, $fz){
|
||||
if($face < 0 or $face > 5){
|
||||
return false;
|
||||
}
|
||||
|
||||
$target = $this->getBlock($vector);
|
||||
$block = $this->getBlockFace($target, $face);
|
||||
$item = $player->equipment;
|
||||
$target = $player->level->getBlock($vector);
|
||||
$block = $target->getSide($face);
|
||||
$item = $player->getSlot($player->slot);
|
||||
|
||||
if($target->getID() === AIR){ //If no block exists
|
||||
if($target->getID() === AIR and $this->server->api->dhandle("player.block.place.invalid", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== true){ //If no block exists or not allowed in CREATIVE
|
||||
$this->cancelAction($target, $player);
|
||||
return $this->cancelAction($block, $player);
|
||||
}
|
||||
|
||||
if($this->server->api->dhandle("player.block.touch", array("type" => "place", "player" => $player, "block" => $block, "target" => $target, "item" => $item)) === false){
|
||||
return $this->cancelAction($block, $player);
|
||||
}
|
||||
$this->blockUpdate($target, BLOCK_UPDATE_TOUCH);
|
||||
|
||||
if($target->isActivable === true){
|
||||
if($this->server->api->dhandle("player.block.activate", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== false and $target->onActivate($this, $item, $player) === true){
|
||||
if($this->server->api->dhandle("player.block.activate", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== false and $target->onActivate($item, $player) === true){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if($player->gamemode === ADVENTURE){ //Adventure mode!!
|
||||
return $this->cancelAction($block, $player);
|
||||
}
|
||||
|
||||
/*if(isset(Material::$activable[$target[0]])){
|
||||
switch($target[0]){
|
||||
case 54:
|
||||
$cancelPlace = true;
|
||||
if($this->server->gamemode === 1){
|
||||
break;
|
||||
if(($player->gamemode & 0x02) === 0x02){ //Adventure mode!!
|
||||
return $this->cancelAction($block, $player, false);
|
||||
}
|
||||
$this->server->api->player->getByEID($data["eid"])->dataPacket(MC_CONTAINER_OPEN, array(
|
||||
"windowid" => 1,
|
||||
"type" => WINDOW_CHEST,
|
||||
"slots" => 27,
|
||||
"title" => "Chest",
|
||||
));
|
||||
break;
|
||||
case 61:
|
||||
case 62:
|
||||
$cancelPlace = true;
|
||||
if($this->server->gamemode === 1){
|
||||
break;
|
||||
}
|
||||
$this->server->api->player->getByEID($data["eid"])->dataPacket(MC_CONTAINER_OPEN, array(
|
||||
"windowid" => 1,
|
||||
"type" => WINDOW_FURNACE,
|
||||
"slots" => 3,
|
||||
"title" => "Furnace",
|
||||
));
|
||||
break;
|
||||
default:
|
||||
$cancelPlace = true;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
if($block->y > 127 or $block->y < 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($item->isActivable === true and $item->onActivate($this, $player, $block, $target, $face, $fx, $fy, $fz)){
|
||||
return $this->cancelAction($block, $player);
|
||||
if($item->isActivable === true and $item->onActivate($player->level, $player, $block, $target, $face, $fx, $fy, $fz) === true){
|
||||
if($item->count <= 0){
|
||||
$player->setSlot($player->slot, BlockAPI::getItem(AIR, 0, 0), false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if($item->isPlaceable()){
|
||||
$hand = $item->getBlock();
|
||||
$hand->position($block);
|
||||
}elseif($block->getID() === FIRE){
|
||||
$player->level->setBlock($block, new AirBlock());
|
||||
return false;
|
||||
}else{
|
||||
return $this->cancelAction($block, $player);
|
||||
return $this->cancelAction($block, $player, false);
|
||||
}
|
||||
|
||||
if(!($block->isReplaceable === true or ($hand->getID() === SLAB and $block->getID() === SLAB))){
|
||||
return $this->cancelAction($block, $player);
|
||||
return $this->cancelAction($block, $player, false);
|
||||
}
|
||||
|
||||
if($hand->isTransparent === false and $player->entity->inBlock($block->x, $block->y, $block->z)){
|
||||
return $this->cancelAction($block, $player); //Entity in block
|
||||
if($hand->isSolid === true and $player->entity->inBlock($block)){
|
||||
return $this->cancelAction($block, $player, false); //Entity in block
|
||||
}
|
||||
|
||||
if($this->server->api->dhandle("player.block.place", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) === false){
|
||||
return $this->cancelAction($block, $player);
|
||||
}elseif($hand->place($this, $item, $player, $block, $target, $face, $fx, $fy, $fz) === false){
|
||||
return $this->cancelAction($block, $player);
|
||||
}elseif($hand->place($item, $player, $block, $target, $face, $fx, $fy, $fz) === false){
|
||||
return $this->cancelAction($block, $player, false);
|
||||
}
|
||||
if($hand->getID() === SIGN_POST or $hand->getID() === WALL_POST){
|
||||
$t = $this->server->api->tileentity->addSign($block->x, $block->y, $block->z);
|
||||
if($hand->getID() === SIGN_POST or $hand->getID() === WALL_SIGN){
|
||||
$t = $this->server->api->tile->addSign($player->level, $block->x, $block->y, $block->z);
|
||||
$t->data["creator"] = $player->username;
|
||||
}
|
||||
|
||||
if($this->server->gamemode === SURVIVAL or $this->server->gamemode === ADVENTURE){
|
||||
$player->removeItem($item->getID(), $item->getMetadata(), 1);
|
||||
if(($player->gamemode & 0x01) === 0x00){
|
||||
--$item->count;
|
||||
if($item->count <= 0){
|
||||
$player->setSlot($player->slot, BlockAPI::getItem(AIR, 0, 0), false);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function blockScheduler($data){
|
||||
$this->updateBlock($data["x"], $data["y"], $data["z"], BLOCK_UPDATE_SCHEDULED);
|
||||
}
|
||||
|
||||
public function updateBlockRemote($data, $event){
|
||||
if($event !== "block.update"){
|
||||
return;
|
||||
}
|
||||
$this->updateBlock($data["x"], $data["y"], $data["z"], isset($data["type"]) ? $data["type"]:BLOCK_UPDATE_RANDOM);
|
||||
}
|
||||
/*
|
||||
|
||||
public function flowLavaOn($source, $face){
|
||||
$down = 0;
|
||||
@ -654,25 +718,6 @@ class BlockAPI{
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 74:
|
||||
if($type === BLOCK_UPDATE_SCHEDULED or $type === BLOCK_UPDATE_RANDOM){
|
||||
$changed = true;
|
||||
$this->server->api->level->setBlock($x, $y, $z, 73, $block[1], false);
|
||||
$type = BLOCK_UPDATE_WEAK;
|
||||
}
|
||||
break;
|
||||
case 73:
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
$changed = true;
|
||||
$this->server->api->level->setBlock($x, $y, $z, 74, $block[1], false);
|
||||
$this->server->schedule(mt_rand(40, 100), array($this, "blockScheduler"), array(
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
));
|
||||
$type = BLOCK_UPDATE_WEAK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if($type === BLOCK_TYPE_SCHEDULED){
|
||||
@ -681,14 +726,107 @@ class BlockAPI{
|
||||
if($changed === true){
|
||||
$this->updateBlocksAround($x, $y, $z, $type);
|
||||
}
|
||||
}*/
|
||||
|
||||
public function blockUpdateAround(Position $pos, $type = BLOCK_UPDATE_NORMAL, $delay = false){
|
||||
if($delay !== false){
|
||||
$this->scheduleBlockUpdate($pos->getSide(0), $delay, $type);
|
||||
$this->scheduleBlockUpdate($pos->getSide(1), $delay, $type);
|
||||
$this->scheduleBlockUpdate($pos->getSide(2), $delay, $type);
|
||||
$this->scheduleBlockUpdate($pos->getSide(3), $delay, $type);
|
||||
$this->scheduleBlockUpdate($pos->getSide(4), $delay, $type);
|
||||
$this->scheduleBlockUpdate($pos->getSide(5), $delay, $type);
|
||||
}else{
|
||||
$this->blockUpdate($pos->getSide(0), $type);
|
||||
$this->blockUpdate($pos->getSide(1), $type);
|
||||
$this->blockUpdate($pos->getSide(2), $type);
|
||||
$this->blockUpdate($pos->getSide(3), $type);
|
||||
$this->blockUpdate($pos->getSide(4), $type);
|
||||
$this->blockUpdate($pos->getSide(5), $type);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateBlocksAround($x, $y, $z, $type){
|
||||
$this->updateBlock($x + 1, $y, $z, $type);
|
||||
$this->updateBlock($x, $y + 1, $z, $type);
|
||||
$this->updateBlock($x, $y, $z + 1, $type);
|
||||
$this->updateBlock($x - 1, $y, $z, $type);
|
||||
$this->updateBlock($x, $y - 1, $z, $type);
|
||||
$this->updateBlock($x, $y, $z - 1, $type);
|
||||
public function blockUpdate(Position $pos, $type = BLOCK_UPDATE_NORMAL){
|
||||
if(!($pos instanceof Block)){
|
||||
$block = $pos->level->getBlock($pos);
|
||||
}else{
|
||||
$pos = new Position($pos->x, $pos->y, $pos->z, $pos->level);
|
||||
$block = $pos->level->getBlock($pos);
|
||||
}
|
||||
if($block === false){
|
||||
return false;
|
||||
}
|
||||
|
||||
$level = $block->onUpdate($type);
|
||||
if($level === BLOCK_UPDATE_NORMAL){
|
||||
$this->blockUpdateAround($block, $level);
|
||||
$this->server->api->entity->updateRadius($pos, 1);
|
||||
}elseif($level === BLOCK_UPDATE_RANDOM){
|
||||
$this->nextRandomUpdate($pos);
|
||||
}
|
||||
return $level;
|
||||
}
|
||||
|
||||
public function scheduleBlockUpdate(Position $pos, $delay, $type = BLOCK_UPDATE_SCHEDULED){
|
||||
$type = (int) $type;
|
||||
if($delay < 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$index = $pos->x.".".$pos->y.".".$pos->z.".".$pos->level->getName().".".$type;
|
||||
$delay = microtime(true) + $delay * 0.05;
|
||||
if(!isset($this->scheduledUpdates[$index])){
|
||||
$this->scheduledUpdates[$index] = $pos;
|
||||
$this->server->query("INSERT INTO blockUpdates (x, y, z, level, type, delay) VALUES (".$pos->x.", ".$pos->y.", ".$pos->z.", '".$pos->level->getName()."', ".$type.", ".$delay.");");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function nextRandomUpdate(Position $pos){
|
||||
if(!isset($this->scheduledUpdates[$pos->x.".".$pos->y.".".$pos->z.".".$pos->level->getName().".".BLOCK_UPDATE_RANDOM])){
|
||||
$X = (($pos->x >> 4) << 4);
|
||||
$Y = (($pos->y >> 4) << 4);
|
||||
$Z = (($pos->z >> 4) << 4);
|
||||
$time = microtime(true);
|
||||
$i = 0;
|
||||
$offset = 0;
|
||||
while(true){
|
||||
$t = $offset + Utils::getRandomUpdateTicks() * 0.05;
|
||||
$update = $this->server->query("SELECT COUNT(*) FROM blockUpdates WHERE level = '".$pos->level->getName()."' AND type = ".BLOCK_UPDATE_RANDOM." AND delay >= ".($time + $t - 1)." AND delay <= ".($time + $t + 1).";");
|
||||
if($update instanceof SQLite3Result){
|
||||
$update = $update->fetchArray(SQLITE3_NUM);
|
||||
if($update[0] < 3){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
$offset += mt_rand(25, 75);
|
||||
}
|
||||
$this->scheduleBlockUpdate($pos, $t / 0.05, BLOCK_UPDATE_RANDOM);
|
||||
}
|
||||
}
|
||||
|
||||
public function blockUpdateTick(){
|
||||
$time = microtime(true);
|
||||
if(count($this->scheduledUpdates) > 0){
|
||||
$update = $this->server->query("SELECT x,y,z,level,type FROM blockUpdates WHERE delay <= ".$time.";");
|
||||
if($update instanceof SQLite3Result){
|
||||
$upp = array();
|
||||
while(($up = $update->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$index = $up["x"].".".$up["y"].".".$up["z"].".".$up["level"].".".$up["type"];
|
||||
if(isset($this->scheduledUpdates[$index])){
|
||||
$upp[] = array((int) $up["type"], $this->scheduledUpdates[$index]);
|
||||
unset($this->scheduledUpdates[$index]);
|
||||
}
|
||||
}
|
||||
$this->server->query("DELETE FROM blockUpdates WHERE delay <= ".$time.";");
|
||||
foreach($upp as $b){
|
||||
$this->blockUpdate($b[1], $b[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,17 +27,75 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class ChatAPI{
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->server->api->console->register("tell", "<player> <private message ...>", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("me", "<action ...>", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("say", "<message ...>", array($this, "commandHandler"));
|
||||
$this->server->api->ban->cmdWhitelist("tell");
|
||||
$this->server->api->ban->cmdWhitelist("me");
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||
$output = "";
|
||||
switch($cmd){
|
||||
case "say":
|
||||
$s = implode(" ", $params);
|
||||
if(trim($s) == ""){
|
||||
$output .= "Usage: /say <message>\n";
|
||||
break;
|
||||
}
|
||||
$sender = ($issuer instanceof Player) ? "Server":ucfirst($issuer);
|
||||
$this->server->api->chat->broadcast("[$sender] ".$s);
|
||||
break;
|
||||
case "me":
|
||||
if(!($issuer instanceof Player)){
|
||||
if($issuer === "rcon"){
|
||||
$sender = "Rcon";
|
||||
}else{
|
||||
$sender = ucfirst($issuer);
|
||||
}
|
||||
}else{
|
||||
$sender = $issuer->username;
|
||||
}
|
||||
$this->broadcast("* $sender ".implode(" ", $params));
|
||||
break;
|
||||
case "tell":
|
||||
if(!isset($params[0]) or !isset($params[1])){
|
||||
$output .= "Usage: /$cmd <player> <message>\n";
|
||||
break;
|
||||
}
|
||||
if(!($issuer instanceof Player)){
|
||||
$sender = ucfirst($issuer);
|
||||
}else{
|
||||
$sender = $issuer->username;
|
||||
}
|
||||
$n = array_shift($params);
|
||||
$target = $this->server->api->player->get($n);
|
||||
if($target instanceof Player){
|
||||
$target = $target->username;
|
||||
}else{
|
||||
$target = strtolower($n);
|
||||
if($t === "server" or $t === "console" or $t === "rcon"){
|
||||
$target = "Console";
|
||||
}
|
||||
}
|
||||
$mes = implode(" ", $params);
|
||||
$output .= "[me -> ".$target."] ".$mes."\n";
|
||||
if($target !== "Console" and $target !== "Rcon"){
|
||||
$this->sendTo(false, "[".$sender." -> me] ".$mes, $target);
|
||||
}
|
||||
console("[INFO] [".$sender." -> ".$target."] ".$mes);
|
||||
break;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function broadcast($message){
|
||||
$this->send(false, $message);
|
||||
console("[CHAT] ".$message);
|
||||
}
|
||||
|
||||
public function sendTo($owner, $text, $player){
|
||||
@ -54,6 +112,9 @@ class ChatAPI{
|
||||
}
|
||||
}
|
||||
$message .= $text;
|
||||
if($whitelist === false){
|
||||
console("[INFO] ".$message);
|
||||
}
|
||||
$this->server->handle("server.chat", new Container($message, $whitelist, $blacklist));
|
||||
}
|
||||
}
|
@ -27,57 +27,60 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class ConsoleAPI{
|
||||
private $loop, $server, $event, $help, $cmds, $alias;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
function __construct(){
|
||||
$this->help = array();
|
||||
$this->cmds = array();
|
||||
$this->alias = array();
|
||||
$this->server = $server;
|
||||
$this->server = ServerAPI::request();
|
||||
$this->last = microtime(true);
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->event = $this->server->event("server.tick", array($this, "handle"));
|
||||
$this->loop = new ConsoleLoop;
|
||||
$this->loop->start();
|
||||
$this->server->schedule(2, array($this, "handle"), array(), true);
|
||||
$this->loop = new ConsoleLoop();
|
||||
$this->register("help", "[page|command name]", array($this, "defaultCommands"));
|
||||
$this->register("status", "", array($this, "defaultCommands"));
|
||||
$this->register("difficulty", "<0|1|2|3>", array($this, "defaultCommands"));
|
||||
$this->register("stop", "", array($this, "defaultCommands"));
|
||||
$this->register("defaultgamemode", "<mode>", array($this, "defaultCommands"));
|
||||
$this->server->api->ban->cmdWhitelist("help");
|
||||
}
|
||||
|
||||
function __destruct(){
|
||||
$this->server->deleteEvent($this->event);
|
||||
$this->loop->stop = true;
|
||||
$this->loop->stop();
|
||||
$this->loop->notify();
|
||||
$this->loop->join();
|
||||
//$this->loop->join();
|
||||
}
|
||||
|
||||
public function defaultCommands($cmd, $params, $issuer, $alias){
|
||||
$output = "";
|
||||
switch($cmd){
|
||||
case "crash": //Crashes the server to generate an report
|
||||
$this->callNotDefinedMethodCrash();
|
||||
$this->server->api->server; //Access a private property
|
||||
callNotExistingFunction();
|
||||
break;
|
||||
case "invisible":
|
||||
$p = strtolower(array_shift($params));
|
||||
switch($p){
|
||||
case "on":
|
||||
case "true":
|
||||
case "1":
|
||||
$output .= "Server is invisible\n";
|
||||
$this->server->api->setProperty("invisible", true);
|
||||
break;
|
||||
case "off":
|
||||
case "false":
|
||||
case "0":
|
||||
$output .= "Server is visible\n";
|
||||
$this->server->api->setProperty("invisible", false);
|
||||
break;
|
||||
default:
|
||||
$output .= "Usage: /invisible <on | off>\n";
|
||||
case "defaultgamemode":
|
||||
$gms = array(
|
||||
"0" => SURVIVAL,
|
||||
"survival" => SURVIVAL,
|
||||
"s" => SURVIVAL,
|
||||
"1" => CREATIVE,
|
||||
"creative" => CREATIVE,
|
||||
"c" => CREATIVE,
|
||||
"2" => ADVENTURE,
|
||||
"adventure" => ADVENTURE,
|
||||
"a" => ADVENTURE,
|
||||
"3" => VIEW,
|
||||
"view" => VIEW,
|
||||
"viewer" => VIEW,
|
||||
"spectator" => VIEW,
|
||||
"v" => VIEW,
|
||||
);
|
||||
if(!isset($gms[strtolower($params[0])])){
|
||||
$output .= "Usage: /$cmd <mode>\n";
|
||||
break;
|
||||
}
|
||||
$this->server->api->setProperty("gamemode", $gms[strtolower($params[0])]);
|
||||
$output .= "Default Gamemode is now ".strtoupper($this->server->getGamemode()).".\n";
|
||||
break;
|
||||
case "status":
|
||||
case "lag":
|
||||
if(!($issuer instanceof Player) and $issuer === "console"){
|
||||
$this->server->debugInfo(true);
|
||||
}
|
||||
@ -92,48 +95,53 @@ class ConsoleAPI{
|
||||
$output .= "Stopping the server\n";
|
||||
$this->server->close();
|
||||
break;
|
||||
case "gamemode":
|
||||
$s = trim(array_shift($params));
|
||||
if($s == "" or (((int) $s) !== 0 and ((int) $s) !== 1 and ((int) $s) !== 2)){
|
||||
$output .= "Usage: /gamemode <0 | 1 | 2>\n";
|
||||
break;
|
||||
}
|
||||
$this->server->api->setProperty("gamemode", (int) $s);
|
||||
$output .= "Gamemode changed to ".$this->server->getGamemode()."\n";
|
||||
break;
|
||||
case "difficulty":
|
||||
$s = trim(array_shift($params));
|
||||
if($s == "" or (((int) $s) !== 0 and ((int) $s) !== 1)){
|
||||
$output .= "Usage: /difficulty <0 | 1>\n";
|
||||
if($s === "" or (((int) $s) > 3 and ((int) $s) < 0)){
|
||||
$output .= "Usage: /difficulty <0|1|2|3>\n";
|
||||
break;
|
||||
}
|
||||
$this->server->api->setProperty("difficulty", (int) $s);
|
||||
$output .= "Difficulty changed to ".$this->server->difficulty."\n";
|
||||
loadConfig(true);
|
||||
break;
|
||||
case "say":
|
||||
$s = implode(" ", $params);
|
||||
if(trim($s) == ""){
|
||||
$output .= "Usage: /say <message>\n";
|
||||
case "?":
|
||||
if($issuer !== "console" and $issuer !== "rcon"){
|
||||
break;
|
||||
}
|
||||
$this->server->api->chat->broadcast($s);
|
||||
break;
|
||||
case "save-all":
|
||||
$this->server->save();
|
||||
break;
|
||||
case "help":
|
||||
case "?":
|
||||
$output .= "/help: Show available commands\n";
|
||||
$output .= "/status: Show server TPS and memory usage\n";
|
||||
$output .= "/gamemode: Changes default gamemode\n";
|
||||
$output .= "/difficulty: Changes difficulty\n";
|
||||
$output .= "/invisible: Manages server visibility\n";
|
||||
$output .= "/say: Broadcasts mesages\n";
|
||||
$output .= "/save-all: Saves pending changes\n";
|
||||
$output .= "/stop: Stops the server\n";
|
||||
if(isset($params[0]) and !is_numeric($params[0])){
|
||||
$c = trim(strtolower($params[0]));
|
||||
if(isset($this->help[$c]) or isset($this->alias[$c])){
|
||||
$c = isset($this->help[$c]) ? $c : $this->alias[$c];
|
||||
if($this->server->api->dhandle("console.command.".$c, array("cmd" => $c, "parameters" => array(), "issuer" => $issuer, "alias" => false)) === false
|
||||
or $this->server->api->dhandle("console.command", array("cmd" => $c, "parameters" => array(), "issuer" => $issuer, "alias" => false)) === false){
|
||||
break;
|
||||
}
|
||||
$output .= "Usage: /$c ".$this->help[$c]."\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$cmds = array();
|
||||
foreach($this->help as $c => $h){
|
||||
$output .= "/$c: ".$h."\n";
|
||||
if($this->server->api->dhandle("console.command.".$c, array("cmd" => $c, "parameters" => array(), "issuer" => $issuer, "alias" => false)) === false
|
||||
or $this->server->api->dhandle("console.command", array("cmd" => $c, "parameters" => array(), "issuer" => $issuer, "alias" => false)) === false){
|
||||
continue;
|
||||
}
|
||||
$cmds[$c] = $h;
|
||||
}
|
||||
|
||||
$max = ceil(count($cmds) / 5);
|
||||
$page = (int) (isset($params[0]) ? min($max, max(1, intval($params[0]))):1);
|
||||
$output .= "- Showing help page $page of $max (/help <page>) -\n";
|
||||
$current = 1;
|
||||
foreach($cmds as $c => $h){
|
||||
$curpage = (int) ceil($current / 5);
|
||||
if($curpage === $page){
|
||||
$output .= "/$c ".$h."\n";
|
||||
}elseif($curpage > $page){
|
||||
break;
|
||||
}
|
||||
++$current;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -155,40 +163,95 @@ class ConsoleAPI{
|
||||
$cmd = strtolower(trim($cmd));
|
||||
$this->cmds[$cmd] = $callback;
|
||||
$this->help[$cmd] = $help;
|
||||
ksort($this->help, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
}
|
||||
|
||||
public function run($line = "", $issuer = false, $alias = false){
|
||||
public function run($line = "", $issuer = "console", $alias = false){
|
||||
if($line != ""){
|
||||
$params = explode(" ", $line);
|
||||
$cmd = strtolower(array_shift($params));
|
||||
$end = strpos($line, " ");
|
||||
if($end === false){
|
||||
$end = strlen($line);
|
||||
}
|
||||
$cmd = strtolower(substr($line, 0, $end));
|
||||
$params = (string) substr($line, $end + 1);
|
||||
if(isset($this->alias[$cmd])){
|
||||
$this->run($this->alias[$cmd] . " " .implode(" ", $params), $issuer, $cmd);
|
||||
return;
|
||||
return $this->run($this->alias[$cmd] . ($params !== "" ? " " .$params:""), $issuer, $cmd);
|
||||
}
|
||||
if($issuer instanceof Player){
|
||||
console("[INFO] \"".$issuer->username."\" issued server command: $alias /$cmd ".implode(" ", $params));
|
||||
console("[DEBUG] \x1b[33m".$issuer->username."\x1b[0m issued server command: ".ltrim("$alias ")."/$cmd ".$params, true, true, 2);
|
||||
}else{
|
||||
console("[INFO] Issued server command: $alias /$cmd ".implode(" ", $params));
|
||||
console("[DEBUG] \x1b[33m*".$issuer."\x1b[0m issued server command: ".ltrim("$alias ")."/$cmd ".$params, true, true, 2);
|
||||
}
|
||||
if($this->server->api->dhandle("console.command.".$cmd, array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias)) === false
|
||||
or $this->server->api->dhandle("console.command", array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias)) === false){
|
||||
$output = "You don't have permissions\n";
|
||||
}else{
|
||||
|
||||
if(preg_match_all('#@([@a-z]{1,})#', $params, $matches, PREG_OFFSET_CAPTURE) > 0){
|
||||
$offsetshift = 0;
|
||||
foreach($matches[1] as $selector){
|
||||
if($selector[0]{0} === "@"){ //Escape!
|
||||
$params = substr_replace($params, $selector[0], $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1);
|
||||
--$offsetshift;
|
||||
continue;
|
||||
}
|
||||
switch(strtolower($selector[0])){
|
||||
case "u":
|
||||
case "player":
|
||||
case "username":
|
||||
$p = ($issuer instanceof Player) ? $issuer->username:$issuer;
|
||||
$params = substr_replace($params, $p, $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1);
|
||||
$offsetshift -= strlen($selector[0]) - strlen($p) + 1;
|
||||
break;
|
||||
case "w":
|
||||
case "world":
|
||||
$p = ($issuer instanceof Player) ? $issuer->level->getName():$this->server->api->level->getDefault()->getName();
|
||||
$params = substr_replace($params, $p, $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1);
|
||||
$offsetshift -= strlen($selector[0]) - strlen($p) + 1;
|
||||
break;
|
||||
case "a":
|
||||
case "all":
|
||||
$output = "";
|
||||
foreach($this->server->api->player->getAll() as $p){
|
||||
$output .= $this->run($cmd . " ". substr_replace($params, $p->username, $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1), $issuer, $alias);
|
||||
}
|
||||
return $output;
|
||||
case "r":
|
||||
case "random":
|
||||
$l = array();
|
||||
foreach($this->server->api->player->getAll() as $p){
|
||||
if($p !== $issuer){
|
||||
$l[] = $p;
|
||||
}
|
||||
}
|
||||
if(count($l) === 0){
|
||||
return;
|
||||
}
|
||||
|
||||
$p = $l[mt_rand(0, count($l) - 1)]->username;
|
||||
$params = substr_replace($params, $p, $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1);
|
||||
$offsetshift -= strlen($selector[0]) - strlen($p) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$params = explode(" ", $params);
|
||||
if(count($params) === 1 and $params[0] === ""){
|
||||
$params = array();
|
||||
}
|
||||
|
||||
if(($d1 = $this->server->api->dhandle("console.command.".$cmd, array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false
|
||||
or ($d2 = $this->server->api->dhandle("console.command", array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false){
|
||||
$output = "You don't have permissions to use this command.\n";
|
||||
}elseif($d1 !== true and $d2 !== true){
|
||||
if(isset($this->cmds[$cmd]) and is_callable($this->cmds[$cmd])){
|
||||
$output = @call_user_func($this->cmds[$cmd], $cmd, $params, $issuer, $alias);
|
||||
}elseif($this->server->api->dhandle("console.command.unknown", array("cmd" => $cmd, "params" => $params, "issuer" => $issuer, "alias" => $alias)) !== false){
|
||||
$output = $this->defaultCommands($cmd, $params, $issuer, $alias);
|
||||
}
|
||||
}else{
|
||||
$output = "";
|
||||
}
|
||||
if($output != "" and ($issuer instanceof Player)){
|
||||
$issuer->sendChat(trim($output));
|
||||
}elseif($output != "" and $issuer === "console"){
|
||||
$mes = explode("\n", trim($output));
|
||||
foreach($mes as $m){
|
||||
console("[CMD] ".$m);
|
||||
}
|
||||
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +259,13 @@ class ConsoleAPI{
|
||||
if($this->loop->line !== false){
|
||||
$line = trim($this->loop->line);
|
||||
$this->loop->line = false;
|
||||
$this->run($line, "console");
|
||||
$output = $this->run($line, "console");
|
||||
if($output != ""){
|
||||
$mes = explode("\n", trim($output));
|
||||
foreach($mes as $m){
|
||||
console("[CMD] ".$m);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$this->loop->notify();
|
||||
}
|
||||
@ -205,19 +274,48 @@ class ConsoleAPI{
|
||||
}
|
||||
|
||||
class ConsoleLoop extends Thread{
|
||||
public $line, $stop;
|
||||
public $line;
|
||||
public $stop;
|
||||
public $base;
|
||||
public $ev;
|
||||
public $fp;
|
||||
public function __construct(){
|
||||
$this->line = false;
|
||||
$this->stop = false;
|
||||
$this->start();
|
||||
}
|
||||
|
||||
public function stop(){
|
||||
$this->stop = true;
|
||||
}
|
||||
|
||||
private function readLine(){
|
||||
if( $this->fp ){
|
||||
$line = trim( fgets( $this->fp ) );
|
||||
} else {
|
||||
$line = trim( readline( "" ) );
|
||||
if( $line != "" ){
|
||||
readline_add_history( $line );
|
||||
}
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
public function run(){
|
||||
$fp = fopen("php://stdin", "r");
|
||||
while($this->stop === false and ($line = fgets($fp)) !== false){
|
||||
$this->line = $line;
|
||||
if( ! extension_loaded( 'readline' ) ){
|
||||
$this->fp = fopen( "php://stdin", "r" );
|
||||
}
|
||||
|
||||
while( $this->stop === false ) {
|
||||
$this->line = $this->readLine();
|
||||
$this->wait();
|
||||
$this->line = false;
|
||||
}
|
||||
|
||||
if( ! $this->haveReadline ) {
|
||||
@fclose($fp);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
@ -27,23 +27,72 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class EntityAPI{
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
private $entities;
|
||||
private $eCnt = 1;
|
||||
|
||||
function __construct(){
|
||||
$this->entities = array();
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function get($eid){
|
||||
if(isset($this->server->entities[$eid])){
|
||||
return $this->server->entities[$eid];
|
||||
if(isset($this->entities[$eid])){
|
||||
return $this->entities[$eid];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
|
||||
$this->server->schedule(25, array($this, "updateEntities"), array(), true);
|
||||
}
|
||||
|
||||
public function getAll(){
|
||||
return $this->server->entities;
|
||||
public function updateEntities(){
|
||||
$l = $this->server->query("SELECT EID FROM entities WHERE hasUpdate = 1;");
|
||||
|
||||
if($l !== false and $l !== true){
|
||||
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$e = $this->get($e["EID"]);
|
||||
if($e instanceof Entity){
|
||||
$e->update();
|
||||
$this->server->query("UPDATE entities SET hasUpdate = 0 WHERE EID = ".$e->eid.";");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updateRadius(Position $center, $radius = 15, $class = false){
|
||||
$this->server->query("UPDATE entities SET hasUpdate = 1 WHERE level = '".$center->level->getName()."' ".($class !== false ? "AND class = $class ":"")."AND abs(x - {$center->x}) <= $radius AND abs(y - {$center->y}) <= $radius AND abs(z - {$center->z}) <= $radius;");
|
||||
}
|
||||
|
||||
public function getRadius(Position $center, $radius = 15, $class = false){
|
||||
$entities = array();
|
||||
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$center->level->getName()."' ".($class !== false ? "AND class = $class ":"")."AND abs(x - {$center->x}) <= $radius AND abs(y - {$center->y}) <= $radius AND abs(z - {$center->z}) <= $radius;");
|
||||
if($l !== false and $l !== true){
|
||||
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$e = $this->get($e["EID"]);
|
||||
if($e instanceof Entity){
|
||||
$entities[$e->eid] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
public function getAll($level = null){
|
||||
if($level instanceof Level){
|
||||
$entities = array();
|
||||
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."';");
|
||||
if($l !== false and $l !== true){
|
||||
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$e = $this->get($e["EID"]);
|
||||
if($e instanceof Entity){
|
||||
$entities[$e->eid] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
return $this->entities;
|
||||
}
|
||||
|
||||
public function heal($eid, $heal = 1, $cause){
|
||||
@ -58,46 +107,70 @@ class EntityAPI{
|
||||
$e->setHealth($e->getHealth() - $attack, $cause, $force);
|
||||
}
|
||||
|
||||
public function add($class, $type = 0, $data = array()){
|
||||
$eid = $this->server->eidCnt++;
|
||||
$this->server->entities[$eid] = new Entity($this->server, $eid, $class, $type, $data);
|
||||
$this->server->handle("entity.add", $this->server->entities[$eid]);
|
||||
return $this->server->entities[$eid];
|
||||
public function add(Level $level, $class, $type = 0, $data = array()){
|
||||
$eid = $this->eCnt++;
|
||||
$this->entities[$eid] = new Entity($level, $eid, $class, $type, $data);
|
||||
$this->server->handle("entity.add", $this->entities[$eid]);
|
||||
return $this->entities[$eid];
|
||||
}
|
||||
|
||||
public function spawnTo($eid, $player){
|
||||
$e = $this->get($eid);
|
||||
if($e === false){
|
||||
return false;
|
||||
}
|
||||
$e->spawn($player);
|
||||
}
|
||||
|
||||
public function spawnToAll($eid){
|
||||
$e = $this->get($eid);
|
||||
if($e === false){
|
||||
return false;
|
||||
}
|
||||
foreach($this->server->api->player->getAll() as $player){
|
||||
if($player->eid !== false){
|
||||
public function spawnToAll(Entity $e){
|
||||
foreach($this->server->api->player->getAll($e->level) as $player){
|
||||
if($player->eid !== false and $player->eid !== $e->eid and $e->class !== ENTITY_PLAYER){
|
||||
$e->spawn($player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function spawnAll($player){
|
||||
foreach($this->getAll() as $e){
|
||||
public function drop(Position $pos, Item $item){
|
||||
if($item->getID() === AIR or $item->count <= 0){
|
||||
return;
|
||||
}
|
||||
$data = array(
|
||||
"x" => $pos->x,
|
||||
"y" => $pos->y + 0.19,
|
||||
"z" => $pos->z,
|
||||
//"speedX" => mt_rand(-3, 3) / 8,
|
||||
"speedY" => mt_rand(5, 8) / 2,
|
||||
//"speedZ" => mt_rand(-3, 3) / 8,
|
||||
"item" => $item,
|
||||
);
|
||||
if($this->server->api->handle("item.drop", $data) !== false){
|
||||
for($count = $item->count; $count > 0; ){
|
||||
$item->count = min($item->getMaxStackSize(), $count);
|
||||
$count -= $item->count;
|
||||
$e = $this->add($pos->level, ENTITY_ITEM, $item->getID(), $data);
|
||||
$this->spawnToAll($e);
|
||||
$this->server->api->handle("entity.motion", $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function spawnAll(Player $player){
|
||||
foreach($this->getAll($player->level) as $e){
|
||||
if($e->class !== ENTITY_PLAYER){
|
||||
$e->spawn($player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function remove($eid){
|
||||
if(isset($this->server->entities[$eid])){
|
||||
$entity = $this->server->entities[$eid];
|
||||
$this->server->entities[$eid] = null;
|
||||
unset($this->server->entities[$eid]);
|
||||
if(isset($this->entities[$eid])){
|
||||
$entity = $this->entities[$eid];
|
||||
$this->entities[$eid] = null;
|
||||
unset($this->entities[$eid]);
|
||||
$entity->closed = true;
|
||||
$this->server->query("DELETE FROM entities WHERE EID = ".$entity->eid.";");
|
||||
$this->server->query("DELETE FROM entities WHERE EID = ".$eid.";");
|
||||
if($entity->class === ENTITY_PLAYER){
|
||||
$this->server->api->player->broadcastPacket($this->server->api->player->getAll(), MC_REMOVE_PLAYER, array(
|
||||
"clientID" => 0,
|
||||
"eid" => $entity->eid,
|
||||
));
|
||||
}else{
|
||||
$this->server->api->player->broadcastPacket($this->server->api->player->getAll($entity->level), MC_REMOVE_ENTITY, array(
|
||||
"eid" => $entity->eid,
|
||||
));
|
||||
}
|
||||
$this->server->api->dhandle("entity.remove", $entity);
|
||||
$entity = null;
|
||||
unset($entity);
|
||||
|
@ -26,35 +26,202 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class LevelAPI{
|
||||
private $server, $map;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
$this->map = $this->server->map;
|
||||
$this->heightMap = array_fill(0, 256, array());
|
||||
private $server, $levels, $default;
|
||||
public function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
$this->levels = array();
|
||||
}
|
||||
|
||||
public function get($name){
|
||||
if(isset($this->levels[$name])){
|
||||
return $this->levels[$name];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDefault(){
|
||||
return $this->levels[$this->default];
|
||||
}
|
||||
|
||||
public function init(){
|
||||
/*$this->server->event("player.block.break", array($this, "handle"));
|
||||
$this->server->event("player.block.place", array($this, "handle"));
|
||||
$this->server->event("player.block.update", array($this, "handle"));*/
|
||||
$this->server->api->console->register("seed", "[world]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("save-all", "", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("save-on", "", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("save-off", "", array($this, "commandHandler"));
|
||||
$this->default = $this->server->api->getProperty("level-name");
|
||||
if($this->loadLevel($this->default) === false){
|
||||
$this->generateLevel($this->default, $this->server->seed);
|
||||
$this->loadLevel($this->default);
|
||||
}
|
||||
$this->server->spawn = $this->getDefault()->getSpawn();
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||
$output = "";
|
||||
switch($cmd){
|
||||
case "save-all":
|
||||
$save = $this->server->saveEnabled;
|
||||
$this->server->saveEnabled = true;
|
||||
$this->saveAll();
|
||||
$this->server->saveEnabled = $save;
|
||||
break;
|
||||
case "save-on":
|
||||
$this->server->saveEnabled = true;
|
||||
break;
|
||||
case "save-off":
|
||||
$this->server->saveEnabled = false;
|
||||
break;
|
||||
case "seed":
|
||||
if(!isset($params[0]) and ($issuer instanceof Player)){
|
||||
$output .= "Seed: ".$issuer->level->getSeed()."\n";
|
||||
}elseif(isset($params[0])){
|
||||
if(($lv = $this->server->api->level->get(trim(implode(" ", $params)))) !== false){
|
||||
$output .= "Seed: ".$lv->getSeed()."\n";
|
||||
}
|
||||
}else{
|
||||
$output .= "Seed: ".$this->server->api->level->getDefault()->getSeed()."\n";
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function generateLevel($name, $seed = false, $generator = false){
|
||||
if($this->levelExists($name)){
|
||||
return false;
|
||||
}
|
||||
$options = array();
|
||||
if($this->server->api->getProperty("generator-settings") !== false and trim($this->server->api->getProperty("generator-settings")) != ""){
|
||||
$options["preset"] = $this->server->api->getProperty("generator-settings");
|
||||
}
|
||||
|
||||
if($generator !== false and class_exists($generator)){
|
||||
$generator = new $generator($options);
|
||||
}else{
|
||||
if(strtoupper($this->server->api->getProperty("level-type")) == "FLAT"){
|
||||
$generator = new SuperflatGenerator($options);
|
||||
}else{
|
||||
$generator = new TemporalGenerator($options);
|
||||
}
|
||||
}
|
||||
$gen = new WorldGenerator($generator, $name, $seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)):(int) $seed);
|
||||
$gen->generate();
|
||||
$gen->close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function levelExists($name){
|
||||
if($name === ""){
|
||||
return false;
|
||||
}
|
||||
$path = DATA_PATH."worlds/".$name."/";
|
||||
if($this->get($name) === false and !file_exists($path."level.pmf")){
|
||||
$level = new LevelImport($path);
|
||||
if($level->import() === false){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unloadLevel(Level $level, $force = false){
|
||||
$name = $level->getName();
|
||||
if($name === $this->default and $force !== true){
|
||||
return false;
|
||||
}
|
||||
console("[INFO] Unloading level \"".$name."\"");
|
||||
$level->nextSave = PHP_INT_MAX;
|
||||
$level->save();
|
||||
foreach($this->server->api->player->getAll($level) as $player){
|
||||
$player->teleport($this->server->spawn);
|
||||
}
|
||||
foreach($this->server->api->entity->getAll($level) as $entity){
|
||||
if($entity->class !== ENTITY_PLAYER){
|
||||
$entity->close();
|
||||
}
|
||||
}
|
||||
foreach($this->server->api->tile->getAll($level) as $tile){
|
||||
$tile->close();
|
||||
}
|
||||
$level->close();
|
||||
unset($this->levels[$name]);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function loadLevel($name){
|
||||
if($this->get($name) !== false){
|
||||
return true;
|
||||
}elseif($this->levelExists($name) === false){
|
||||
console("[NOTICE] Level \"".$name."\" not found");
|
||||
return false;
|
||||
}
|
||||
$path = DATA_PATH."worlds/".$name."/";
|
||||
console("[INFO] Preparing level \"".$name."\"");
|
||||
$level = new PMFLevel($path."level.pmf");
|
||||
$entities = new Config($path."entities.yml", CONFIG_YAML);
|
||||
if(file_exists($path."tileEntities.yml")){
|
||||
@rename($path."tileEntities.yml", $path."tiles.yml");
|
||||
}
|
||||
$tiles = new Config($path."tiles.yml", CONFIG_YAML);
|
||||
$blockUpdates = new Config($path."bupdates.yml", CONFIG_YAML);
|
||||
$this->levels[$name] = new Level($level, $entities, $tiles, $blockUpdates, $name);
|
||||
foreach($entities->getAll() as $entity){
|
||||
if(!isset($entity["id"])){
|
||||
break;
|
||||
}
|
||||
if($entity["id"] === 64){ //Item Drop
|
||||
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_ITEM, $entity["Item"]["id"], array(
|
||||
"meta" => $entity["Item"]["Damage"],
|
||||
"stack" => $entity["Item"]["Count"],
|
||||
"x" => $entity["Pos"][0],
|
||||
"y" => $entity["Pos"][1],
|
||||
"z" => $entity["Pos"][2],
|
||||
"yaw" => $entity["Rotation"][0],
|
||||
"pitch" => $entity["Rotation"][1],
|
||||
));
|
||||
}elseif($entity["id"] === FALLING_SAND){
|
||||
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_FALLING, $entity["id"], $entity);
|
||||
$e->setPosition(new Vector3($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2]), $entity["Rotation"][0], $entity["Rotation"][1]);
|
||||
$e->setHealth($entity["Health"]);
|
||||
}elseif($entity["id"] === OBJECT_PAINTING or $entity["id"] === OBJECT_ARROW){ //Painting
|
||||
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_OBJECT, $entity["id"], $entity);
|
||||
$e->setPosition(new Vector3($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2]), $entity["Rotation"][0], $entity["Rotation"][1]);
|
||||
$e->setHealth($entity["Health"]);
|
||||
}else{
|
||||
$e = $this->server->api->entity->add($this->levels[$name], ENTITY_MOB, $entity["id"], $entity);
|
||||
$e->setPosition(new Vector3($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2]), $entity["Rotation"][0], $entity["Rotation"][1]);
|
||||
$e->setHealth($entity["Health"]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($tiles->getAll() as $tile){
|
||||
if(!isset($tile["id"])){
|
||||
break;
|
||||
}
|
||||
$t = $this->server->api->tile->add($this->levels[$name], $tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
|
||||
}
|
||||
|
||||
$timeu = microtime(true);
|
||||
foreach($blockUpdates->getAll() as $bupdate){
|
||||
$this->server->api->block->scheduleBlockUpdate(new Position((int) $bupdate["x"],(int) $bupdate["y"],(int) $bupdate["z"], $this->levels[$name]), (float) $bupdate["delay"], (int) $bupdate["type"]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handle($data, $event){
|
||||
switch($event){
|
||||
case "player.block.place":
|
||||
case "player.block.update":
|
||||
$b = BlockAPI::get($data["block"], $data["meta"]);
|
||||
console("[DEBUG] Player ".$data["entity"]->player->username." placed ".$b->getName()." (".$data["block"].":".$data["meta"].") at (".$data["x"].", ".$data["y"].", ".$data["z"].")", true, true, 2);
|
||||
$this->setBlock($data["x"], $data["y"], $data["z"], $data["block"], $data["meta"]);
|
||||
break;
|
||||
case "player.block.break":
|
||||
if($data["block"]->getID() === 0){
|
||||
break;
|
||||
}
|
||||
$b = BlockAPI::get($block[0], $block[1]);
|
||||
console("[DEBUG] Player ".$data["player"]->username." broke ".$data["block"]->getName()." (".$data["block"]->getID().":".$data["block"]->getMetadata().") at (".$data["block"]->x.", ".$data["block"]->y.", ".$data["block"]->z.")", true, true, 2);
|
||||
$this->setBlock($data["block"]->x, $data["block"]->y, $data["block"]->z, 0, 0, true, true);
|
||||
break;
|
||||
}
|
||||
|
||||
public function saveAll(){
|
||||
foreach($this->levels as $level){
|
||||
$level->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
$this->saveAll();
|
||||
foreach($this->levels as $level){
|
||||
$this->unloadLevel($level, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,100 +229,18 @@ class LevelAPI{
|
||||
return $this->server->spawn;
|
||||
}
|
||||
|
||||
public function getChunk($X, $Z){
|
||||
return $this->map->map[$X][$Z];
|
||||
public function loadMap(){
|
||||
if($this->mapName !== false and trim($this->mapName) !== ""){
|
||||
if(!file_exists($this->mapDir."level.pmf")){
|
||||
$level = new LevelImport($this->mapDir);
|
||||
$level->import();
|
||||
}
|
||||
$this->level = new PMFLevel($this->mapDir."level.pmf");
|
||||
console("[INFO] Preparing level \"".$this->level->getData("name")."\"");
|
||||
$this->time = (int) $this->level->getData("time");
|
||||
$this->seed = (int) $this->level->getData("seed");
|
||||
$this->spawn = $this->level->getSpawn();
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockFace($block, $face){
|
||||
$data = array("x" => $block[2][0], "y" => $block[2][1], "z" => $block[2][2]);
|
||||
BlockFace::setPosition($data, $face);
|
||||
return $this->getBlock($data["x"], $data["y"], $data["z"]);
|
||||
}
|
||||
|
||||
public function getBlock($x, $y, $z){
|
||||
$b = $this->map->getBlock($x, $y, $z);
|
||||
$b[2] = array($x, $y, $z);
|
||||
return $b;
|
||||
}
|
||||
|
||||
public function getFloor($x, $z){
|
||||
if(!isset($this->heightMap[$z][$x])){
|
||||
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z);
|
||||
}
|
||||
return $this->heightMap[$z][$x];
|
||||
}
|
||||
|
||||
public function setBlock($x, $y, $z, $block, $meta = 0, $update = true, $tiles = false){
|
||||
if($x < 0 or $y < 0 or $z < 0){
|
||||
return false;
|
||||
}
|
||||
if($this->server->api->dhandle("block.change", array(
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
"block" => $block,
|
||||
"meta" => $meta,
|
||||
)) !== false){
|
||||
$this->map->setBlock($x, $y, $z, $block, $meta);
|
||||
$this->heightMap[$z][$x] = $this->map->getFloor($x, $z);
|
||||
if($update === true){
|
||||
$this->server->api->block->updateBlock($x, $y, $z, BLOCK_UPDATE_NORMAL);
|
||||
$this->server->api->block->updateBlocksAround($x, $y, $z, BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
if($tiles === true){
|
||||
if(($t = $this->server->api->tileentity->get($x, $y, $z)) !== false){
|
||||
$t[0]->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getOrderedChunks($X, $Z, $columnsPerPacket = 2){
|
||||
$columnsPerPacket = max(1, (int) $columnsPerPacket);
|
||||
$ordered = array();
|
||||
$i = 0;
|
||||
$cnt = 0;
|
||||
$ordered[$i] = "";
|
||||
for($z = 0; $z < 16; ++$z){
|
||||
for($x = 0; $x < 16; ++$x){
|
||||
if($cnt >= $columnsPerPacket){
|
||||
++$i;
|
||||
$ordered[$i] = str_repeat("\x00", $i * $columnsPerPacket);
|
||||
$cnt = 0;
|
||||
}
|
||||
$ordered[$i] .= "\xff";
|
||||
$block = $this->map->getChunkColumn($X, $Z, $x, $z, 0);
|
||||
$meta = $this->map->getChunkColumn($X, $Z, $x, $z, 1);
|
||||
for($k = 0; $k < 8; ++$k){
|
||||
$ordered[$i] .= substr($block, $k << 4, 16);
|
||||
$ordered[$i] .= substr($meta, $k << 3, 8);
|
||||
}
|
||||
++$cnt;
|
||||
}
|
||||
}
|
||||
return $ordered;
|
||||
}
|
||||
|
||||
public function getMiniChunk($X, $Z, $Y, $MTU){
|
||||
$ordered = array();
|
||||
$i = 0;
|
||||
$ordered[$i] = "";
|
||||
$cnt = 0;
|
||||
for($z = 0; $z < 16; ++$z){
|
||||
for($x = 0; $x < 16; ++$x){
|
||||
if((strlen($ordered[$i]) + 16 + 8 + 1) > $MTU){
|
||||
++$i;
|
||||
$ordered[$i] = str_repeat("\x00", $cnt);
|
||||
}
|
||||
$ordered[$i] .= chr(1 << $Y);
|
||||
$block = $this->map->getChunkColumn($X, $Z, $x, $z, 0);
|
||||
$meta = $this->map->getChunkColumn($X, $Z, $x, $z, 1);
|
||||
$ordered[$i] .= substr($block, $Y << 4, 16);
|
||||
$ordered[$i] .= substr($meta, $Y << 3, 8);
|
||||
++$cnt;
|
||||
}
|
||||
}
|
||||
return $ordered;
|
||||
}
|
||||
}
|
@ -25,25 +25,13 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class TickLoop extends Thread{
|
||||
public $tick, $stop, $lastTic;
|
||||
class MobAPI{
|
||||
private $server;
|
||||
public function __construct(PocketMinecraftServer $server){
|
||||
$this->tick = false;
|
||||
$this->lastTick = 0;
|
||||
$this->server = $server;
|
||||
function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
public function run(){
|
||||
while($this->stop !== true){
|
||||
usleep(1);
|
||||
$time = microtime(true);
|
||||
if($this->lastTick <= ($time - 0.05)){
|
||||
$this->lastTick = $time;
|
||||
$this->tick = true;
|
||||
$this->wait();
|
||||
$this->tick = false;
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
|
||||
public function init(){
|
||||
|
||||
}
|
||||
}
|
@ -27,25 +27,35 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class PlayerAPI{
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->server->addHandler("server.regeneration", array($this, "handle"));
|
||||
$this->server->schedule(20 * 15, array($this, "handle"), 1, true, "server.regeneration");
|
||||
$this->server->addHandler("player.death", array($this, "handle"), 1);
|
||||
$this->server->api->console->register("list", "Shows connected player list", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("kill", "Kills a player", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("harm", "Harms a player", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("tppos", "Teleports a player to a position", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("tp", "Teleports a player to another player", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("list", "", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("kill", "<player>", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("gamemode", "<mode> [player]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("tp", "[target player] <destination player|w:world> OR /tp [target player] <x> <y> <z>", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("spawnpoint", "[player] [x] [y] [z]", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("spawn", "", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("ping", "", array($this, "commandHandler"));
|
||||
$this->server->api->console->alias("lag", "ping");
|
||||
$this->server->api->console->alias("suicide", "kill");
|
||||
$this->server->api->console->alias("tppos", "tp");
|
||||
$this->server->api->ban->cmdWhitelist("list");
|
||||
$this->server->api->ban->cmdWhitelist("ping");
|
||||
$this->server->api->ban->cmdWhitelist("spawn");
|
||||
$this->server->preparedSQL->selectPlayersToHeal = $this->server->database->prepare("SELECT EID FROM entities WHERE class = ".ENTITY_PLAYER." AND health < 20;");
|
||||
}
|
||||
|
||||
public function handle($data, $event){
|
||||
switch($event){
|
||||
case "server.regeneration":
|
||||
$result = $this->server->query("SELECT EID FROM entities WHERE class = ".ENTITY_PLAYER." AND health < 20;");
|
||||
if($result !== true and $result !== false){
|
||||
if($this->server->difficulty === 0){
|
||||
$result = $this->server->preparedSQL->selectPlayersToHeal->execute();
|
||||
if($result !== false){
|
||||
while(($player = $result->fetchArray()) !== false){
|
||||
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
|
||||
if($player->getHealth() <= 0){
|
||||
@ -54,55 +64,56 @@ class PlayerAPI{
|
||||
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "player.death":
|
||||
$message = $data["name"];
|
||||
if(is_numeric($data["cause"]) and isset($this->entities[$data["cause"]])){
|
||||
$e = $this->api->entity->get($data["cause"]);
|
||||
if(is_numeric($data["cause"])){
|
||||
$e = $this->server->api->entity->get($data["cause"]);
|
||||
if($e instanceof Entity){
|
||||
switch($e->class){
|
||||
case ENTITY_PLAYER:
|
||||
$message .= " was killed by ".$e->name;
|
||||
$message = " was killed by ".$e->name;
|
||||
break;
|
||||
default:
|
||||
$message .= " was killed";
|
||||
$message = " was killed";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
switch($data["cause"]){
|
||||
case "cactus":
|
||||
$message .= " was pricked to death";
|
||||
$message = " was pricked to death";
|
||||
break;
|
||||
case "lava":
|
||||
$message .= " tried to swim in lava";
|
||||
$message = " tried to swim in lava";
|
||||
break;
|
||||
case "fire":
|
||||
$message .= " went up in flames";
|
||||
$message = " went up in flames";
|
||||
break;
|
||||
case "burning":
|
||||
$message .= " burned to death";
|
||||
$message = " burned to death";
|
||||
break;
|
||||
case "suffocation":
|
||||
$message .= " suffocated in a wall";
|
||||
$message = " suffocated in a wall";
|
||||
break;
|
||||
case "water":
|
||||
$message .= " drowned";
|
||||
$message = " drowned";
|
||||
break;
|
||||
case "void":
|
||||
$message .= " fell out of the world";
|
||||
$message = " fell out of the world";
|
||||
break;
|
||||
case "fall":
|
||||
$message .= " hit the ground too hard";
|
||||
break;
|
||||
case "flying":
|
||||
$message .= " tried to fly up to the sky";
|
||||
$message = " hit the ground too hard";
|
||||
break;
|
||||
default:
|
||||
$message .= " died";
|
||||
$message = " died";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->server->chat(false, $message);
|
||||
$this->server->api->chat->broadcast($data["player"]->username . $message);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -110,117 +121,227 @@ class PlayerAPI{
|
||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||
$output = "";
|
||||
switch($cmd){
|
||||
case "tp":
|
||||
$name = array_shift($params);
|
||||
$target = array_shift($params);
|
||||
if($name == null or $target == null){
|
||||
$output .= "Usage: /tp <player> <target>\n";
|
||||
case "spawnpoint":
|
||||
if(!($issuer instanceof Player)){
|
||||
$output .= "Please run this command in-game.\n";
|
||||
break;
|
||||
}
|
||||
if($this->teleport($name, $target)){
|
||||
|
||||
if(count($params) === 1 or count($params) === 4){
|
||||
$target = $this->server->api->player->get(array_shift($params));
|
||||
}else{
|
||||
$target = $issuer;
|
||||
}
|
||||
|
||||
if(!($target instanceof Player)){
|
||||
$output .= "That player cannot be found.\n";
|
||||
break;
|
||||
}
|
||||
|
||||
if(count($params) === 3){
|
||||
$spawn = new Position(floatval(array_shift($params)), floatval(array_shift($params)), floatval(array_shift($params)), $issuer->level);
|
||||
}else{
|
||||
$spawn = new Position($issuer->entity->x, $issuer->entity->y, $issuer->entity->z, $issuer->entity->level);
|
||||
}
|
||||
|
||||
$target->setSpawn($spawn);
|
||||
|
||||
$output .= "Spawnpoint set correctly!\n";
|
||||
break;
|
||||
case "spawn":
|
||||
if(!($issuer instanceof Player)){
|
||||
$output .= "Please run this command in-game.\n";
|
||||
break;
|
||||
}
|
||||
$spawn = $issuer->getSpawn();
|
||||
$issuer->teleport($spawn);
|
||||
break;
|
||||
case "ping":
|
||||
if(!($issuer instanceof Player)){
|
||||
$output .= "Please run this command in-game.\n";
|
||||
break;
|
||||
}
|
||||
$output .= "ping ".round($issuer->getLag(), 2)."ms, packet loss ".round($issuer->getPacketLoss() * 100, 2)."%, ".round($issuer->getBandwidth() / 1024, 2)." KB/s\n";
|
||||
break;
|
||||
case "gamemode":
|
||||
$player = false;
|
||||
$gms = array(
|
||||
"0" => SURVIVAL,
|
||||
"survival" => SURVIVAL,
|
||||
"s" => SURVIVAL,
|
||||
"1" => CREATIVE,
|
||||
"creative" => CREATIVE,
|
||||
"c" => CREATIVE,
|
||||
"2" => ADVENTURE,
|
||||
"adventure" => ADVENTURE,
|
||||
"a" => ADVENTURE,
|
||||
"3" => VIEW,
|
||||
"view" => VIEW,
|
||||
"viewer" => VIEW,
|
||||
"spectator" => VIEW,
|
||||
"v" => VIEW,
|
||||
);
|
||||
if($issuer instanceof Player){
|
||||
$player = $issuer;
|
||||
}
|
||||
if(isset($params[1])){
|
||||
$player = $this->server->api->player->get($params[1]);
|
||||
}
|
||||
if(!($player instanceof Player) or !isset($gms[strtolower($params[0])])){
|
||||
$output .= "Usage: /$cmd <mode> [player]\n";
|
||||
break;
|
||||
}
|
||||
if($player->setGamemode($gms[strtolower($params[0])])){
|
||||
$output .= "Gamemode of ".$player->username." changed to ".$player->getGamemode()."\n";
|
||||
}
|
||||
break;
|
||||
case "tp":
|
||||
if(count($params) <= 2 or substr($params[0], 0, 2) === "w:" or substr($params[1], 0, 2) === "w:"){
|
||||
if((!isset($params[1]) or substr($params[0], 0, 2) === "w:") and isset($params[0]) and ($issuer instanceof Player)){
|
||||
$name = $issuer->username;
|
||||
$target = implode(" ", $params);
|
||||
}elseif(isset($params[1]) and isset($params[0])){
|
||||
$name = array_shift($params);
|
||||
$target = implode(" ", $params);
|
||||
}else{
|
||||
$output .= "Usage: /$cmd [target player] <destination player>\n";
|
||||
break;
|
||||
}
|
||||
if($this->teleport($name, $target) !== false){
|
||||
$output .= "\"$name\" teleported to \"$target\"\n";
|
||||
}else{
|
||||
$output .= "Couldn't teleport\n";
|
||||
$output .= "Couldn't teleport.\n";
|
||||
}
|
||||
break;
|
||||
case "tppos":
|
||||
$z = array_pop($params);
|
||||
$y = array_pop($params);
|
||||
$x = array_pop($params);
|
||||
$name = implode(" ", $params);
|
||||
if($name == null or $x === null or $y === null or $z === null){
|
||||
$output .= "Usage: /tp <player> <x> <y> <z>\n";
|
||||
}else{
|
||||
if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
|
||||
$name = $issuer->username;
|
||||
$x = $params[0];
|
||||
$y = $params[1];
|
||||
$z = $params[2];
|
||||
}elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
|
||||
$name = $params[0];
|
||||
$x = $params[1];
|
||||
$y = $params[2];
|
||||
$z = $params[3];
|
||||
}else{
|
||||
$output .= "Usage: /$cmd [player] <x> <y> <z>\n";
|
||||
break;
|
||||
}
|
||||
if($this->tppos($name, $x, $y, $z)){
|
||||
$output .= "\"$name\" teleported to ($x, $y, $z)\n";
|
||||
}else{
|
||||
$output .= "Couldn't teleport\n";
|
||||
$output .= "Couldn't teleport.\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "kill":
|
||||
$player = $this->get(implode(" ", $params));
|
||||
if($player !== false){
|
||||
$this->server->api->entity->harm($player->eid, 20, "console", true);
|
||||
case "suicide":
|
||||
if(!isset($params[0]) and ($issuer instanceof Player)){
|
||||
$player = $issuer;
|
||||
}else{
|
||||
$output .= "Usage: /kill <player>\n";
|
||||
$player = $this->get($params[0]);
|
||||
}
|
||||
break;
|
||||
case "harm":
|
||||
$dmg = (int) array_shift($params);
|
||||
$player = $this->get(implode(" ", $params));
|
||||
if($player !== false){
|
||||
$this->server->api->entity->harm($player->eid, $dmg, "console", true);
|
||||
if($player instanceof Player){
|
||||
$player->entity->harm(1000, "console", true);
|
||||
$player->sendChat("Ouch. That looks like it hurt.\n");
|
||||
}else{
|
||||
$output .= "Usage: /harm <damage> <player>\n";
|
||||
$output .= "Usage: /$cmd [player]\n";
|
||||
}
|
||||
break;
|
||||
case "list":
|
||||
$output .= "Player list:\n";
|
||||
foreach($this->server->clients as $c){
|
||||
$output .= $c->username." (".$c->ip.":".$c->port."), ClientID ".$c->clientID.", (".round($c->entity->x, 2).", ".round($c->entity->y, 2).", ".round($c->entity->z, 2).")\n";
|
||||
$output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n";
|
||||
if(count($this->server->clients) == 0){
|
||||
break;
|
||||
}
|
||||
foreach($this->server->clients as $c){
|
||||
$output .= $c->username.", ";
|
||||
}
|
||||
$output = substr($output, 0, -2)."\n";
|
||||
break;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function teleport($name, $target){
|
||||
$target = $this->get($target);
|
||||
if(($target instanceof Player) and ($target->entity instanceof Entity)){
|
||||
return $this->tppos($name, $target->entity->x, $target->entity->y, $target->entity->z);
|
||||
public function teleport(&$name, &$target){
|
||||
if(substr($target, 0, 2) === "w:"){
|
||||
$lv = $this->server->api->level->get(substr($target, 2));
|
||||
if($lv instanceof Level){
|
||||
$origin = $this->get($name);
|
||||
if($origin instanceof Player){
|
||||
$name = $origin->username;
|
||||
return $origin->teleport($lv->getSpawn());
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$player = $this->get($target);
|
||||
if(($player instanceof Player) and ($player->entity instanceof Entity)){
|
||||
$target = $player->username;
|
||||
$origin = $this->get($name);
|
||||
if($origin instanceof Player){
|
||||
$name = $origin->username;
|
||||
return $origin->teleport($player->entity);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function tppos($name, $x, $y, $z){
|
||||
public function tppos(&$name, &$x, &$y, &$z){
|
||||
$player = $this->get($name);
|
||||
if(($player instanceof Player) and ($player->entity instanceof Entity)){
|
||||
$player->entity->setPosition($x, $y, $z, 0, 0);
|
||||
$player->fallY = false;
|
||||
$player->fallStart = false;
|
||||
$player->dataPacket(MC_MOVE_PLAYER, array(
|
||||
"eid" => 0,
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
"yaw" => 0,
|
||||
"pitch" => 0,
|
||||
));
|
||||
$player->fallY = false;
|
||||
$player->fallStart = false;
|
||||
$name = $player->username;
|
||||
$x = $x{0} === "~" ? $player->entity->x + floatval(substr($x, 1)):floatval($x);
|
||||
$y = $y{0} === "~" ? $player->entity->y + floatval(substr($y, 1)):floatval($y);
|
||||
$z = $z{0} === "~" ? $player->entity->z + floatval(substr($z, 1)):floatval($z);
|
||||
$player->teleport(new Vector3($x, $y, $z));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get($name){
|
||||
$CID = $this->server->query("SELECT ip,port FROM players WHERE name = '".str_replace("'", "", $name)."';", true);
|
||||
$CID = $this->server->clientID($CID["ip"], $CID["port"]);
|
||||
public function get($name, $alike = true){
|
||||
$name = trim(strtolower($name));
|
||||
if($name === ""){
|
||||
return false;
|
||||
}
|
||||
$CID = $this->server->query("SELECT ip,port FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";", true);
|
||||
$CID = PocketMinecraftServer::clientID($CID["ip"], $CID["port"]);
|
||||
if(isset($this->server->clients[$CID])){
|
||||
return $this->server->clients[$CID];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getAll(){
|
||||
public function getAll($level = null){
|
||||
if($level instanceof Level){
|
||||
$clients = array();
|
||||
$l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."' AND class = '".ENTITY_PLAYER."';");
|
||||
if($l !== false and $l !== true){
|
||||
while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$e = $this->getByEID($e["EID"]);
|
||||
if($e instanceof Player){
|
||||
$clients[$e->CID] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $clients;
|
||||
}
|
||||
return $this->server->clients;
|
||||
}
|
||||
|
||||
public function broadcastPacket(array $players, $id, $data = array()){
|
||||
$data = new CustomPacketHandler($id, "", $data, true);
|
||||
$packet = array("raw" => chr($id).$data->raw);
|
||||
foreach($players as $p){
|
||||
$p->dataPacket(false, $packet);
|
||||
}
|
||||
}
|
||||
|
||||
public function getByEID($eid){
|
||||
$eid = (int) $eid;
|
||||
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
|
||||
$CID = $this->server->clientID($CID["ip"], $CID["port"]);
|
||||
if(isset($this->server->clients[$CID])){
|
||||
return $this->server->clients[$CID];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getByClientID($clientID){
|
||||
$clientID = (int) $clientID;
|
||||
$CID = $this->server->query("SELECT ip,port FROM players WHERE clientID = '".$clientID."';", true);
|
||||
$CID = $this->server->clientID($CID["ip"], $CID["port"]);
|
||||
$CID = PocketMinecraftServer::clientID($CID["ip"], $CID["port"]);
|
||||
if(isset($this->server->clients[$CID])){
|
||||
return $this->server->clients[$CID];
|
||||
}
|
||||
@ -240,9 +361,54 @@ class PlayerAPI{
|
||||
public function add($CID){
|
||||
if(isset($this->server->clients[$CID])){
|
||||
$player = $this->server->clients[$CID];
|
||||
console("[INFO] Player \"\x1b[33m".$player->username."\x1b[0m\" connected from \x1b[36m".$player->ip.":".$player->port."\x1b[0m");
|
||||
$player->data = $this->getOffline($player->username);
|
||||
$this->server->query("INSERT OR REPLACE INTO players (clientID, ip, port, name) VALUES (".$player->clientID.", '".$player->ip."', ".$player->port.", '".$player->username."');");
|
||||
$player->gamemode = $player->data->get("gamemode");
|
||||
if(($player->level = $this->server->api->level->get($player->data->get("position")["level"])) === false){
|
||||
$player->level = $this->server->api->level->getDefault();
|
||||
$player->data->set("position", array(
|
||||
"level" => $player->level->getName(),
|
||||
"x" => $player->level->getSpawn()->x,
|
||||
"y" => $player->level->getSpawn()->y,
|
||||
"z" => $player->level->getSpawn()->z,
|
||||
));
|
||||
}
|
||||
$this->server->query("INSERT OR REPLACE INTO players (CID, ip, port, name) VALUES (".$player->CID.", '".$player->ip."', ".$player->port.", '".strtolower($player->username)."');");
|
||||
}
|
||||
}
|
||||
|
||||
public function spawnAllPlayers(Player $player){
|
||||
foreach($this->getAll() as $p){
|
||||
if($p !== $player and ($p->entity instanceof Entity)){
|
||||
$p->entity->spawn($player);
|
||||
if($p->level !== $player->level){
|
||||
$player->dataPacket(MC_MOVE_ENTITY_POSROT, array(
|
||||
"eid" => $p->entity->eid,
|
||||
"x" => -256,
|
||||
"y" => 128,
|
||||
"z" => -256,
|
||||
"yaw" => 0,
|
||||
"pitch" => 0,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function spawnToAllPlayers(Player $player){
|
||||
foreach($this->getAll() as $p){
|
||||
if($p !== $player and ($p->entity instanceof Entity)){
|
||||
$player->entity->spawn($p);
|
||||
if($p->level !== $player->level){
|
||||
$p->dataPacket(MC_MOVE_ENTITY_POSROT, array(
|
||||
"eid" => $player->entity->eid,
|
||||
"x" => -256,
|
||||
"y" => 128,
|
||||
"z" => -256,
|
||||
"yaw" => 0,
|
||||
"pitch" => 0,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +418,9 @@ class PlayerAPI{
|
||||
$this->server->clients[$CID] = null;
|
||||
unset($this->server->clients[$CID]);
|
||||
$player->close();
|
||||
$this->saveOffline($player->username, $player->data);
|
||||
if($player->username != "" and ($player->data instanceof Config)){
|
||||
$this->saveOffline($player->data);
|
||||
}
|
||||
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
|
||||
if($player->entity instanceof Entity){
|
||||
$player->entity->player = null;
|
||||
@ -265,33 +433,46 @@ class PlayerAPI{
|
||||
}
|
||||
|
||||
public function getOffline($name){
|
||||
if(!file_exists(DATA_PATH."players/".$name.".dat")){
|
||||
console("[NOTICE] Player data not found for \"".$name."\", creating new profile");
|
||||
$data = array(
|
||||
"spawn" => array(
|
||||
"x" => $this->server->spawn["x"],
|
||||
"y" => $this->server->spawn["y"],
|
||||
"z" => $this->server->spawn["z"],
|
||||
$iname = strtolower($name);
|
||||
$default = array(
|
||||
"caseusername" => $name,
|
||||
"position" => array(
|
||||
"level" => $this->server->spawn->level->getName(),
|
||||
"x" => $this->server->spawn->x,
|
||||
"y" => $this->server->spawn->y,
|
||||
"z" => $this->server->spawn->z,
|
||||
),
|
||||
"inventory" => array_fill(0, 36, array(AIR, 0, 0)),
|
||||
"armor" => array_fill(0, 4, array(AIR, 0, 0)),
|
||||
"spawn" => array(
|
||||
"level" => $this->server->spawn->level->getName(),
|
||||
"x" => $this->server->spawn->x,
|
||||
"y" => $this->server->spawn->y,
|
||||
"z" => $this->server->spawn->z,
|
||||
),
|
||||
"inventory" => array_fill(0, PLAYER_SURVIVAL_SLOTS, array(AIR, 0, 0)),
|
||||
"armor" => array_fill(0, 4, array(AIR, 0)),
|
||||
"gamemode" => $this->server->gamemode,
|
||||
"health" => 20,
|
||||
"lastIP" => "",
|
||||
"lastID" => 0,
|
||||
);
|
||||
$this->saveOffline($name, $data);
|
||||
|
||||
if(!file_exists(DATA_PATH."players/".$iname.".yml")){
|
||||
console("[NOTICE] Player data not found for \"".$iname."\", creating new profile");
|
||||
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
|
||||
$data->save();
|
||||
}else{
|
||||
$data = unserialize(file_get_contents(DATA_PATH."players/".$name.".dat"));
|
||||
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
|
||||
}
|
||||
if($this->server->gamemode === 1){
|
||||
$data["health"] = 20;
|
||||
|
||||
if(($this->server->gamemode & 0x01) === 0x01){
|
||||
$data->set("health", 20);
|
||||
}
|
||||
$this->server->handle("api.player.offline.get", $data);
|
||||
$this->server->handle("player.offline.get", $data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function saveOffline($name, $data){
|
||||
$this->server->handle("api.player.offline.save", $data);
|
||||
file_put_contents(DATA_PATH."players/".str_replace("/", "", $name).".dat", serialize($data));
|
||||
public function saveOffline(Config $data){
|
||||
$this->server->handle("player.offline.save", $data);
|
||||
$data->save();
|
||||
}
|
||||
}
|
@ -28,8 +28,8 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class PluginAPI extends stdClass{
|
||||
private $server;
|
||||
private $plugins = array();
|
||||
public function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
public function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function getList(){
|
||||
@ -41,6 +41,7 @@ class PluginAPI extends stdClass{
|
||||
}
|
||||
|
||||
public function getInfo($className){
|
||||
$className = strtolower($className);
|
||||
if(!isset($this->plugins[$className])){
|
||||
return false;
|
||||
}
|
||||
@ -49,11 +50,15 @@ class PluginAPI extends stdClass{
|
||||
}
|
||||
|
||||
public function load($file){
|
||||
if(strtolower(substr($file, -3)) === "pmf"){
|
||||
$pmf = new PMFPlugin($file);
|
||||
$info = $pmf->getPluginInfo();
|
||||
}else{
|
||||
$content = file_get_contents($file);
|
||||
$info = strstr($content, "*/", true);
|
||||
$content = substr(strstr($content, "*/"),2);
|
||||
$content = str_repeat(PHP_EOL, substr_count($info, "\n")).substr(strstr($content, "*/"),2);
|
||||
if(preg_match_all('#([a-zA-Z0-9\-_]*)=([^\r\n]*)#u', $info, $matches) == 0){ //false or 0 matches
|
||||
console("[ERROR] [PluginAPI] Failed parsing of ".basename($file));
|
||||
console("[ERROR] Failed parsing of ".basename($file));
|
||||
return false;
|
||||
}
|
||||
$info = array();
|
||||
@ -73,26 +78,33 @@ class PluginAPI extends stdClass{
|
||||
}
|
||||
$info[$i] = $v;
|
||||
}
|
||||
$info["code"] = $content;
|
||||
$info["class"] = trim(strtolower($info["class"]));
|
||||
}
|
||||
if(!isset($info["name"]) or !isset($info["version"]) or !isset($info["class"]) or !isset($info["author"])){
|
||||
console("[ERROR] [PluginAPI] Failed parsing of ".basename($file));
|
||||
console("[ERROR] Failed parsing of ".basename($file));
|
||||
return false;
|
||||
}
|
||||
console("[INFO] [PluginAPI] Loading plugin \"\x1b[32m".$info["name"]."\x1b[0m\" \x1b[35m".$info["version"]."\x1b[0m by \x1b[36m".$info["author"]."\x1b[0m");
|
||||
if(class_exists($info["class"])){
|
||||
console("[ERROR] [PluginAPI] Failed loading plugin: class exists");
|
||||
console("[INFO] Loading plugin \"\x1b[32m".$info["name"]."\x1b[0m\" \x1b[35m".$info["version"]." \x1b[0mby \x1b[36m".$info["author"]."\x1b[0m");
|
||||
if($info["class"] !== "none" and class_exists($info["class"])){
|
||||
console("[ERROR] Failed loading plugin: class already exists");
|
||||
return false;
|
||||
}
|
||||
if(eval($content) === false or !class_exists($info["class"])){
|
||||
console("[ERROR] [PluginAPI] Failed loading plugin: evaluation error");
|
||||
if(eval($info["code"]) === false or ($info["class"] !== "none" and !class_exists($info["class"]))){
|
||||
console("[ERROR] Failed loading plugin: evaluation error");
|
||||
return false;
|
||||
}
|
||||
$className = trim($info["class"]);
|
||||
if(!isset($info["apiversion"]) or intval($info["apiversion"]) < CURRENT_API_VERSION){
|
||||
console("[ERROR] [PluginAPI] Plugin \"".$info["name"]."\" uses an outdated API! It can crash or corrupt the server!");
|
||||
|
||||
$className = $info["class"];
|
||||
$apiversion = array_map("intval", explode(",", (string) $info["apiversion"]));
|
||||
if(!in_array((string) CURRENT_API_VERSION, $apiversion)){
|
||||
console("[WARNING] Plugin \"".$info["name"]."\" may not be compatible with the API (".$info["apiversion"]." != ".CURRENT_API_VERSION.")! It can crash or corrupt the server!");
|
||||
}
|
||||
if(isset($info["api"]) and $info["api"] !== true){
|
||||
console("[INFO] [PluginAPI] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" got raw access to Server methods");
|
||||
}
|
||||
$object = new $className($this->server->api, ((isset($info["api"]) and $info["api"] !== true) ? $this->server:false));
|
||||
|
||||
if($info["class"] !== "none"){
|
||||
$object = new $className($this->server->api, false);
|
||||
if(!($object instanceof Plugin)){
|
||||
console("[ERROR] [PluginAPI] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" doesn't use the Plugin Interface");
|
||||
console("[ERROR] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" doesn't use the Plugin Interface");
|
||||
if(method_exists($object, "__destruct")){
|
||||
$object->__destruct();
|
||||
}
|
||||
@ -101,6 +113,9 @@ class PluginAPI extends stdClass{
|
||||
}else{
|
||||
$this->plugins[$className] = array($object, $info);
|
||||
}
|
||||
}else{
|
||||
$this->plugins[md5($info["name"])] = array(new DummyPlugin($this->server->api, false), $info);
|
||||
}
|
||||
}
|
||||
|
||||
public function get(Plugin $plugin){
|
||||
@ -119,6 +134,7 @@ class PluginAPI extends stdClass{
|
||||
}
|
||||
$path = DATA_PATH."plugins/".$p[1]["name"]."/";
|
||||
$this->plugins[$p[1]["class"]][1]["path"] = $path;
|
||||
@mkdir($path);
|
||||
return $path;
|
||||
}
|
||||
|
||||
@ -127,9 +143,7 @@ class PluginAPI extends stdClass{
|
||||
if($p === false){
|
||||
return false;
|
||||
}
|
||||
$path = DATA_PATH."plugins/".$p[1]["name"]."/";
|
||||
@mkdir($path);
|
||||
$this->plugins[$p[1]["class"]][1]["path"] = $path;
|
||||
$path = $this->configPath($plugin);
|
||||
$cnf = new Config($path."config.yml", CONFIG_YAML, $default);
|
||||
$cnf->save();
|
||||
return $path;
|
||||
@ -162,11 +176,11 @@ class PluginAPI extends stdClass{
|
||||
}
|
||||
|
||||
public function loadAll(){
|
||||
console("[INFO] Loading Plugins...");
|
||||
$dir = dir(DATA_PATH."plugins/");
|
||||
while(false !== ($file = $dir->read())){
|
||||
if($file{0} !== "."){
|
||||
if(strtolower(substr($file, -3)) === "php"){
|
||||
$ext = strtolower(substr($file, -3));
|
||||
if($ext === "php" or $ext === "pmf"){
|
||||
$this->load(DATA_PATH."plugins/" . $file);
|
||||
}
|
||||
}
|
||||
@ -174,6 +188,7 @@ class PluginAPI extends stdClass{
|
||||
}
|
||||
|
||||
public function initAll(){
|
||||
console("[INFO] Starting plugins...");
|
||||
foreach($this->plugins as $p){
|
||||
$p[0]->init(); //ARGHHH!!! Plugin loading randomly fails!!
|
||||
}
|
||||
@ -186,3 +201,14 @@ interface Plugin{
|
||||
public function init();
|
||||
public function __destruct();
|
||||
}
|
||||
|
||||
class DummyPlugin implements Plugin{
|
||||
public function __construct(ServerAPI $api, $server = false){
|
||||
}
|
||||
|
||||
public function init(){
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
}
|
||||
}
|
@ -26,115 +26,97 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class ServerAPI{
|
||||
var $restart = false;
|
||||
public $restart = false;
|
||||
private static $serverRequest = false;
|
||||
private $asyncCalls = array();
|
||||
private $server;
|
||||
private $config;
|
||||
private $apiList = array();
|
||||
private $asyncCnt = 0;
|
||||
private $rcon;
|
||||
private $query;
|
||||
|
||||
public static function request(){
|
||||
return self::$serverRequest;
|
||||
}
|
||||
|
||||
public function start(){
|
||||
return $this->run();
|
||||
}
|
||||
|
||||
public function run(){
|
||||
$this->load();
|
||||
return $this->init();
|
||||
}
|
||||
|
||||
public function load(){
|
||||
@mkdir(DATA_PATH."logs/", 0777, true);
|
||||
@mkdir(DATA_PATH."players/", 0777);
|
||||
@mkdir(DATA_PATH."worlds/", 0777);
|
||||
@mkdir(DATA_PATH."plugins/", 0777);
|
||||
console("[INFO] Starting ServerAPI server handler...");
|
||||
file_put_contents(DATA_PATH."logs/packets.log", "");
|
||||
if(!file_exists(DATA_PATH."logs/test.bin.log") or md5_file(DATA_PATH."logs/test.bin.log") !== TEST_MD5){
|
||||
console("[NOTICE] Executing tests...");
|
||||
console("[INFO] OS: ".PHP_OS.", ".Utils::getOS());
|
||||
console("[INFO] uname -a: ".php_uname("a"));
|
||||
console("[INFO] PHP Version: ".phpversion());
|
||||
console("[INFO] Endianness: ".ENDIANNESS);
|
||||
$test = b"";
|
||||
$test .= Utils::writeLong("5567381823242127440");
|
||||
$test .= Utils::writeLong("2338608908624488819");
|
||||
$test .= Utils::writeLong("2333181766244987936");
|
||||
$test .= Utils::writeLong("2334669371112169504");
|
||||
$test .= Utils::writeShort(Utils::readShort("\xff\xff\xff\xff"));
|
||||
$test .= Utils::writeShort(Utils::readShort("\xef\xff\xff\xff"));
|
||||
$test .= Utils::writeInt(Utils::readInt("\xff\xff\xff\xff"));
|
||||
$test .= Utils::writeInt(1);
|
||||
$test .= Utils::writeInt(-1);
|
||||
$test .= Utils::writeFloat(Utils::readFloat("\xff\xff\xff\xff"));
|
||||
$test .= Utils::writeFloat(-1.584563155838E+29);
|
||||
$test .= Utils::writeFloat(1);
|
||||
$test .= Utils::writeLDouble(Utils::readLDouble("\xff\xff\xff\xff\xff\xff\xff\xff"));
|
||||
$test .= Utils::writeLong("-1152921504606846977");
|
||||
$test .= Utils::writeLong("-1152921504606846976");
|
||||
$str = new Java_String("TESTING\x00\n\r\t\xff");
|
||||
$test .= Utils::writeInt($str->hashCode());
|
||||
$test .= Utils::writeDataArray(array("a", "b", "c", "\xff\xff\xff\xff"));
|
||||
$test .= Utils::hexToStr("012334567890");
|
||||
file_put_contents(DATA_PATH."logs/test.bin.log", $test);
|
||||
$md5 = md5($test);
|
||||
console("[INFO] MD5 of test: ".$md5);
|
||||
if($md5 !== TEST_MD5){
|
||||
console("[ERROR] Test error, please send your console.log + test.bin.log to the Github repo");
|
||||
die();
|
||||
}
|
||||
}
|
||||
@mkdir(DATA_PATH."players/", 0755);
|
||||
@mkdir(DATA_PATH."worlds/", 0755);
|
||||
@mkdir(DATA_PATH."plugins/", 0755);
|
||||
console("[INFO] \x1b[33;1mPocketMine-MP ".MAJOR_VERSION." API #".CURRENT_API_VERSION.", LGPL License", true, true, 0);
|
||||
|
||||
console("[DEBUG] Loading server.properties...", true, true, 2);
|
||||
console("[INFO] Loading properties...");
|
||||
$this->config = new Config(DATA_PATH . "server.properties", CONFIG_PROPERTIES, array(
|
||||
"server-name" => "Minecraft Server",
|
||||
"server-name" => "Minecraft: PE Server",
|
||||
"description" => "Server made using PocketMine-MP",
|
||||
"motd" => "Welcome @username to this server!",
|
||||
"invisible" => false,
|
||||
"server-ip" => "0.0.0.0",
|
||||
"port" => 19132,
|
||||
"memory-limit" => "256M",
|
||||
"motd" => "Welcome @player to this server!",
|
||||
"server-ip" => "",
|
||||
"server-port" => 19132,
|
||||
"server-type" => "normal",
|
||||
"memory-limit" => "128M",
|
||||
"last-update" => false,
|
||||
"white-list" => false,
|
||||
"debug" => 2,
|
||||
"spawn-protection" => 16,
|
||||
"view-distance" => 10,
|
||||
"max-players" => 20,
|
||||
"server-type" => "normal",
|
||||
"time-per-second" => 20,
|
||||
"gamemode" => 1,
|
||||
"allow-flight" => false,
|
||||
"spawn-animals" => true,
|
||||
"spawn-mobs" => true,
|
||||
"gamemode" => SURVIVAL,
|
||||
"hardcore" => false,
|
||||
"pvp" => true,
|
||||
"difficulty" => 1,
|
||||
"generator" => "",
|
||||
"generator-settings" => "",
|
||||
"level-name" => false,
|
||||
"server-id" => false,
|
||||
"upnp-forwarding" => false,
|
||||
"level-name" => "world",
|
||||
"level-seed" => "",
|
||||
"level-type" => "DEFAULT",
|
||||
"enable-query" => true,
|
||||
"enable-rcon" => false,
|
||||
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
|
||||
"send-usage" => true,
|
||||
"auto-save" => true,
|
||||
));
|
||||
|
||||
$this->parseProperties();
|
||||
define("DEBUG", $this->getProperty("debug"));
|
||||
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), false, $this->getProperty("port"), $this->getProperty("server-id"), $this->getProperty("server-ip"));
|
||||
self::$serverRequest = $this->server;
|
||||
$this->setProperty("server-id", $this->server->serverID);
|
||||
define("DEBUG", $this->getProperty("debug", 1));
|
||||
if($this->getProperty("port") !== false){
|
||||
$this->setProperty("server-port", $this->getProperty("port"));
|
||||
$this->config->remove("port");
|
||||
$this->config->remove("invisible");
|
||||
}
|
||||
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed:false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0");
|
||||
$this->server->api = $this;
|
||||
self::$serverRequest = $this->server;
|
||||
|
||||
if($this->getProperty("upnp-forwarding") === true){
|
||||
console("[INFO] [UPnP] Trying to port forward...");
|
||||
UPnP_PortForward($this->getProperty("port"));
|
||||
}
|
||||
if(($ip = Utils::getIP()) !== false){
|
||||
console("[INFO] External IP: ".$ip);
|
||||
UPnP_PortForward($this->getProperty("server-port"));
|
||||
}
|
||||
|
||||
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
|
||||
console("[INFO] Checking for new server version");
|
||||
console("[INFO] Last check: \x1b[36m".date("Y-m-d H:i:s", $this->getProperty("last-update"))."\x1b[0m");
|
||||
$info = json_decode(Utils::curl_get("http://www.pocketmine.org/latest"), true);
|
||||
$info = json_decode(Utils::curl_get("http://www.pocketmine.net/latest"), true);
|
||||
if($this->server->version->isDev()){
|
||||
if($info === false or !isset($info["development"])){
|
||||
console("[ERROR] PocketMine.org API error");
|
||||
console("[ERROR] PocketMine API error");
|
||||
}else{
|
||||
$last = $info["development"]["date"];
|
||||
if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false){
|
||||
if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false and GIT_COMMIT != $info["development"]["commit"]){
|
||||
console("[NOTICE] \x1b[33mA new DEVELOPMENT version of PocketMine-MP has been released");
|
||||
console("[NOTICE] \x1b[33mVersion \"".$info["development"]["version"]."\" [".substr($info["development"]["commit"], 0, 10)."]");
|
||||
console("[NOTICE] \x1b[36mIf you want to update, get the latest version at ".$info["development"]["download"]);
|
||||
console("[NOTICE] \x1b[36mGet it at PocketMine.net or ".$info["development"]["download"]);
|
||||
console("[NOTICE] This message will dissapear after issuing the command \"/update-done\"");
|
||||
sleep(3);
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
console("[INFO] \x1b[36mThis is the latest DEVELOPMENT version");
|
||||
@ -142,7 +124,7 @@ class ServerAPI{
|
||||
}
|
||||
}else{
|
||||
if($info === false or !isset($info["stable"])){
|
||||
console("[ERROR] PocketMine.org API error");
|
||||
console("[ERROR] PocketMine API error");
|
||||
}else{
|
||||
$newest = new VersionString(MAJOR_VERSION);
|
||||
$newestN = $newest->getNumber();
|
||||
@ -151,46 +133,18 @@ class ServerAPI{
|
||||
if($updateN > $newestN){
|
||||
console("[NOTICE] \x1b[33mA new STABLE version of PocketMine-MP has been released");
|
||||
console("[NOTICE] \x1b[36mVersion \"".$info["stable"]["version"]."\" #".$updateN);
|
||||
console("[NOTICE] Download it at ".$info["stable"]["download"]);
|
||||
console("[NOTICE] Get it at PocketMine.net or ".$info["stable"]["download"]);
|
||||
console("[NOTICE] This message will dissapear as soon as you update");
|
||||
sleep(5);
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
console("[INFO] \x1b[36mThis is the latest STABLE version");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if(file_exists(DATA_PATH."worlds/level.dat")){
|
||||
console("[NOTICE] Detected unimported map data. Importing...");
|
||||
$this->importMap(DATA_PATH."worlds/", true);
|
||||
}
|
||||
$this->server->mapName = $this->getProperty("level-name");
|
||||
$this->server->mapDir = DATA_PATH."worlds/".$this->server->mapName."/";
|
||||
if($this->server->mapName === false or trim($this->server->mapName) === "" or (!file_exists($this->server->mapDir."chunks.dat") and !file_exists($this->server->mapDir."chunks.dat.gz"))){
|
||||
if($this->server->mapName === false or trim($this->server->mapName) === ""){
|
||||
$this->server->mapName = "world";
|
||||
}
|
||||
$this->server->mapDir = DATA_PATH."worlds/".$this->server->mapName."/";
|
||||
$generator = "SuperflatGenerator";
|
||||
if($this->getProperty("generator") !== false and class_exists($this->getProperty("generator"))){
|
||||
$generator = $this->getProperty("generator");
|
||||
}
|
||||
$this->gen = new WorldGenerator($generator, $this->server->seed);
|
||||
if($this->getProperty("generator-settings") !== false and trim($this->getProperty("generator-settings")) != ""){
|
||||
$this->gen->set("preset", $this->getProperty("generator-settings"));
|
||||
}
|
||||
$this->gen->init();
|
||||
$this->gen->generate();
|
||||
$this->gen->save($this->server->mapDir, $this->server->mapName);
|
||||
$this->setProperty("level-name", $this->server->mapName);
|
||||
$this->setProperty("gamemode", 1);
|
||||
}
|
||||
$this->loadProperties();
|
||||
$this->server->loadMap();
|
||||
|
||||
console("[INFO] Loading default APIs");
|
||||
|
||||
$this->loadAPI("console", "ConsoleAPI");
|
||||
$this->loadAPI("level", "LevelAPI");
|
||||
@ -198,9 +152,10 @@ class ServerAPI{
|
||||
$this->loadAPI("chat", "ChatAPI");
|
||||
$this->loadAPI("ban", "BanAPI");
|
||||
$this->loadAPI("entity", "EntityAPI");
|
||||
$this->loadAPI("tileentity", "TileEntityAPI");
|
||||
$this->loadAPI("tile", "TileAPI");
|
||||
$this->loadAPI("player", "PlayerAPI");
|
||||
$this->loadAPI("time", "TimeAPI");
|
||||
$this->loadAPI("mob", "MobAPI");
|
||||
|
||||
foreach($this->apiList as $ob){
|
||||
if(is_callable(array($ob, "init"))){
|
||||
@ -209,51 +164,77 @@ class ServerAPI{
|
||||
}
|
||||
$this->loadAPI("plugin", "PluginAPI"); //fix :(
|
||||
$this->plugin->init();
|
||||
}
|
||||
|
||||
public function async(callable $callable, $params = array(), $remove = false){
|
||||
$cnt = $this->asyncCnt++;
|
||||
$this->asyncCalls[$cnt] = new Async($callable, $params);
|
||||
return $remove === true ? $this->getAsync($cnt):$cnt;
|
||||
}
|
||||
|
||||
$this->server->loadEntities();
|
||||
public function getAsync($id){
|
||||
if(!isset($this->asyncCalls[$id])){
|
||||
return false;
|
||||
}
|
||||
$ob = $this->asyncCalls[$id];
|
||||
unset($this->asyncCalls[$id]);
|
||||
return $ob;
|
||||
}
|
||||
public function autoSave(){
|
||||
console("[DEBUG] Saving....", true, true, 2);
|
||||
$this->server->api->level->saveAll();
|
||||
}
|
||||
|
||||
public function sendUsage(){
|
||||
console("[INTERNAL] Sending usage data...", true, true, 3);
|
||||
Utils::curl_post("http://www.pocketmine.org/usage.php", array(
|
||||
console("[DEBUG] Sending usage data...", true, true, 2);
|
||||
$plist = "";
|
||||
foreach($this->plugin->getList() as $p){
|
||||
$plist .= str_replace(array(";", ":"), "", $p["name"]).":".str_replace(array(";", ":"), "", $p["version"]).";";
|
||||
}
|
||||
|
||||
$this->asyncOperation(ASYNC_CURL_POST, array(
|
||||
"url" => "http://stats.pocketmine.net/usage.php",
|
||||
"data" => array(
|
||||
"serverid" => $this->server->serverID,
|
||||
"port" => $this->server->port,
|
||||
"os" => Utils::getOS(),
|
||||
"memory_total" => $this->getProperty("memory-limit"),
|
||||
"memory_usage" => memory_get_usage(true),
|
||||
"php_version" => PHP_VERSION,
|
||||
"version" => MAJOR_VERSION,
|
||||
"mc_version" => CURRENT_MINECRAFT_VERSION,
|
||||
"protocol" => CURRENT_PROTOCOL,
|
||||
"online" => count($this->server->clients),
|
||||
"max" => $this->server->maxClients,
|
||||
));
|
||||
"plugins" => $plist,
|
||||
),
|
||||
), NULL);
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
foreach($this->apiList as $ob){
|
||||
if(is_callable($ob, "__destruct")){
|
||||
foreach($this->apiList as $i => $ob){
|
||||
if(method_exists($ob, "__destruct")){
|
||||
$ob->__destruct();
|
||||
unset($this->apiList[$ob]);
|
||||
unset($this->apiList[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function loadProperties(){
|
||||
if(($memory = $this->getProperty("memory-limit")) !== false){
|
||||
if(($memory = str_replace("B", "", strtoupper($this->getProperty("memory-limit")))) !== false){
|
||||
$value = array("M" => 1, "G" => 1024);
|
||||
$real = ((int) substr($memory, 0, -1)) * $value[substr($memory, -1)];
|
||||
if($real < 128){
|
||||
console("[ERROR] PocketMine doesn't work right with less than 128MB of RAM", true, true, 0);
|
||||
console("[WARNING] PocketMine-MP may not work right with less than 128MB of RAM", true, true, 0);
|
||||
}
|
||||
@ini_set("memory_limit", $memory);
|
||||
}else{
|
||||
$this->setProperty("memory-limit", "256M");
|
||||
}
|
||||
if(!$this->config->exists("invisible")){
|
||||
$this->config->set("invisible", false);
|
||||
$this->setProperty("memory-limit", "128M");
|
||||
}
|
||||
|
||||
if($this->server instanceof PocketMinecraftServer){
|
||||
$this->server->setType($this->getProperty("server-type"));
|
||||
$this->server->timePerSecond = $this->getProperty("time-per-second");
|
||||
$this->server->invisible = $this->getProperty("invisible");
|
||||
$this->server->maxClients = $this->getProperty("max-players");
|
||||
$this->server->description = $this->getProperty("description");
|
||||
$this->server->motd = $this->getProperty("motd");
|
||||
@ -280,10 +261,9 @@ class ServerAPI{
|
||||
break;
|
||||
case "gamemode":
|
||||
case "max-players":
|
||||
case "port":
|
||||
case "server-port":
|
||||
case "debug":
|
||||
case "difficulty":
|
||||
case "time-per-second":
|
||||
$v = (int) $v;
|
||||
break;
|
||||
case "server-id":
|
||||
@ -294,26 +274,47 @@ class ServerAPI{
|
||||
}
|
||||
$this->config->set($n, $v);
|
||||
}
|
||||
if($this->getProperty("hardcore") == 1 and $this->getProperty("difficulty") < 3){
|
||||
$this->setProperty("difficulty", 3);
|
||||
}
|
||||
}
|
||||
|
||||
public function init(){
|
||||
if($this->getProperty("send-usage") !== false){
|
||||
$this->server->schedule(36000, array($this, "sendUsage"), array(), true); //Send usage data every 30 minutes
|
||||
$this->server->schedule(6000, array($this, "sendUsage"), array(), true); //Send the info after 5 minutes have passed
|
||||
$this->sendUsage();
|
||||
}
|
||||
if($this->getProperty("auto-save") === true){
|
||||
$this->server->schedule(18000, array($this, "autoSave"), array(), true);
|
||||
}
|
||||
if($this->getProperty("enable-rcon") === true){
|
||||
$this->rcon = new RCON($this->getProperty("rcon.password", ""), $this->getProperty("rcon.port", $this->getProperty("server-port")), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0", $this->getProperty("rcon.threads", 1), $this->getProperty("rcon.clients-per-thread", 50));
|
||||
}
|
||||
|
||||
if($this->getProperty("enable-query") === true){
|
||||
$this->query = new Query();
|
||||
}
|
||||
CraftingRecipes::init();
|
||||
$this->server->init();
|
||||
unregister_tick_function(array($this->server, "tick"));
|
||||
$this->console->__destruct();
|
||||
if($this->rcon instanceof RCON){
|
||||
$this->rcon->stop();
|
||||
}
|
||||
$this->__destruct();
|
||||
unset($this->server);
|
||||
if($this->getProperty("upnp-forwarding") === true ){
|
||||
console("[INFO] [UPnP] Removing port forward...");
|
||||
UPnP_RemovePortForward($this->getProperty("port"));
|
||||
UPnP_RemovePortForward($this->getProperty("server-port"));
|
||||
}
|
||||
return $this->restart;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
public function asyncOperation($t, $d, $c = null){
|
||||
return $this->server->asyncOperation($t, $d, $c);
|
||||
}
|
||||
|
||||
public function addHandler($e, $c, $p = 5){
|
||||
return $this->server->addHandler($e, $c, $p);
|
||||
}
|
||||
@ -326,10 +327,6 @@ class ServerAPI{
|
||||
return $this->server->handle($e, $d);
|
||||
}
|
||||
|
||||
public function action($t, $c, $r = true){
|
||||
return $this->server->action($t, $c, $r);
|
||||
}
|
||||
|
||||
public function schedule($t, $c, $d, $r = false, $e = "server.schedule"){
|
||||
return $this->server->schedule($t, $c, $d, $r, $e);
|
||||
}
|
||||
@ -346,55 +343,11 @@ class ServerAPI{
|
||||
return $this->server->deleteEvent($id);
|
||||
}
|
||||
|
||||
public function importMap($dir, $remove = false){
|
||||
if(file_exists($dir."level.dat")){
|
||||
$nbt = new NBT();
|
||||
$level = parseNBTData($nbt->loadFile($dir."level.dat"));
|
||||
if($level["LevelName"] == ""){
|
||||
$level["LevelName"] = "world".time();
|
||||
}
|
||||
console("[DEBUG] Importing map \"".$level["LevelName"]."\" gamemode ".$level["GameType"]." with seed ".$level["RandomSeed"], true, true, 2);
|
||||
unset($level["Player"]);
|
||||
$lvName = $level["LevelName"]."/";
|
||||
@mkdir(DATA_PATH."worlds/".$lvName, 0777);
|
||||
file_put_contents(DATA_PATH."worlds/".$lvName."level.dat", serialize($level));
|
||||
$entities = parseNBTData($nbt->loadFile($dir."entities.dat"));
|
||||
file_put_contents(DATA_PATH."worlds/".$lvName."entities.dat", serialize($entities["Entities"]));
|
||||
if(!isset($entities["TileEntities"])){
|
||||
$entities["TileEntities"] = array();
|
||||
}
|
||||
file_put_contents(DATA_PATH."worlds/".$lvName."tileEntities.dat", serialize($entities["TileEntities"]));
|
||||
console("[DEBUG] Imported ".count($entities["Entities"])." Entities and ".count($entities["TileEntities"])." TileEntities", true, true, 2);
|
||||
|
||||
if($remove === true){
|
||||
rename($dir."chunks.dat", DATA_PATH."worlds/".$lvName."chunks.dat");
|
||||
unlink($dir."level.dat");
|
||||
@unlink($dir."level.dat_old");
|
||||
@unlink($dir."player.dat");
|
||||
unlink($dir."entities.dat");
|
||||
}else{
|
||||
copy($dir."chunks.dat", DATA_PATH."worlds/".$lvName."chunks.dat");
|
||||
}
|
||||
if($this->getProperty("level-name") === false){
|
||||
console("[INFO] Setting default level to \"".$level["LevelName"]."\"");
|
||||
$this->setProperty("level-name", $level["LevelName"]);
|
||||
$this->setProperty("gamemode", $level["GameType"]);
|
||||
$this->server->seed = $level["RandomSeed"];
|
||||
$this->server->spawn = array("x" => $level["SpawnX"], "y" => $level["SpawnY"], "z" => $level["SpawnZ"]);
|
||||
$this->writeProperties();
|
||||
}
|
||||
console("[INFO] Map \"".$level["LevelName"]."\" importing done!");
|
||||
unset($level, $entities, $nbt);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getProperties(){
|
||||
return $this->config->getAll();
|
||||
}
|
||||
|
||||
public function getProperty($name){
|
||||
public function getProperty($name, $default = false){
|
||||
if(($v = arg($name)) !== false){ //Allow for command-line arguments
|
||||
switch(strtolower(trim($v))){
|
||||
case "on":
|
||||
@ -418,7 +371,7 @@ class ServerAPI{
|
||||
break;
|
||||
case "gamemode":
|
||||
case "max-players":
|
||||
case "port":
|
||||
case "server-port":
|
||||
case "debug":
|
||||
case "difficulty":
|
||||
case "time-per-second":
|
||||
@ -432,7 +385,7 @@ class ServerAPI{
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
return $this->config->get($name);
|
||||
return ($this->config->exists($name) ? $this->config->get($name):$default);
|
||||
}
|
||||
|
||||
public function setProperty($name, $value){
|
||||
@ -449,7 +402,9 @@ class ServerAPI{
|
||||
if(isset($this->$name)){
|
||||
return false;
|
||||
}elseif(!class_exists($class)){
|
||||
$internal = false;
|
||||
if($dir === false){
|
||||
$internal = true;
|
||||
$dir = FILE_PATH."src/API/";
|
||||
}
|
||||
$file = $dir.$class.".php";
|
||||
@ -458,10 +413,12 @@ class ServerAPI{
|
||||
return false;
|
||||
}
|
||||
require_once($file);
|
||||
}else{
|
||||
$internal = true;
|
||||
}
|
||||
$this->$name = new $class($this->server);
|
||||
$this->$name = new $class();
|
||||
$this->apiList[] = $this->$name;
|
||||
console("[INFO] API \x1b[36m".$name."\x1b[0m [\x1b[30;1m".$class."\x1b[0m] loaded");
|
||||
console("[".($internal === true ? "INTERNAL":"DEBUG")."] API \x1b[36m".$name."\x1b[0m [\x1b[30;1m".$class."\x1b[0m] loaded", true, true, ($internal === true ? 3:2));
|
||||
}
|
||||
|
||||
}
|
122
src/API/TileAPI.php
Normal file
122
src/API/TileAPI.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class TileAPI{
|
||||
private $server;
|
||||
private $tiles;
|
||||
private $tCnt = 1;
|
||||
function __construct(){
|
||||
$this->tiles = array();
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function get(Position $pos){
|
||||
$tile = $this->server->query("SELECT * FROM tiles WHERE level = '".$pos->level->getName()."' AND x = {$pos->x} AND y = {$pos->y} AND z = {$pos->z};", true);
|
||||
if($tile !== false and $tile !== true and ($tile = $this->getByID($tile["ID"])) !== false){
|
||||
return $tile;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getByID($id){
|
||||
if($id instanceof Tile){
|
||||
return $id;
|
||||
}elseif(isset($this->tiles[$id])){
|
||||
return $this->tiles[$id];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
|
||||
}
|
||||
|
||||
public function getAll($level = null){
|
||||
if($level instanceof Level){
|
||||
$tiles = array();
|
||||
$l = $this->server->query("SELECT ID FROM tiles WHERE level = '".$level->getName()."';");
|
||||
if($l !== false and $l !== true){
|
||||
while(($t = $l->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$t = $this->getByID($t["ID"]);
|
||||
if($t instanceof Tile){
|
||||
$tiles[$t->id] = $t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tiles;
|
||||
}
|
||||
return $this->tiles;
|
||||
}
|
||||
|
||||
public function add(Level $level, $class, $x, $y, $z, $data = array()){
|
||||
$id = $this->tCnt++;
|
||||
$this->tiles[$id] = new Tile($level, $id, $class, $x, $y, $z, $data);
|
||||
$this->spawnToAll($this->tiles[$id]);
|
||||
return $this->tiles[$id];
|
||||
}
|
||||
|
||||
public function addSign(Level $level, $x, $y, $z, $lines = array("", "", "", "")){
|
||||
return $this->add($level, TILE_SIGN, $x, $y, $z, $data = array(
|
||||
"id" => "Sign",
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
"Text1" => $lines[0],
|
||||
"Text2" => $lines[1],
|
||||
"Text3" => $lines[2],
|
||||
"Text4" => $lines[3],
|
||||
));
|
||||
}
|
||||
|
||||
public function spawnToAll(Tile $t){
|
||||
foreach($this->server->api->player->getAll($t->level) as $player){
|
||||
if($player->eid !== false){
|
||||
$t->spawn($player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function spawnAll(Player $player){
|
||||
foreach($this->getAll($player->level) as $t){
|
||||
$t->spawn($player);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove($id){
|
||||
if(isset($this->tiles[$id])){
|
||||
$t = $this->tiles[$id];
|
||||
$this->tiles[$id] = null;
|
||||
unset($this->tiles[$id]);
|
||||
$t->closed = true;
|
||||
$t->close();
|
||||
$this->server->query("DELETE FROM tiles WHERE ID = ".$id.";");
|
||||
$this->server->api->dhandle("tile.remove", $t);
|
||||
$t = null;
|
||||
unset($t);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class TileEntityAPI{
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
public function get($x, $y = false, $z = false){
|
||||
if(($x instanceof Vector3) or ($x instanceof Block)){
|
||||
$z = (int) $x->z;
|
||||
$y = (int) $x->y;
|
||||
$x = (int) $x->x;
|
||||
}else{
|
||||
$x = (int) $x;
|
||||
$y = (int) $y;
|
||||
$z = (int) $z;
|
||||
}
|
||||
$tiles = $this->server->query("SELECT * FROM tileentities WHERE x = $x AND y = $y AND z = $z;");
|
||||
$ret = array();
|
||||
if($tiles !== false and $tiles !== true){
|
||||
while(($t = $tiles->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
if(($tile = $this->getByID($t["ID"])) !== false){
|
||||
if($tile->normal === true){
|
||||
$ret[] = $tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(count($ret) === 0){
|
||||
return false;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function getByID($id){
|
||||
if($id instanceof TileEntity){
|
||||
return $id;
|
||||
}elseif(isset($this->server->tileEntities[$id])){
|
||||
return $this->server->tileEntities[$id];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function init(){
|
||||
|
||||
}
|
||||
|
||||
public function getAll(){
|
||||
return $this->server->tileEntities;
|
||||
}
|
||||
|
||||
public function add($class, $x, $y, $z, $data = array()){
|
||||
$id = $this->tCnt++;
|
||||
$this->server->tileEntities[$id] = new TileEntity($this->server, $id, $class, $x, $y, $z, $data);
|
||||
$this->spawnToAll($id);
|
||||
return $this->server->tileEntities[$id];
|
||||
}
|
||||
|
||||
public function addSign($x, $y, $z, $lines = array("", "", "", "")){
|
||||
return $this->add(TILE_SIGN, $x, $y, $z, $data = array(
|
||||
"id" => "Sign",
|
||||
"x" => $x,
|
||||
"y" => $y,
|
||||
"z" => $z,
|
||||
"Text1" => $lines[0],
|
||||
"Text2" => $lines[1],
|
||||
"Text3" => $lines[2],
|
||||
"Text4" => $lines[3],
|
||||
));
|
||||
}
|
||||
|
||||
public function spawnTo($id, $player, $queue = false){
|
||||
$t = $this->getByID($id);
|
||||
if($t === false){
|
||||
return false;
|
||||
}
|
||||
$t->spawn($player, $queue);
|
||||
}
|
||||
|
||||
public function spawnToAll($id){
|
||||
$t = $this->getByID($id);
|
||||
if($t === false){
|
||||
return false;
|
||||
}
|
||||
foreach($this->server->api->player->getAll() as $player){
|
||||
if($player->eid !== false){
|
||||
$t->spawn($player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function spawnAll($player){
|
||||
foreach($this->getAll() as $t){
|
||||
$t->spawn($player);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove($id){
|
||||
if(isset($this->server->tileEntities[$id])){
|
||||
$t = $this->server->tileEntities[$eid];
|
||||
$this->server->tileEntities[$id] = null;
|
||||
unset($this->server->tileEntities[$id]);
|
||||
$t->closed = true;
|
||||
$t->close();
|
||||
$this->server->query("DELETE FROM tileentities WHERE ID = ".$id.";");
|
||||
$t = null;
|
||||
unset($t);
|
||||
}
|
||||
}
|
||||
}
|
@ -33,43 +33,41 @@ class TimeAPI{
|
||||
"sunrise" => 17800,
|
||||
);
|
||||
private $server;
|
||||
function __construct(PocketMinecraftServer $server){
|
||||
$this->server = $server;
|
||||
function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
|
||||
public function init(){
|
||||
$this->server->api->console->register("time", "Manages server time", array($this, "commandHandler"));
|
||||
$this->server->api->console->register("time", "<check|set|add> [time]", array($this, "commandHandler"));
|
||||
}
|
||||
|
||||
public function commandHandler($cmd, $params, $issuer, $alias){
|
||||
$output = "";
|
||||
switch($cmd){
|
||||
case "time":
|
||||
$level = false;
|
||||
if($issuer instanceof Player){
|
||||
$level = $issuer->level;
|
||||
}
|
||||
$p = strtolower(array_shift($params));
|
||||
switch($p){
|
||||
case "check":
|
||||
$output .= "Time: ".$this->getDate().", ".$this->getPhase()." (".$this->get(true).")\n";
|
||||
$output .= "Time: ".$this->getDate($level).", ".$this->getPhase($level)." (".$this->get(true, $level).")\n";
|
||||
break;
|
||||
case "add":
|
||||
$this->add(array_shift($params));
|
||||
$output .= "Set the time to ".$this->add(array_shift($params), $level)."\n";
|
||||
break;
|
||||
case "set":
|
||||
$this->set(array_shift($params));
|
||||
$output .= "Set the time to ".$this->set(array_shift($params), $level)."\n";
|
||||
break;
|
||||
case "sunrise":
|
||||
$this->sunrise();
|
||||
break;
|
||||
case "day":
|
||||
$this->day();
|
||||
break;
|
||||
case "sunset":
|
||||
$this->sunset();
|
||||
break;
|
||||
case "night":
|
||||
$this->night();
|
||||
$output .= "Set the time to ".$this->set($p, $level)."\n";
|
||||
break;
|
||||
default:
|
||||
$output .= "Usage: /time <check | set | add | sunrise | day | sunset | night> [time]\n";
|
||||
$output .= "Usage: /time <check|set|add> [time]\n";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -78,33 +76,39 @@ class TimeAPI{
|
||||
}
|
||||
|
||||
public function night(){
|
||||
$this->set("night");
|
||||
return $this->set("night");
|
||||
}
|
||||
public function day(){
|
||||
$this->set("day");
|
||||
return $this->set("day");
|
||||
}
|
||||
public function sunrise(){
|
||||
$this->set("sunrise");
|
||||
return $this->set("sunrise");
|
||||
}
|
||||
public function sunset(){
|
||||
$this->set("sunset");
|
||||
return $this->set("sunset");
|
||||
}
|
||||
|
||||
public function get($raw = false){
|
||||
return $raw === true ? $this->server->time:abs($this->server->time) % 19200;
|
||||
public function get($raw = false, $level = false){
|
||||
if(!($level instanceof Level)){
|
||||
$level = $this->server->api->level->getDefault();
|
||||
}
|
||||
return $raw === true ? $level->getTime():abs($level->getTime()) % 19200;
|
||||
}
|
||||
|
||||
public function add($time){
|
||||
$this->server->time += (int) $time;
|
||||
public function add($time, $level = false){
|
||||
if(!($level instanceof Level)){
|
||||
$level = $this->server->api->level->getDefault();
|
||||
}
|
||||
$level->setTime($level->getTime() + (int) $time);
|
||||
}
|
||||
|
||||
public function getDate($time = false){
|
||||
$time = $time === false ? $this->get():$time;
|
||||
$time = !is_integer($time) ? $this->get(false, $time):$time;
|
||||
return str_pad(strval((floor($time /800) + 6) % 24), 2, "0", STR_PAD_LEFT).":".str_pad(strval(floor(($time % 800) / 13.33)), 2, "0", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
public function getPhase($time = false){
|
||||
$time = $time === false ? $this->get():$time;
|
||||
$time = !is_integer($time) ? $this->get(false, $time):$time;
|
||||
if($time < $this->phase["sunset"]){
|
||||
$time = "day";
|
||||
}elseif($time < $this->phase["night"]){
|
||||
@ -117,12 +121,16 @@ class TimeAPI{
|
||||
return $time;
|
||||
}
|
||||
|
||||
public function set($time){
|
||||
if(is_string($time) and isset($this->phases[$time])){
|
||||
$this->server->time = $this->phases[$time];
|
||||
}else{
|
||||
$this->server->time = (int) $time;
|
||||
public function set($time, $level = false){
|
||||
if(!($level instanceof Level)){
|
||||
$level = $this->server->api->level->getDefault();
|
||||
}
|
||||
if(is_string($time) and isset($this->phases[$time])){
|
||||
$level->setTime($this->phases[$time]);
|
||||
}else{
|
||||
$level->setTime((int) $time);
|
||||
}
|
||||
return $level->getTime();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class Async extends Thread {
|
||||
/**
|
||||
* Provide a passthrough to call_user_func_array
|
||||
**/
|
||||
public function __construct($method, $params = array()){
|
||||
$this->method = $method;
|
||||
$this->params = $params;
|
||||
$this->result = null;
|
||||
$this->joined = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The smallest thread in the world
|
||||
**/
|
||||
public function run(){
|
||||
if(($this->result=call_user_func_array($this->method, $this->params))){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to create your threads from functions ...
|
||||
**/
|
||||
public static function call($method, $params = array()){
|
||||
$thread = new Async($method, $params);
|
||||
if($thread->start()){
|
||||
return $thread;
|
||||
} /** else throw Nastyness **/
|
||||
}
|
||||
|
||||
/**
|
||||
* Do whatever, result stored in $this->result, don't try to join twice
|
||||
**/
|
||||
public function __toString(){
|
||||
if(!$this->joined) {
|
||||
$this->joined = true;
|
||||
$this->join();
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
}
|
@ -28,7 +28,13 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class Deprecation{
|
||||
public static $events = array(
|
||||
"server.tick" => "ServerAPI::schedule()",
|
||||
"server.time" => "time.change",
|
||||
"world.block.change" => "block.change",
|
||||
"block.drop" => "item.drop",
|
||||
"api.op.check" => "op.check",
|
||||
"api.player.offline.get" => "player.offline.get",
|
||||
"api.player.offline.save" => "player.offline.save",
|
||||
);
|
||||
|
||||
|
||||
|
1923
src/Player.php
1923
src/Player.php
File diff suppressed because it is too large
Load Diff
@ -27,37 +27,32 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
class PocketMinecraftServer{
|
||||
public $tCnt;
|
||||
public $version, $invisible, $api, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $timePerSecond, $spawn, $entities, $mapDir, $mapName, $map, $levelData, $tileEntities;
|
||||
private $serverip, $database, $interface, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $ticker;
|
||||
public $serverID, $interface, $database, $version, $invisible, $api, $tickMeasure, $preparedSQL, $seed, $gamemode, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled;
|
||||
private $serverip, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $ticks, $memoryStats, $async = array(), $asyncID = 0;
|
||||
|
||||
private function load(){
|
||||
$this->version = new VersionString();
|
||||
console("[INFO] \x1b[33;1mPocketMine-MP ".MAJOR_VERSION." #".$this->version->getNumber()." by @shoghicp, LGPL License", true, true, 0);
|
||||
console("[INFO] Target Minecraft PE: \x1b[36;1m".CURRENT_MINECRAFT_VERSION."\x1b[0m, protocol #".CURRENT_PROTOCOL, true, true, 0);
|
||||
@cli_set_process_title("PocketMine-MP ".MAJOR_VERSION);
|
||||
if($this->version->isDev()){
|
||||
console("[INFO] \x1b[31;1mThis is a Development version");
|
||||
}
|
||||
console("[INFO] Starting Minecraft PE Server at ".$this->serverip.":".$this->port);
|
||||
console("[INFO] Starting \x1b[36;1m".CURRENT_MINECRAFT_VERSION."\x1b[0m #".CURRENT_PROTOCOL." Minecraft PE Server at ".$this->serverip.":".$this->port);
|
||||
if($this->port < 19132 or $this->port > 19135){ //Mojang =(
|
||||
console("[WARNING] You've selected a not-standard port. Normal port range is from 19132 to 19135 included");
|
||||
}
|
||||
define("BOOTUP_RANDOM", Utils::getRandomBytes(16));
|
||||
$this->serverID = $this->serverID === false ? Utils::readLong(Utils::getRandomBytes(8, false)):$this->serverID;
|
||||
$this->seed = $this->seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)):$this->seed;
|
||||
console("[INFO] Loading database...");
|
||||
$this->startDatabase();
|
||||
$this->doTick = false;
|
||||
$this->api = false;
|
||||
$this->tCnt = 1;
|
||||
$this->mapDir = false;
|
||||
$this->mapName = false;
|
||||
$this->events = array();
|
||||
$this->eventsID = array();
|
||||
$this->handlers = array();
|
||||
$this->map = false;
|
||||
$this->invisible = false;
|
||||
$this->levelData = false;
|
||||
$this->difficulty = 1;
|
||||
$this->tileEntities = array();
|
||||
$this->tiles = array();
|
||||
$this->entities = array();
|
||||
$this->custom = array();
|
||||
$this->evCnt = 1;
|
||||
@ -68,25 +63,26 @@ class PocketMinecraftServer{
|
||||
$this->scheduleCnt = 1;
|
||||
$this->description = "";
|
||||
$this->whitelist = false;
|
||||
$this->memoryStats = array();
|
||||
$this->clients = array();
|
||||
$this->spawn = array("x" => 128.5,"y" => 100,"z" => 128.5);
|
||||
$this->time = 0;
|
||||
$this->timePerSecond = 10;
|
||||
$this->spawn = false;
|
||||
$this->saveEnabled = true;
|
||||
$this->tickMeasure = array_fill(0, 40, 0);
|
||||
$this->setType("normal");
|
||||
$this->interface = new MinecraftInterface("255.255.255.255", $this->port, true, false);
|
||||
$this->interface = new MinecraftInterface($this, "255.255.255.255", $this->port, true, false, $this->serverip);
|
||||
$this->reloadConfig();
|
||||
console("[INFO] Server Name: \x1b[36m".$this->name."\x1b[0m");
|
||||
console("[DEBUG] Server ID: ".$this->serverID, true, true, 2);
|
||||
$this->stop = false;
|
||||
$this->ticks = 0;
|
||||
$this->asyncThread = new AsyncMultipleQueue();
|
||||
}
|
||||
|
||||
function __construct($name, $gamemode = CREATIVE, $seed = false, $port = 19132, $serverID = false, $serverip = "0.0.0.0"){
|
||||
function __construct($name, $gamemode = SURVIVAL, $seed = false, $port = 19132, $serverip = "0.0.0.0"){
|
||||
$this->port = (int) $port; //19132 - 19135
|
||||
$this->doTick = true;
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->name = $name;
|
||||
$this->motd = "Welcome to ".$name;
|
||||
$this->serverID = $serverID;
|
||||
$this->serverID = false;
|
||||
$this->seed = $seed;
|
||||
$this->serverip = $serverip;
|
||||
$this->load();
|
||||
@ -98,38 +94,63 @@ class PocketMinecraftServer{
|
||||
return round($tps, 4);
|
||||
}
|
||||
|
||||
public function loadEvents(){
|
||||
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->api->dhandle("server.time", $this->time);');
|
||||
$this->action(5000000, 'if($this->difficulty < 2){$this->api->dhandle("server.regeneration", 1);}');
|
||||
$this->action(1000000 * 60, '$this->reloadConfig();');
|
||||
$this->action(1000000 * 60 * 10, '$this->custom = array();');
|
||||
if($this->api instanceof ServerAPI){
|
||||
$this->action(1000000 * 80, '$cnt = count($this->clients); if($cnt > 1){$this->api->chat->broadcast("Online (".$cnt."): ".implode(", ",$this->api->player->online()));}');
|
||||
public function titleTick(){
|
||||
$time = microtime(true);
|
||||
if(ENABLE_ANSI === true){
|
||||
echo "\x1b]0;PocketMine-MP ".MAJOR_VERSION." | Online ". count($this->clients)."/".$this->maxClients." | RAM ".round((memory_get_usage() / 1024) / 1024, 2)."MB | U ".round(($this->interface->bandwidth[1] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2)." D ".round(($this->interface->bandwidth[0] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2)." kB/s | TPS ".$this->getTPS()."\x07";
|
||||
}
|
||||
$this->interface->bandwidth = array(0, 0, $time);
|
||||
}
|
||||
|
||||
public function loadEvents(){
|
||||
if(ENABLE_ANSI === true){
|
||||
$this->schedule(30, array($this, "titleTick"), array(), true);
|
||||
}
|
||||
$this->schedule(20 * 15, array($this, "checkTicks"), array(), true);
|
||||
$this->schedule(20 * 60, array($this, "checkMemory"), array(), true);
|
||||
$this->schedule(20, array($this, "asyncOperationChecker"), array(), true);
|
||||
}
|
||||
|
||||
public function checkTicks(){
|
||||
if($this->getTPS() < 12){
|
||||
console("[WARNING] Can't keep up! Is the server overloaded?");
|
||||
}
|
||||
}
|
||||
|
||||
public function checkMemory(){
|
||||
$info = $this->debugInfo();
|
||||
$data = $info["memory_usage"].",".$info["players"].",".$info["entities"];
|
||||
$i = count($this->memoryStats) - 1;
|
||||
if($i < 0 or $this->memoryStats[$i] !== $data){
|
||||
$this->memoryStats[] = $data;
|
||||
}
|
||||
$this->action(1000000 * 120, '$this->debugInfo(true);');
|
||||
}
|
||||
|
||||
public function startDatabase(){
|
||||
$this->preparedSQL = new stdClass();
|
||||
$this->preparedSQL->entity = new stdClass();
|
||||
$this->database = new SQLite3(":memory:");
|
||||
//$this->query("PRAGMA journal_mode = OFF;");
|
||||
//$this->query("PRAGMA encoding = \"UTF-8\";");
|
||||
//$this->query("PRAGMA secure_delete = OFF;");
|
||||
$this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE);");
|
||||
$this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, type NUMERIC, class NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);");
|
||||
$this->query("CREATE TABLE tileentities (ID INTEGER PRIMARY KEY, class TEXT, x NUMERIC, y NUMERIC, z NUMERIC, spawnable NUMERIC);");
|
||||
$this->query("PRAGMA journal_mode = OFF;");
|
||||
$this->query("PRAGMA encoding = \"UTF-8\";");
|
||||
$this->query("PRAGMA secure_delete = OFF;");
|
||||
$this->query("CREATE TABLE players (CID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE COLLATE NOCASE);");
|
||||
$this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, level TEXT, type NUMERIC, class NUMERIC, hasUpdate NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);");
|
||||
$this->query("CREATE TABLE tiles (ID INTEGER PRIMARY KEY, level TEXT, class TEXT, x NUMERIC, y NUMERIC, z NUMERIC, spawnable NUMERIC);");
|
||||
$this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);");
|
||||
$this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);");
|
||||
//$this->query("PRAGMA synchronous = OFF;");
|
||||
$this->query("CREATE TABLE blockUpdates (level TEXT, x INTEGER, y INTEGER, z INTEGER, type INTEGER, delay NUMERIC);");
|
||||
$this->query("CREATE TABLE recipes (id INTEGER PRIMARY KEY, type NUMERIC, recipe TEXT);");
|
||||
$this->query("PRAGMA synchronous = OFF;");
|
||||
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
|
||||
$this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);");
|
||||
$this->preparedSQL->updateActions = $this->database->prepare("UPDATE actions SET last = :time WHERE last <= (:time - interval);");
|
||||
$this->preparedSQL->updateAction = $this->database->prepare("UPDATE actions SET last = :time WHERE ID = :id;");
|
||||
$this->preparedSQL->entity->setPosition = $this->database->prepare("UPDATE entities SET x = :x, y = :y, z = :z, pitch = :pitch, yaw = :yaw WHERE EID = :eid ;");
|
||||
$this->preparedSQL->entity->setLevel = $this->database->prepare("UPDATE entities SET level = :level WHERE EID = :eid ;");
|
||||
}
|
||||
|
||||
public function query($sql, $fetch = false){
|
||||
console("[INTERNAL] [SQL] ".$sql, true, true, 3);
|
||||
$result = $this->database->query($sql) or console("[ERROR] [SQL Error] ".$this->database->lastErrorMsg().". Query: ".$sql, true, true, 0);
|
||||
if($fetch === true and ($result !== false and $result !== true)){
|
||||
if($fetch === true and ($result instanceof SQLite3Result)){
|
||||
$result = $result->fetchArray(SQLITE3_ASSOC);
|
||||
}
|
||||
return $result;
|
||||
@ -142,10 +163,12 @@ class PocketMinecraftServer{
|
||||
public function debugInfo($console = false){
|
||||
$info = array();
|
||||
$info["tps"] = $this->getTPS();
|
||||
$info["memory_usage"] = round((memory_get_usage(true) / 1024) / 1024, 2)."MB";
|
||||
$info["memory_peak_usage"] = round((memory_get_peak_usage(true) / 1024) / 1024, 2)."MB";
|
||||
$info["memory_usage"] = round((memory_get_usage() / 1024) / 1024, 2)."MB";
|
||||
$info["memory_peak_usage"] = round((memory_get_peak_usage() / 1024) / 1024, 2)."MB";
|
||||
$info["entities"] = $this->query("SELECT count(EID) as count FROM entities;", true);
|
||||
$info["entities"] = $info["entities"]["count"];
|
||||
$info["players"] = $this->query("SELECT count(CID) as count FROM players;", true);
|
||||
$info["players"] = $info["players"]["count"];
|
||||
$info["events"] = count($this->eventsID);
|
||||
$info["handlers"] = $this->query("SELECT count(ID) as count FROM handlers;", true);
|
||||
$info["handlers"] = $info["handlers"]["count"];
|
||||
@ -159,31 +182,27 @@ class PocketMinecraftServer{
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function close($reason = "stop"){
|
||||
public function close($reason = "server stop"){
|
||||
if($this->stop !== true){
|
||||
if(is_int($reason)){
|
||||
$reason = "signal stop";
|
||||
}
|
||||
if(($this->api instanceof ServerAPI) === true){
|
||||
if(($this->api->chat instanceof ChatAPI) === true){
|
||||
$this->api->chat->send(false, "Stopping server...");
|
||||
$this->api->chat->broadcast("Stopping server...");
|
||||
}
|
||||
}
|
||||
//$this->ticker->stop = true;
|
||||
$this->save(true);
|
||||
$this->stop = true;
|
||||
$this->trigger("server.close", $reason);
|
||||
$this->interface->close();
|
||||
@$this->asyncThread->stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function chat($owner, $text, $target = false){
|
||||
$this->api->chat->send($owner, $text, $target);
|
||||
}
|
||||
|
||||
public function setType($type = "normal"){
|
||||
switch($type){
|
||||
switch(trim(strtolower($type))){
|
||||
case "normal":
|
||||
case "demo":
|
||||
$this->serverType = "MCCPP;Demo;";
|
||||
break;
|
||||
case "minecon":
|
||||
@ -193,7 +212,60 @@ class PocketMinecraftServer{
|
||||
|
||||
}
|
||||
|
||||
public function addHandler($event, $callable, $priority = 5){
|
||||
public function asyncOperation($type, array $data, callable $callable = null){
|
||||
$d = "";
|
||||
$type = (int) $type;
|
||||
switch($type){
|
||||
case ASYNC_CURL_GET:
|
||||
$d .= Utils::writeShort(strlen($data["url"])).$data["url"].(isset($data["timeout"]) ? Utils::writeShort($data["timeout"]) : Utils::writeShort(10));
|
||||
break;
|
||||
case ASYNC_CURL_POST:
|
||||
$d .= Utils::writeShort(strlen($data["url"])).$data["url"].(isset($data["timeout"]) ? Utils::writeShort($data["timeout"]) : Utils::writeShort(10));
|
||||
$d .= Utils::writeShort(count($data["data"]));
|
||||
foreach($data["data"] as $key => $value){
|
||||
$d .= Utils::writeShort(strlen($key)).$key . Utils::writeInt(strlen($value)).$value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
$ID = $this->asyncID++;
|
||||
$this->async[$ID] = $callable;
|
||||
$this->asyncThread->input .= Utils::writeInt($ID).Utils::writeShort($type).$d;
|
||||
return $ID;
|
||||
}
|
||||
|
||||
public function asyncOperationChecker(){
|
||||
if(isset($this->asyncThread->output{5})){
|
||||
$offset = 0;
|
||||
$ID = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
|
||||
$offset += 4;
|
||||
$type = Utils::readShort(substr($this->asyncThread->output, $offset, 2));
|
||||
$offset += 2;
|
||||
$data = array();
|
||||
switch($type){
|
||||
case ASYNC_CURL_GET:
|
||||
case ASYNC_CURL_POST:
|
||||
$len = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
|
||||
$offset += 4;
|
||||
$data["result"] = substr($this->asyncThread->output, $offset, $len);
|
||||
$offset += $len;
|
||||
break;
|
||||
}
|
||||
$this->asyncThread->output = substr($this->asyncThread->output, $offset);
|
||||
if(isset($this->async[$ID]) and $this->async[$ID] !== null and is_callable($this->async[$ID])){
|
||||
if(is_array($this->async[$ID])){
|
||||
$method = $this->async[$ID][1];
|
||||
$result = $this->async[$ID][0]->$method($data, $type, $ID);
|
||||
}else{
|
||||
$result = $this->async[$ID]($data, $type, $ID);
|
||||
}
|
||||
}
|
||||
unset($this->async[$ID]);
|
||||
}
|
||||
}
|
||||
|
||||
public function addHandler($event,callable $callable, $priority = 5){
|
||||
if(!is_callable($callable)){
|
||||
return false;
|
||||
}elseif(isset(Deprecation::$events[$event])){
|
||||
@ -211,21 +283,24 @@ class PocketMinecraftServer{
|
||||
return $hnid;
|
||||
}
|
||||
|
||||
public function dhandle($e, $d){
|
||||
return $this->handle($e, $d);
|
||||
}
|
||||
|
||||
public function handle($event, &$data){
|
||||
$this->preparedSQL->selectHandlers->reset();
|
||||
$this->preparedSQL->selectHandlers->clear();
|
||||
$this->preparedSQL->selectHandlers->bindValue(":name", $event, SQLITE3_TEXT);
|
||||
$handlers = $this->preparedSQL->selectHandlers->execute();
|
||||
$result = true;
|
||||
if($handlers !== false and $handlers !== true){
|
||||
console("[INTERNAL] Handling ".$event, true, true, 3);
|
||||
$result = null;
|
||||
if($handlers instanceof SQLite3Result){
|
||||
$call = array();
|
||||
while(($hn = $handlers->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$call[(int) $hn["ID"]] = true;
|
||||
}
|
||||
$handlers->finalize();
|
||||
foreach($call as $hnid => $boolean){
|
||||
if($result !== false){
|
||||
if($result !== false and $result !== true){
|
||||
$called[$hnid] = true;
|
||||
$handler = $this->handlers[$hnid];
|
||||
if(is_array($handler)){
|
||||
@ -258,45 +333,6 @@ class PocketMinecraftServer{
|
||||
}
|
||||
}
|
||||
|
||||
public function loadMap(){
|
||||
if($this->mapName !== false and trim($this->mapName) !== ""){
|
||||
$this->levelData = unserialize(file_get_contents($this->mapDir."level.dat"));
|
||||
if($this->levelData === false){
|
||||
console("[ERROR] Invalid world data for \"".$this->mapDir."\. Please import the world correctly");
|
||||
$this->close("invalid world data");
|
||||
}
|
||||
console("[INFO] Map: ".$this->levelData["LevelName"]);
|
||||
$this->time = (int) $this->levelData["Time"];
|
||||
$this->seed = (int) $this->levelData["RandomSeed"];
|
||||
if(isset($this->levelData["SpawnX"])){
|
||||
$this->spawn = array("x" => $this->levelData["SpawnX"], "y" => $this->levelData["SpawnY"], "z" => $this->levelData["SpawnZ"]);
|
||||
}else{
|
||||
$this->levelData["SpawnX"] = $this->spawn["x"];
|
||||
$this->levelData["SpawnY"] = $this->spawn["y"];
|
||||
$this->levelData["SpawnZ"] = $this->spawn["z"];
|
||||
}
|
||||
$this->levelData["Time"] = $this->time;
|
||||
console("[INFO] Spawn: X \x1b[36m".$this->levelData["SpawnX"]."\x1b[0m Y \x1b[36m".$this->levelData["SpawnY"]."\x1b[0m Z \x1b[36m".$this->levelData["SpawnZ"]."\x1b[0m");
|
||||
console("[INFO] Time: \x1b[36m".$this->time."\x1b[0m");
|
||||
console("[INFO] Seed: \x1b[36m".$this->seed."\x1b[0m");
|
||||
console("[INFO] Gamemode: \x1b[36m".$this->getGamemode()."\x1b[0m");
|
||||
$d = array(0 => "peaceful", 1 => "easy", 2 => "normal", 3 => "hard");
|
||||
console("[INFO] Difficulty: \x1b[36m".$d[$this->difficulty]."\x1b[0m");
|
||||
console("[INFO] Loading map...");
|
||||
$this->map = new ChunkParser();
|
||||
if(!$this->map->loadFile($this->mapDir."chunks.dat")){
|
||||
console("[ERROR] Couldn't load the map \"\x1b[32m".$this->levelData["LevelName"]."\x1b[0m\"!", true, true, 0);
|
||||
$this->map = false;
|
||||
}else{
|
||||
$this->map->loadMap();
|
||||
}
|
||||
}else{
|
||||
console("[INFO] Time: \x1b[36m".$this->time."\x1b[0m");
|
||||
console("[INFO] Seed: \x1b[36m".$this->seed."\x1b[0m");
|
||||
console("[INFO] Gamemode: \x1b[36m".$this->getGamemode()."\x1b[0m");
|
||||
}
|
||||
}
|
||||
|
||||
public function getGamemode(){
|
||||
switch($this->gamemode){
|
||||
case SURVIVAL:
|
||||
@ -305,142 +341,57 @@ class PocketMinecraftServer{
|
||||
return "creative";
|
||||
case ADVENTURE:
|
||||
return "adventure";
|
||||
case VIEW:
|
||||
return "view";
|
||||
}
|
||||
}
|
||||
|
||||
public function loadEntities(){
|
||||
if($this->map !== false){
|
||||
console("[INFO] Loading entities...");
|
||||
$entities = unserialize(file_get_contents($this->mapDir."entities.dat"));
|
||||
if($entities === false or !is_array($entities)){
|
||||
console("[ERROR] Invalid world data for \"".$this->mapDir."\. Please import the world correctly");
|
||||
$this->close("invalid world data");
|
||||
}
|
||||
foreach($entities as $entity){
|
||||
if(!isset($entity["id"])){
|
||||
break;
|
||||
}
|
||||
if(isset($this->api) and $this->api !== false){
|
||||
if($entity["id"] === 64){ //Item Drop
|
||||
$e = $this->api->entity->add(ENTITY_ITEM, $entity["Item"]["id"], array(
|
||||
"meta" => $entity["Item"]["Damage"],
|
||||
"stack" => $entity["Item"]["Count"],
|
||||
"x" => $entity["Pos"][0],
|
||||
"y" => $entity["Pos"][1],
|
||||
"z" => $entity["Pos"][2],
|
||||
"yaw" => $entity["Rotation"][0],
|
||||
"pitch" => $entity["Rotation"][1],
|
||||
));
|
||||
}elseif($entity["id"] === OBJECT_PAINTING){ //Painting
|
||||
$e = $this->api->entity->add(ENTITY_OBJECT, $entity["id"], $entity);
|
||||
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
|
||||
$e->setHealth($entity["Health"]);
|
||||
}else{
|
||||
$e = $this->api->entity->add(ENTITY_MOB, $entity["id"], $entity);
|
||||
$e->setPosition($entity["Pos"][0], $entity["Pos"][1], $entity["Pos"][2], $entity["Rotation"][0], $entity["Rotation"][1]);
|
||||
$e->setHealth($entity["Health"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$tiles = unserialize(file_get_contents($this->mapDir."tileEntities.dat"));
|
||||
foreach($tiles as $tile){
|
||||
if(!isset($tile["id"])){
|
||||
break;
|
||||
}
|
||||
$t = $this->api->tileentity->add($tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
|
||||
}
|
||||
$this->action(1000000 * 60 * 15, '$this->api->chat->broadcast("Forcing save...");$this->save();');
|
||||
}
|
||||
}
|
||||
|
||||
public function save($final = false){
|
||||
if($this->mapName !== false){
|
||||
$this->levelData["Time"] = $this->time;
|
||||
file_put_contents($this->mapDir."level.dat", serialize($this->levelData));
|
||||
$this->map->saveMap($final);
|
||||
$this->trigger("server.save", $final);
|
||||
console("[INFO] Saving entities...");
|
||||
if(count($this->entities) > 0){
|
||||
$entities = array();
|
||||
foreach($this->entities as $entity){
|
||||
if($entity->class === ENTITY_MOB){
|
||||
$entities[] = array(
|
||||
"id" => $entity->type,
|
||||
"Color" => @$entity->data["Color"],
|
||||
"Sheared" => @$entity->data["Sheared"],
|
||||
"Health" => $entity->health,
|
||||
"Pos" => array(
|
||||
0 => $entity->x,
|
||||
1 => $entity->y,
|
||||
2 => $entity->z,
|
||||
),
|
||||
"Rotation" => array(
|
||||
0 => $entity->yaw,
|
||||
1 => $entity->pitch,
|
||||
),
|
||||
);
|
||||
}elseif($entity->class === ENTITY_OBJECT){
|
||||
$entities[] = array(
|
||||
"id" => $entity->type,
|
||||
"TileX" => $entity->x,
|
||||
"TileX" => $entity->y,
|
||||
"TileX" => $entity->z,
|
||||
"Health" => $entity->health,
|
||||
"Motive" => $entity->data["Motive"],
|
||||
"Pos" => array(
|
||||
0 => $entity->x,
|
||||
1 => $entity->y,
|
||||
2 => $entity->z,
|
||||
),
|
||||
"Rotation" => array(
|
||||
0 => $entity->yaw,
|
||||
1 => $entity->pitch,
|
||||
),
|
||||
);
|
||||
}elseif($entity->class === ENTITY_ITEM){
|
||||
$entities[] = array(
|
||||
"id" => 64,
|
||||
"Item" => array(
|
||||
"id" => $entity->type,
|
||||
"Damage" => $entity->meta,
|
||||
"Count" => $entity->stack,
|
||||
),
|
||||
"Health" => $entity->health,
|
||||
"Pos" => array(
|
||||
0 => $entity->x,
|
||||
1 => $entity->y,
|
||||
2 => $entity->z,
|
||||
),
|
||||
"Rotation" => array(
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
file_put_contents($this->mapDir."entities.dat", serialize($entities));
|
||||
}
|
||||
if(count($this->tileEntities) > 0){
|
||||
$tiles = array();
|
||||
foreach($this->tileEntities as $tile){
|
||||
$tiles[] = $tile->data;
|
||||
}
|
||||
file_put_contents($this->mapDir."tileEntities.dat", serialize($tiles));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function init(){
|
||||
if($this->mapName !== false and $this->map === false){
|
||||
$this->loadMap();
|
||||
$this->loadEntities();
|
||||
}
|
||||
console("[INFO] Loading events...");
|
||||
$this->loadEvents();
|
||||
//$this->ticker = new TickLoop($this);
|
||||
//$this->ticker->start();
|
||||
declare(ticks=15);
|
||||
register_tick_function(array($this, "tick"));
|
||||
console("[INFO] Starting internal ticker calculation");
|
||||
$t = 0;
|
||||
while(true){
|
||||
switch($t){
|
||||
case 0:
|
||||
declare(ticks=100);
|
||||
break;
|
||||
case 1:
|
||||
declare(ticks=60);
|
||||
break;
|
||||
case 2:
|
||||
declare(ticks=40);
|
||||
break;
|
||||
case 3:
|
||||
declare(ticks=30);
|
||||
break;
|
||||
case 4:
|
||||
declare(ticks=20);
|
||||
break;
|
||||
case 5:
|
||||
declare(ticks=15);
|
||||
break;
|
||||
default:
|
||||
declare(ticks=10);
|
||||
break;
|
||||
}
|
||||
if($t > 5){
|
||||
break;
|
||||
}
|
||||
$this->ticks = 0;
|
||||
while($this->ticks < 20){
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
if($this->getTPS() < 19.5){
|
||||
++$t;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->loadEvents();
|
||||
register_shutdown_function(array($this, "dumpError"));
|
||||
register_shutdown_function(array($this, "close"));
|
||||
if(function_exists("pcntl_signal")){
|
||||
@ -448,24 +399,29 @@ class PocketMinecraftServer{
|
||||
pcntl_signal(SIGINT, array($this, "close"));
|
||||
pcntl_signal(SIGHUP, array($this, "close"));
|
||||
}
|
||||
console("[INFO] Default game type: ".strtoupper($this->getGamemode()));
|
||||
$this->trigger("server.start", microtime(true));
|
||||
console("[INFO] Server started!");
|
||||
console('[INFO] Done ('.round(microtime(true) - START_TIME, 3).'s)! For help, type "help" or "?"');
|
||||
$this->process();
|
||||
}
|
||||
|
||||
public function dumpError(){
|
||||
if($this->stop === true){
|
||||
return;
|
||||
}
|
||||
console("[ERROR] An Unrecovereable has ocurred and the server has Crashed. Creating an Error Dump");
|
||||
$dump = "# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
|
||||
$dump = "```\r\n# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
|
||||
$er = error_get_last();
|
||||
$dump .= "Error: ".var_export($er, true)."\r\n\r\n";
|
||||
$dump .= "Code: \r\n";
|
||||
$file = file($er["file"], FILE_IGNORE_NEW_LINES);
|
||||
$file = @file($er["file"], FILE_IGNORE_NEW_LINES);
|
||||
for($l = max(0, $er["line"] - 10); $l < $er["line"] + 10; ++$l){
|
||||
$dump .= "[".($l + 1)."] ".$file[$l]."\r\n";
|
||||
$dump .= "[".($l + 1)."] ".@$file[$l]."\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
$version = new VersionString();
|
||||
$dump .= "PM Version: ".$version." #".$version->getNumber()." [Protocol ".CURRENT_PROTOCOL."]\r\n";
|
||||
$dump .= "Commit: ".GIT_COMMIT."\r\n";
|
||||
$dump .= "uname -a: ".php_uname("a")."\r\n";
|
||||
$dump .= "PHP Version: " .phpversion()."\r\n";
|
||||
$dump .= "Zend version: ".zend_version()."\r\n";
|
||||
@ -473,114 +429,97 @@ class PocketMinecraftServer{
|
||||
$dump .= "Debug Info: ".var_export($this->debugInfo(false), true)."\r\n\r\n\r\n";
|
||||
global $arguments;
|
||||
$dump .= "Parameters: ".var_export($arguments, true)."\r\n\r\n\r\n";
|
||||
$dump .= "server.properties: ".var_export($this->api->getProperties(), true)."\r\n\r\n\r\n";
|
||||
if($this->api->plugin instanceof PluginAPI){
|
||||
$dump .= "Loaded plugins: ".var_export($this->api->plugin->getList(), true)."\r\n\r\n\r\n";
|
||||
$p = $this->api->getProperties();
|
||||
if($p["rcon.password"] != ""){
|
||||
$p["rcon.password"] = "******";
|
||||
}
|
||||
$dump .= "Loaded Modules: ".var_export(get_loaded_extensions(), true)."\r\n\r\n";
|
||||
$name = "error_dump_".time();
|
||||
$dump .= "server.properties: ".var_export($p, true)."\r\n\r\n\r\n";
|
||||
if($this->api->plugin instanceof PluginAPI){
|
||||
$plist = $this->api->plugin->getList();
|
||||
$dump .= "Loaded plugins:\r\n";
|
||||
foreach($plist as $p){
|
||||
$dump .= $p["name"]." ".$p["version"]." by ".$p["author"]."\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
}
|
||||
$dump .= "Loaded Modules: ".var_export(get_loaded_extensions(), true)."\r\n";
|
||||
$dump .= "Memory Usage Tracking: \r\n".chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9)))."\r\n";
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$dump .= "\r\nphpinfo(): \r\n".chunk_split(base64_encode(gzdeflate(ob_get_contents(), 9)))."\r\n";
|
||||
ob_end_clean();
|
||||
$dump .= "\r\n```";
|
||||
$name = "Error_Dump_".date("D_M_j-H.i.s-T_Y");
|
||||
logg($dump, $name, true, 0, true);
|
||||
console("[ERROR] Please submit the \"logs/{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0);
|
||||
console("[ERROR] Please submit the \"{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0);
|
||||
}
|
||||
|
||||
public function tick(){
|
||||
/*if($this->ticker->tick === true and $this->ticker->isWaiting() === true){
|
||||
$this->ticker->tick = false;
|
||||
$time = microtime(true);
|
||||
array_shift($this->tickMeasure);
|
||||
$this->tickMeasure[] = $this->lastTick = $time;
|
||||
$this->tickerFunction($time);
|
||||
$this->trigger("server.tick", $time);
|
||||
$this->ticker->notify();
|
||||
}*/
|
||||
$time = microtime(true);
|
||||
if($this->lastTick <= ($time - 0.05)){
|
||||
array_shift($this->tickMeasure);
|
||||
$this->tickMeasure[] = $this->lastTick = $time;
|
||||
unset($this->tickMeasure[key($this->tickMeasure)]);
|
||||
++$this->ticks;
|
||||
$this->tickerFunction($time);
|
||||
$this->trigger("server.tick", $time);
|
||||
}
|
||||
}
|
||||
|
||||
public function clientID($ip, $port){
|
||||
return md5($ip . $port, true);
|
||||
public static function clientID($ip, $port){
|
||||
//faster than string indexes in PHP
|
||||
return crc32($ip . $port) ^ crc32($port . $ip . BOOTUP_RANDOM);
|
||||
}
|
||||
|
||||
public function packetHandler($packet){
|
||||
$data =& $packet["data"];
|
||||
$CID = $this->clientID($packet["ip"], $packet["port"]);
|
||||
$CID = PocketMinecraftServer::clientID($packet["ip"], $packet["port"]);
|
||||
if(isset($this->clients[$CID])){
|
||||
$this->clients[$CID]->handle($packet["pid"], $data);
|
||||
$this->clients[$CID]->handlePacket($packet["pid"], $data);
|
||||
}else{
|
||||
if($this->handle("server.noauthpacket", $packet) === false){
|
||||
return;
|
||||
}
|
||||
switch($packet["pid"]){
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
if($this->invisible === true){
|
||||
$this->send(0x1c, array(
|
||||
$data[0],
|
||||
$this->serverID,
|
||||
MAGIC,
|
||||
RAKNET_MAGIC,
|
||||
$this->serverType,
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
break;
|
||||
}
|
||||
if($this->api->ban->isIPBanned($packet["ip"])){
|
||||
$this->send(0x1c, array(
|
||||
$data[0],
|
||||
$this->serverID,
|
||||
MAGIC,
|
||||
$this->serverType. $this->name . " [You're banned]",
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
break;
|
||||
}
|
||||
if(!isset($this->custom["times_".$CID])){
|
||||
$this->custom["times_".$CID] = 0;
|
||||
}
|
||||
$ln = 15;
|
||||
if($this->description == "" or substr($this->description, -1) != " "){
|
||||
$this->description .= " ";
|
||||
}
|
||||
$txt = substr($this->description, $this->custom["times_".$CID], $ln);
|
||||
$txt .= substr($this->description, 0, $ln - strlen($txt));
|
||||
$this->send(0x1c, array(
|
||||
$data[0],
|
||||
$this->serverID,
|
||||
MAGIC,
|
||||
$this->serverType. $this->name . " [".($this->gamemode === CREATIVE ? "C":($this->gamemode === ADVENTURE ? "A":"S")).($this->whitelist !== false ? "W":"")." ".count($this->clients)."/".$this->maxClients."] ".$txt,
|
||||
RAKNET_MAGIC,
|
||||
$this->serverType. $this->name . " [".count($this->clients)."/".$this->maxClients."] ".$txt,
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
$this->custom["times_".$CID] = ($this->custom["times_".$CID] + 1) % strlen($this->description);
|
||||
break;
|
||||
case 0x05:
|
||||
if($this->api->ban->isIPBanned($packet["ip"]) or count($this->clients) >= $this->maxClients){
|
||||
$this->send(0x80, array(
|
||||
0,
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_LOGIN_STATUS,
|
||||
"status" => 1,
|
||||
),
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
$this->send(0x80, array(
|
||||
1,
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_DISCONNECT,
|
||||
),
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
break;
|
||||
}
|
||||
$version = $data[1];
|
||||
$size = strlen($data[2]);
|
||||
if($version !== CURRENT_STRUCTURE){
|
||||
console("[DEBUG] Incorrect structure #$version from ".$packet["ip"].":".$packet["port"], true, true, 2);
|
||||
$this->send(0x1a, array(
|
||||
CURRENT_STRUCTURE,
|
||||
MAGIC,
|
||||
RAKNET_MAGIC,
|
||||
$this->serverID,
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
}else{
|
||||
$this->send(0x06, array(
|
||||
MAGIC,
|
||||
RAKNET_MAGIC,
|
||||
$this->serverID,
|
||||
0,
|
||||
strlen($packet["raw"]),
|
||||
@ -588,36 +527,29 @@ class PocketMinecraftServer{
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
if($this->api->ban->isIPBanned($packet["ip"]) or count($this->clients) >= $this->maxClients){
|
||||
$this->send(0x80, array(
|
||||
0,
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_LOGIN_STATUS,
|
||||
"status" => 1,
|
||||
),
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
$this->send(0x80, array(
|
||||
1,
|
||||
0x00,
|
||||
array(
|
||||
"id" => MC_DISCONNECT,
|
||||
),
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
if($this->invisible === true){
|
||||
break;
|
||||
}
|
||||
$port = $data[2];
|
||||
$MTU = $data[3];
|
||||
$clientID = $data[4];
|
||||
$this->clients[$CID] = new Player($this, $clientID, $packet["ip"], $packet["port"], $MTU); //New Session!
|
||||
$this->clients[$CID]->handle(0x07, $data);
|
||||
if(count($this->clients) < $this->maxClients){
|
||||
$this->clients[$CID] = new Player($clientID, $packet["ip"], $packet["port"], $MTU); //New Session!
|
||||
$this->send(0x08, array(
|
||||
RAKNET_MAGIC,
|
||||
$this->serverID,
|
||||
$this->port,
|
||||
$data[3],
|
||||
0,
|
||||
), false, $packet["ip"], $packet["port"]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function send($pid, $data = array(), $raw = false, $dest = false, $port = false){
|
||||
$this->interface->writePacket($pid, $data, $raw, $dest, $port);
|
||||
return $this->interface->writePacket($pid, $data, $raw, $dest, $port);
|
||||
}
|
||||
|
||||
public function process(){
|
||||
@ -654,49 +586,47 @@ class PocketMinecraftServer{
|
||||
}
|
||||
}
|
||||
|
||||
public function schedule($ticks, $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
|
||||
public function schedule($ticks, callable $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
|
||||
if(!is_callable($callback)){
|
||||
return false;
|
||||
}
|
||||
$add = "";
|
||||
$chcnt = $this->scheduleCnt++;
|
||||
if($repeat === false){
|
||||
$add = '$this->schedule['.$chcnt.']=null;unset($this->schedule['.$chcnt.']);';
|
||||
}
|
||||
$this->schedule[$chcnt] = array($callback, $data, $eventName);
|
||||
$this->action(50000 * $ticks, '$schedule=$this->schedule['.$chcnt.'];'.$add.'if(!is_callable($schedule[0])){$this->schedule['.$chcnt.']=null;unset($this->schedule['.$chcnt.']);return false;}return call_user_func($schedule[0],$schedule[1],$schedule[2]);', (bool) $repeat);
|
||||
$this->query("INSERT INTO actions (ID, interval, last, repeat) VALUES(".$chcnt.", ".($ticks / 20).", ".microtime(true).", ".(((bool) $repeat) === true ? 1:0).");");
|
||||
return $chcnt;
|
||||
}
|
||||
|
||||
public function action($microseconds, $code, $repeat = true){
|
||||
$this->query("INSERT INTO actions (interval, last, code, repeat) VALUES(".($microseconds / 1000000).", ".microtime(true).", '".base64_encode($code)."', ".($repeat === true ? 1:0).");");
|
||||
console("[INTERNAL] Attached to action ".$microseconds, true, true, 3);
|
||||
}
|
||||
|
||||
public function tickerFunction($time){
|
||||
//actions that repeat every x time will go here
|
||||
$this->preparedSQL->selectActions->reset();
|
||||
$this->preparedSQL->selectActions->clear();
|
||||
$this->preparedSQL->selectActions->bindValue(":time", $time, SQLITE3_FLOAT);
|
||||
$actions = $this->preparedSQL->selectActions->execute();
|
||||
|
||||
if($actions === false or $actions === true){
|
||||
return;
|
||||
}
|
||||
if($actions instanceof SQLite3Result){
|
||||
while(($action = $actions->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$return = eval(base64_decode($action["code"]));
|
||||
$cid = $action["ID"];
|
||||
$this->preparedSQL->updateAction->reset();
|
||||
$this->preparedSQL->updateAction->bindValue(":time", $time, SQLITE3_FLOAT);
|
||||
$this->preparedSQL->updateAction->bindValue(":id", $cid, SQLITE3_INTEGER);
|
||||
$this->preparedSQL->updateAction->execute();
|
||||
$schedule = $this->schedule[$cid];
|
||||
if(!is_callable($schedule[0])){
|
||||
$return = false;
|
||||
}else{
|
||||
$return = call_user_func($schedule[0], $schedule[1], $schedule[2]);
|
||||
}
|
||||
|
||||
if($action["repeat"] === 0 or $return === false){
|
||||
$this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";");
|
||||
$this->schedule[$cid] = null;
|
||||
unset($this->schedule[$cid]);
|
||||
}
|
||||
}
|
||||
$actions->finalize();
|
||||
$this->preparedSQL->updateActions->reset();
|
||||
$this->preparedSQL->updateActions->clear();
|
||||
$this->preparedSQL->updateActions->bindValue(":time", $time, SQLITE3_FLOAT);
|
||||
$this->preparedSQL->updateActions->execute();
|
||||
}
|
||||
}
|
||||
|
||||
public function event($event, $func){
|
||||
public function event($event,callable $func){
|
||||
if(!is_callable($func)){
|
||||
return false;
|
||||
}elseif(isset(Deprecation::$events[$event])){
|
||||
|
267
src/build/compile.sh
Executable file
267
src/build/compile.sh
Executable file
@ -0,0 +1,267 @@
|
||||
#!/bin/bash
|
||||
COMPILER_VERSION="0.12"
|
||||
|
||||
PHP_VERSION="5.4.16"
|
||||
ZEND_VM="GOTO"
|
||||
|
||||
LIBEDIT_VERSION="0.3"
|
||||
ZLIB_VERSION="1.2.8"
|
||||
PTHREADS_VERSION="0.0.44"
|
||||
CURL_VERSION="curl-7_30_0"
|
||||
|
||||
echo "[PocketMine] PHP installer and compiler for Linux & Mac"
|
||||
DIR="$(pwd)"
|
||||
date > "$DIR/install.log" 2>&1
|
||||
uname -a >> "$DIR/install.log" 2>&1
|
||||
echo "[INFO] Checking dependecies"
|
||||
type make >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"make\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
type autoconf >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"autoconf\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
type automake >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"automake\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
type libtool >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"libtool\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
type m4 >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"m4\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
type wget >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"wget\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
|
||||
export CC="gcc"
|
||||
COMPILE_FOR_ANDROID=no
|
||||
if [ "$1" == "rpi" ]; then
|
||||
[ -z "$march" ] && march=armv6zk;
|
||||
[ -z "$mtune" ] && mtune=arm1176jzf-s;
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-mfloat-abi=hard -mfpu=vfp";
|
||||
echo "[INFO] Compiling for Raspberry Pi ARMv6zk hard float"
|
||||
elif [ "$1" == "mac" ]; then
|
||||
[ -z "$march" ] && march=prescott;
|
||||
[ -z "$mtune" ] && mtune=generic;
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-fomit-frame-pointer";
|
||||
echo "[INFO] Compiling for Intel MacOS"
|
||||
elif [ "$1" == "crosscompile" ]; then
|
||||
if [ "$2" == "android" ] || [ "$2" == "android-armv6" ]; then
|
||||
COMPILE_FOR_ANDROID=yes
|
||||
[ -z "$march" ] && march=armv6;
|
||||
[ -z "$mtune" ] && mtune=generic;
|
||||
TOOLCHAIN_PREFIX="arm-none-linux-gnueabi"
|
||||
export CC="$TOOLCHAIN_PREFIX-gcc"
|
||||
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-uclibc";
|
||||
echo "[INFO] Cross-compiling for Android ARMv6"
|
||||
elif [ "$2" == "android-armv7" ]; then
|
||||
COMPILE_FOR_ANDROID=yes
|
||||
[ -z "$march" ] && march=armv7;
|
||||
[ -z "$mtune" ] && mtune=generic;
|
||||
TOOLCHAIN_PREFIX="arm-none-linux-gnueabi"
|
||||
export CC="$TOOLCHAIN_PREFIX-gcc"
|
||||
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-uclibc";
|
||||
echo "[INFO] Cross-compiling for Android ARMv7"
|
||||
elif [ "$2" == "rpi" ]; then
|
||||
TOOLCHAIN_PREFIX="arm-linux-gnueabihf"
|
||||
[ -z "$march" ] && march=armv6zk;
|
||||
[ -z "$mtune" ] && mtune=arm1176jzf-s;
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-mfloat-abi=hard -mfpu=vfp";
|
||||
export CC="$TOOLCHAIN_PREFIX-gcc"
|
||||
CONFIGURE_FLAGS="--host=$TOOLCHAIN_PREFIX"
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-uclibc";
|
||||
echo "[INFO] Cross-compiling for Raspberry Pi ARMv6zk hard float"
|
||||
else
|
||||
echo "Please supply a proper platform [android android-armv6 android-armv7 rpi] to cross-compile"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "[INFO] Compiling for current machine"
|
||||
fi
|
||||
|
||||
type $CC >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"$CC\""; read -p "Press [Enter] to continue..."; exit 1; }
|
||||
|
||||
[ -z "$THREADS" ] && THREADS=1;
|
||||
[ -z "$march" ] && march=native;
|
||||
[ -z "$mtune" ] && mtune=native;
|
||||
[ -z "$CFLAGS" ] && CFLAGS="";
|
||||
[ -z "$CONFIGURE_FLAGS" ] && CONFIGURE_FLAGS="";
|
||||
|
||||
$CC -O3 -march=$march -mtune=$mtune -fno-gcse $CFLAGS -Q --help=target >> "$DIR/install.log" 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
$CC -O3 -fno-gcse $CFLAGS -Q --help=target >> "$DIR/install.log" 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
export CFLAGS="-O3 -fno-gcse "
|
||||
else
|
||||
export CFLAGS="-O3 -fno-gcse $CFLAGS"
|
||||
fi
|
||||
else
|
||||
export CFLAGS="-O3 -march=$march -mtune=$mtune -fno-gcse $CFLAGS"
|
||||
fi
|
||||
|
||||
|
||||
rm -r -f install_data/ >> "$DIR/install.log" 2>&1
|
||||
rm -r -f php5/ >> "$DIR/install.log" 2>&1
|
||||
rm -r -f bin/ >> "$DIR/install.log" 2>&1
|
||||
mkdir -m 0777 install_data >> "$DIR/install.log" 2>&1
|
||||
mkdir -m 0777 php5 >> "$DIR/install.log" 2>&1
|
||||
mkdir -m 0777 bin >> "$DIR/install.log" 2>&1
|
||||
cd install_data
|
||||
set -e
|
||||
|
||||
#PHP 5
|
||||
echo -n "[PHP] downloading $PHP_VERSION..."
|
||||
wget http://php.net/get/php-$PHP_VERSION.tar.gz/from/this/mirror -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv php-$PHP_VERSION php
|
||||
echo " done!"
|
||||
|
||||
if [ 1 ] || [ "$1" == "crosscompile" ] || [ "$1" == "rpi" ]; then
|
||||
HAVE_LIBEDIT="--without-libedit"
|
||||
else
|
||||
#libedit
|
||||
echo -n "[libedit] downloading $LIBEDIT_VERSION..."
|
||||
wget http://download.sourceforge.net/project/libedit/libedit/libedit-$LIBEDIT_VERSION/libedit-$LIBEDIT_VERSION.tar.gz -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
echo -n " checking..."
|
||||
cd libedit
|
||||
./configure --prefix="$DIR/install_data/php/ext/libedit" --enable-static >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
if make -j $THREADS >> "$DIR/install.log" 2>&1; then
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
HAVE_LIBEDIT="--with-libedit=\"$DIR/install_data/php/ext/libedit\""
|
||||
else
|
||||
echo -n " disabling..."
|
||||
HAVE_LIBEDIT="--without-libedit"
|
||||
fi
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./libedit
|
||||
echo " done!"
|
||||
fi
|
||||
|
||||
#zlib
|
||||
echo -n "[zlib] downloading $ZLIB_VERSION..."
|
||||
wget http://zlib.net/zlib-$ZLIB_VERSION.tar.gz -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv zlib-$ZLIB_VERSION zlib
|
||||
echo -n " checking..."
|
||||
cd zlib
|
||||
./configure --prefix="$DIR/install_data/php/ext/zlib" \
|
||||
--static >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
make -j $THREADS >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./zlib
|
||||
echo " done!"
|
||||
|
||||
if [ "$(uname -s)" == "Darwin" ] && [ "$1" != "crosscompile" ] && [ "$2" != "curl" ]; then
|
||||
HAVE_CURL="shared,/usr/local"
|
||||
else
|
||||
#curl
|
||||
echo -n "[cURL] downloading $CURL_VERSION..."
|
||||
wget https://github.com/bagder/curl/archive/$CURL_VERSION.tar.gz --no-check-certificate -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv curl-$CURL_VERSION curl
|
||||
echo -n " checking..."
|
||||
cd curl
|
||||
./buildconf >> "$DIR/install.log" 2>&1
|
||||
./configure --enable-ipv6 \
|
||||
--enable-optimize \
|
||||
--enable-http \
|
||||
--enable-ftp \
|
||||
--disable-dict \
|
||||
--enable-file \
|
||||
--disable-gopher \
|
||||
--disable-imap \
|
||||
--disable-pop3 \
|
||||
--disable-rtsp \
|
||||
--disable-smtp \
|
||||
--disable-telnet \
|
||||
--disable-tftp \
|
||||
--prefix="$DIR/install_data/php/ext/curl" \
|
||||
--disable-shared \
|
||||
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
make -j $THREADS >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo -n " cleaning..."
|
||||
cd ..
|
||||
rm -r -f ./curl
|
||||
echo " done!"
|
||||
HAVE_CURL="$DIR/install_data/php/ext/curl"
|
||||
fi
|
||||
|
||||
#pthreads
|
||||
echo -n "[PHP pthreads] downloading $PTHREADS_VERSION..."
|
||||
wget http://pecl.php.net/get/pthreads-$PTHREADS_VERSION.tgz --no-check-certificate -q -O - | tar -zx >> "$DIR/install.log" 2>&1
|
||||
mv pthreads-$PTHREADS_VERSION "$DIR/install_data/php/ext/pthreads"
|
||||
echo " done!"
|
||||
|
||||
|
||||
echo -n "[PHP]"
|
||||
set +e
|
||||
if which free >/dev/null; then
|
||||
MAX_MEMORY=$(free -m | awk '/^Mem:/{print $2}')
|
||||
else
|
||||
MAX_MEMORY=$(top -l 1 | grep PhysMem: | awk '{print $10}' | tr -d 'a-zA-Z')
|
||||
fi
|
||||
if [ $MAX_MEMORY -gt 512 ] && [ "$1" != "crosscompile" ]; then
|
||||
echo -n " enabling optimizations..."
|
||||
OPTIMIZATION="--enable-inline-optimization "
|
||||
else
|
||||
OPTIMIZATION="--disable-inline-optimization "
|
||||
fi
|
||||
set -e
|
||||
echo -n " checking..."
|
||||
cd php
|
||||
rm -rf ./aclocal.m4 >> "$DIR/install.log" 2>&1
|
||||
rm -rf ./autom4te.cache/ >> "$DIR/install.log" 2>&1
|
||||
rm -f ./configure >> "$DIR/install.log" 2>&1
|
||||
./buildconf --force >> "$DIR/install.log" 2>&1
|
||||
if [ "$1" == "crosscompile" ]; then
|
||||
sed -i 's/pthreads_working=no/pthreads_working=yes/' ./configure
|
||||
export LIBS="-lpthread -ldl"
|
||||
fi
|
||||
./configure $OPTIMIZATION--prefix="$DIR/php5" \
|
||||
--exec-prefix="$DIR/php5" \
|
||||
--with-curl="$HAVE_CURL" \
|
||||
--with-zlib="$DIR/install_data/php/ext/zlib" \
|
||||
$HAVE_LIBEDIT \
|
||||
--disable-libxml \
|
||||
--disable-xml \
|
||||
--disable-dom \
|
||||
--disable-simplexml \
|
||||
--disable-xmlreader \
|
||||
--disable-xmlwriter \
|
||||
--disable-cgi \
|
||||
--disable-session \
|
||||
--disable-zip \
|
||||
--disable-debug \
|
||||
--disable-phar \
|
||||
--enable-ctype \
|
||||
--enable-sockets \
|
||||
--enable-shared=no \
|
||||
--enable-static=yes \
|
||||
--enable-shmop \
|
||||
--enable-pcntl \
|
||||
--enable-pthreads \
|
||||
--enable-maintainer-zts \
|
||||
--enable-zend-signals \
|
||||
--enable-embedded-mysqli \
|
||||
--enable-bcmath \
|
||||
--enable-cli \
|
||||
--without-pear \
|
||||
--without-iconv \
|
||||
--disable-pdo \
|
||||
--without-pdo-sqlite \
|
||||
--with-zend-vm=$ZEND_VM \
|
||||
$CONFIGURE_FLAGS >> "$DIR/install.log" 2>&1
|
||||
echo -n " compiling..."
|
||||
if [ COMPILE_FOR_ANDROID == "yes" ]; then
|
||||
sed -i 's/-export-dynamic/-all-static/g' Makefile
|
||||
fi
|
||||
make -j $THREADS >> "$DIR/install.log" 2>&1
|
||||
echo -n " installing..."
|
||||
make install >> "$DIR/install.log" 2>&1
|
||||
echo " done!"
|
||||
cd "$DIR"
|
||||
echo -n "[INFO] Cleaning up..."
|
||||
rm -r -f install_data/ >> "$DIR/install.log" 2>&1
|
||||
mv php5/bin/php bin/php
|
||||
rm -r -f php5/ >> "$DIR/install.log" 2>&1
|
||||
date >> "$DIR/install.log" 2>&1
|
||||
echo " done!"
|
||||
echo "[PocketMine] You should start the server now using \"./start.sh\""
|
||||
echo "[PocketMine] If it doesn't works, please send the \"install.log\" file to the Bug Tracker"
|
@ -26,12 +26,35 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
set_time_limit(0);
|
||||
date_default_timezone_set(@date_default_timezone_get());
|
||||
|
||||
date_default_timezone_set("GMT");
|
||||
if(strpos(" ".strtoupper(php_uname("s")), " WIN") !== false){
|
||||
$time = time();
|
||||
$time -= $time % 60;
|
||||
exec("time.exe /T", $hour);
|
||||
$i = array_map("intval", explode(":", trim($hour[0])));
|
||||
exec("date.exe /T", $date);
|
||||
$j = array_map("intval", explode("/", trim($date[0])));
|
||||
$offset = round((mktime($i[0], $i[1], 0, $j[1], $j[0], $j[2]) - $time) / 60) * 60;
|
||||
}else{
|
||||
exec("date +%s", $t);
|
||||
$offset = round((intval(trim($t[0])) - time()) / 60) * 60;
|
||||
}
|
||||
|
||||
$daylight = (int) date("I");
|
||||
|
||||
if($daylight === 0){
|
||||
$offset -= 3600;
|
||||
}
|
||||
|
||||
date_default_timezone_set(timezone_name_from_abbr("", $offset, $daylight));
|
||||
|
||||
gc_enable();
|
||||
error_reporting(E_ALL ^ E_NOTICE);
|
||||
ini_set("allow_url_fopen", 1);
|
||||
ini_set("display_errors", 1);
|
||||
ini_set('default_charset', 'utf-8');
|
||||
ini_set("display_startup_errors", 1);
|
||||
ini_set("default_charset", "utf-8");
|
||||
if(defined("POCKETMINE_COMPILE") and POCKETMINE_COMPILE === true){
|
||||
define("FILE_PATH", realpath(dirname(__FILE__))."/");
|
||||
}else{
|
||||
@ -39,13 +62,16 @@ if(defined("POCKETMINE_COMPILE") and POCKETMINE_COMPILE === true){
|
||||
}
|
||||
set_include_path(get_include_path() . PATH_SEPARATOR . FILE_PATH);
|
||||
|
||||
ini_set("memory_limit", "256M"); //Default
|
||||
ini_set("memory_limit", "128M"); //Default
|
||||
define("LOG", true);
|
||||
define("MAGIC", "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78");
|
||||
define("TEST_MD5", "ffe889db5932db1e3371d48773590e59");
|
||||
define("MAJOR_VERSION", "Alpha_1.2");
|
||||
define("CURRENT_STRUCTURE", 5);
|
||||
define("CURRENT_PROTOCOL", 9);
|
||||
define("CURRENT_MINECRAFT_VERSION", "v0.6.1 alpha");
|
||||
define("CURRENT_API_VERSION", 3);
|
||||
define("CURRENT_PHP_VERSION", "5.4.12");
|
||||
define("START_TIME", microtime(true));
|
||||
define("MAJOR_VERSION", "Alpha_1.3.4");
|
||||
define("CURRENT_MINECRAFT_VERSION", "0.7.3 alpha");
|
||||
define("CURRENT_API_VERSION", 9);
|
||||
define("CURRENT_PHP_VERSION", "5.5");
|
||||
$gitsha1 = false;
|
||||
if(file_exists(FILE_PATH.".git/refs/heads/master")){ //Found Git information!
|
||||
define(GIT_COMMIT, strtolower(trim(file_get_contents(FILE_PATH.".git/refs/heads/master"))));
|
||||
}else{ //Unknown :(
|
||||
define(GIT_COMMIT, str_repeat("00", 20));
|
||||
}
|
@ -34,6 +34,7 @@ define("COBBLE", 4);
|
||||
define("PLANK", 5);
|
||||
define("PLANKS", 5);
|
||||
define("WOODEN_PLANK", 5);
|
||||
define("WOODEN_PLANKS", 5);
|
||||
define("SAPLING", 6);
|
||||
define("SAPLINGS", 6);
|
||||
define("BEDROCK", 7);
|
||||
@ -121,14 +122,18 @@ define("ICE", 79);
|
||||
define("SNOW_BLOCK", 80);
|
||||
define("CACTUS", 81);
|
||||
define("CLAY_BLOCK", 82);
|
||||
define("REEDS", 83);
|
||||
define("SUGARCANE_BLOCK", 83);
|
||||
|
||||
define("FENCE", 85);
|
||||
|
||||
define("NETHERRACK", 87);
|
||||
define("SOUL_SAND", 88);
|
||||
define("GLOWSTONE", 89);
|
||||
define("GLOWSTONE_BLOCK", 89);
|
||||
|
||||
define("CAKE_BLOCK", 92);
|
||||
|
||||
define("TRAPDOOR", 96);
|
||||
|
||||
define("STONE_BRICKS", 98);
|
||||
@ -145,6 +150,7 @@ define("BRICK_STAIRS", 108);
|
||||
define("STONE_BRICK_STAIRS", 109);
|
||||
|
||||
define("NETHER_BRICKS", 112);
|
||||
define("NETHER_BRICK_BLOCK", 112);
|
||||
|
||||
define("NETHER_BRICKS_STAIRS", 114);
|
||||
|
||||
|
@ -25,7 +25,61 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
|
||||
define("PMF_LEVEL_DEFLATE_LEVEL", 6);
|
||||
|
||||
//Gamemodes
|
||||
define("SURVIVAL", 0);
|
||||
define("CREATIVE", 1);
|
||||
define("ADVENTURE", 2);
|
||||
define("VIEW", 3);
|
||||
define("VIEWER", 3);
|
||||
|
||||
|
||||
//Players
|
||||
define("MAX_CHUNK_RATE", 20 / arg("max-chunks-per-second", 3.5)); //Default rate ~172 kB/s
|
||||
define("PLAYER_MAX_QUEUE", 1024);
|
||||
|
||||
define("PLAYER_SURVIVAL_SLOTS", 36);
|
||||
define("PLAYER_CREATIVE_SLOTS", 111);
|
||||
|
||||
|
||||
//Block Updates
|
||||
define("BLOCK_UPDATE_NORMAL", 1);
|
||||
define("BLOCK_UPDATE_RANDOM", 2);
|
||||
define("BLOCK_UPDATE_SCHEDULED", 3);
|
||||
define("BLOCK_UPDATE_WEAK", 4);
|
||||
define("BLOCK_UPDATE_TOUCH", 5);
|
||||
|
||||
|
||||
//Entities
|
||||
define("ENTITY_PLAYER", 1);
|
||||
|
||||
define("ENTITY_MOB", 2);
|
||||
define("MOB_CHICKEN", 10);
|
||||
define("MOB_COW", 11);
|
||||
define("MOB_PIG", 12);
|
||||
define("MOB_SHEEP", 13);
|
||||
|
||||
define("MOB_ZOMBIE", 32);
|
||||
define("MOB_CREEPER", 33);
|
||||
define("MOB_SKELETON", 34);
|
||||
define("MOB_SPIDER", 35);
|
||||
define("MOB_PIGMAN", 36);
|
||||
|
||||
define("ENTITY_OBJECT", 3);
|
||||
define("OBJECT_ARROW", 80);
|
||||
define("OBJECT_PAINTING", 83);
|
||||
|
||||
define("ENTITY_ITEM", 4);
|
||||
|
||||
define("ENTITY_FALLING", 5);
|
||||
define("FALLING_SAND", 66);
|
||||
|
||||
|
||||
//TileEntities
|
||||
define("TILE_SIGN", "Sign");
|
||||
define("TILE_CHEST", "Chest");
|
||||
define("CHEST_SLOTS", 27);
|
||||
define("TILE_FURNACE", "Furnace");
|
||||
define("FURNACE_SLOTS", 3);
|
@ -29,6 +29,7 @@ define("IRON_SHOVEL", 256);//Implemented
|
||||
define("IRON_PICKAXE", 257);//Implemented
|
||||
define("IRON_AXE", 258);//Implemented
|
||||
define("FLINT_STEEL", 259);
|
||||
define("FLINT_AND_STEEL", 259);
|
||||
define("APPLE", 260);//Implemented
|
||||
define("BOW", 261);
|
||||
define("ARROW", 262);
|
||||
@ -37,10 +38,10 @@ define("DIAMOND", 264);//Implemented
|
||||
define("IRON_INGOT", 265);//Implemented
|
||||
define("GOLD_INGOT", 266);//Implemented
|
||||
define("IRON_SWORD", 267);
|
||||
define("WOODEN_SWORD", 268);
|
||||
define("WOODEN_SHOVEL", 269);
|
||||
define("WOODEN_PICKAXE", 270);
|
||||
define("WOODEN_AXE", 271);
|
||||
define("WOODEN_SWORD", 268);//Implemented
|
||||
define("WOODEN_SHOVEL", 269);//Implemented
|
||||
define("WOODEN_PICKAXE", 270);//Implemented
|
||||
define("WOODEN_AXE", 271);//Implemented
|
||||
define("STONE_SWORD", 272);
|
||||
define("STONE_SHOVEL", 273);
|
||||
define("STONE_PICKAXE", 274);
|
||||
@ -50,12 +51,17 @@ define("DIAMOND_SHOVEL", 277);
|
||||
define("DIAMOND_PICKAXE", 278);
|
||||
define("DIAMOND_AXE", 279);
|
||||
define("STICK", 280);//Implemented
|
||||
define("STICKS", 280);
|
||||
define("BOWL", 281);//Implemented
|
||||
define("MUSHROOM_STEW", 282);
|
||||
define("GOLD_SWORD", 283);
|
||||
define("GOLD_SHOVEL", 284);
|
||||
define("GOLD_PICKAXE", 285);
|
||||
define("GOLD_AXE", 286);
|
||||
define("GOLDEN_SWORD", 283);
|
||||
define("GOLDEN_SHOVEL", 284);
|
||||
define("GOLDEN_PICKAXE", 285);
|
||||
define("GOLDEN_AXE", 286);
|
||||
define("STRING", 287);
|
||||
define("FEATHER", 288);//Implemented
|
||||
define("GUNPOWDER", 289);
|
||||
@ -64,6 +70,7 @@ define("STONE_HOE", 291);
|
||||
define("IRON_HOE", 292);//Implemented
|
||||
define("DIAMOND_HOE", 293);
|
||||
define("GOLD_HOE", 294);
|
||||
define("GOLDEN_HOE", 294);
|
||||
define("SEEDS", 295);
|
||||
define("WHEAT_SEEDS", 295);
|
||||
define("WHEAT", 296);
|
||||
@ -74,19 +81,19 @@ define("LEATHER_PANTS", 300);
|
||||
define("LEATHER_BOOTS", 301);
|
||||
define("CHAIN_HELMET", 302);
|
||||
define("CHAIN_CHESTPLATE", 303);
|
||||
define("CHAIN_LEGGINS", 304);
|
||||
define("CHAIN_LEGGINGS", 304);
|
||||
define("CHAIN_BOOTS", 305);
|
||||
define("IRON_HELMET", 306);
|
||||
define("IRON_CHESTPLATE", 307);
|
||||
define("IRON_LEGGINS", 308);
|
||||
define("IRON_LEGGINGS", 308);
|
||||
define("IRON_BOOTS", 309);
|
||||
define("DIAMOND_HELMET", 310);
|
||||
define("DIAMOND_CHESTPLATE", 311);
|
||||
define("DIAMOND_LEGGINS", 312);
|
||||
define("DIAMOND_LEGGINGS", 312);
|
||||
define("DIAMOND_BOOTS", 313);
|
||||
define("GOLD_HELMET", 314);
|
||||
define("GOLD_CHESTPLATE", 315);
|
||||
define("GOLD_LEGGINS", 316);
|
||||
define("GOLD_LEGGINGS", 316);
|
||||
define("GOLD_BOOTS", 317);
|
||||
define("FLINT", 318);
|
||||
define("RAW_PORKCHOP", 319);
|
||||
@ -95,6 +102,8 @@ define("PAINTING", 321);
|
||||
define("GOLDEN_APPLE", 322);
|
||||
define("SIGN", 323);
|
||||
define("WOODEN_DOOR", 324);
|
||||
define("BUCKET", 325);
|
||||
|
||||
|
||||
define("IRON_DOOR", 330);
|
||||
|
||||
@ -119,7 +128,7 @@ define("COOKED_FISH", 350);
|
||||
define("DYE", 351);
|
||||
define("BONE", 352);
|
||||
define("SUGAR", 353);
|
||||
|
||||
define("CAKE", 354);
|
||||
define("BED", 355);
|
||||
|
||||
|
||||
@ -138,6 +147,8 @@ define("COOKED_BEEF", 364);
|
||||
define("RAW_CHICKEN", 365);
|
||||
define("COOKED_CHICKEN", 366);
|
||||
|
||||
define("SPAWN_EGG", 383);
|
||||
|
||||
define("NETHER_BRICK", 405);
|
||||
define("QUARTZ", 406);
|
||||
define("NETHER_QUARTZ", 406);
|
||||
|
@ -31,12 +31,13 @@ require_once(FILE_PATH."/src/functions.php");
|
||||
/***REM_END***/
|
||||
define(DATA_PATH, realpath(arg("data-path", FILE_PATH))."/");
|
||||
|
||||
if(strpos(strtoupper(php_uname("s")), "WIN") === false or arg("enable-ansi", false) === true){
|
||||
if(arg("enable-ansi", strpos(strtoupper(php_uname("s")), "WIN") === false ? true:false) === true){
|
||||
define("ENABLE_ANSI", true);
|
||||
}else{
|
||||
define("ENABLE_ANSI", false);
|
||||
}
|
||||
set_error_handler("fatal_handler", E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_RECOVERABLE_ERROR | E_DEPRECATED);
|
||||
|
||||
set_error_handler("error_handler", E_ALL);
|
||||
|
||||
$errors = 0;
|
||||
|
||||
@ -45,12 +46,6 @@ if(version_compare("5.4.0", PHP_VERSION) > 0){
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(version_compare(CURRENT_PHP_VERSION, PHP_VERSION) > 0){
|
||||
console("[NOTICE] PocketMine-MP hasn't been tested with PHP < ".CURRENT_PHP_VERSION, true, true, 0);
|
||||
}elseif(version_compare(CURRENT_PHP_VERSION, PHP_VERSION) < 0){
|
||||
console("[NOTICE] PocketMine-MP hasn't been tested with PHP > ".CURRENT_PHP_VERSION, true, true, 0);
|
||||
}
|
||||
|
||||
if(php_sapi_name() !== "cli"){
|
||||
console("[ERROR] You must run PocketMine-MP using the CLI.", true, true, 0);
|
||||
++$errors;
|
||||
@ -81,16 +76,15 @@ if(!extension_loaded("zlib") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") .
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(!extension_loaded("gmp") and @dl((PHP_SHLIB_SUFFIX === "dll" ? "php_":"") . "gmp." . PHP_SHLIB_SUFFIX) === false){
|
||||
console("[ERROR] Unable to find the GMP extension.", true, true, 0);
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if($errors > 0){
|
||||
console("[ERROR] Please use the installer provided on the homepage.", true, true, 0);
|
||||
exit(1); //Exit with error
|
||||
}
|
||||
|
||||
/***REM_START***/
|
||||
require_once(FILE_PATH."/src/math/Vector3.php");
|
||||
require_once(FILE_PATH."/src/world/Position.php");
|
||||
require_once(FILE_PATH."/src/pmf/PMF.php");
|
||||
|
||||
require_all(FILE_PATH . "src/");
|
||||
/***REM_END***/
|
@ -25,21 +25,64 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
if(!function_exists("cli_set_process_title")){
|
||||
function cli_set_process_title($title){
|
||||
if(ENABLE_ANSI === true){
|
||||
echo "\x1b]0;".$title."\x07";
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dummy(){
|
||||
|
||||
}
|
||||
|
||||
function safe_var_dump($var, $cnt = 0){
|
||||
switch(true){
|
||||
case is_array($var):
|
||||
echo str_repeat(" ", $cnt)."array(".count($var).") {".PHP_EOL;
|
||||
foreach($var as $key => $value){
|
||||
echo str_repeat(" ", $cnt + 1)."[".(is_integer($key) ? $key:'"'.$key.'"')."]=>".PHP_EOL;
|
||||
safe_var_dump($value, $cnt + 1);
|
||||
}
|
||||
echo str_repeat(" ", $cnt)."}".PHP_EOL;
|
||||
break;
|
||||
case is_integer($var):
|
||||
echo str_repeat(" ", $cnt)."int(".$var.")".PHP_EOL;
|
||||
break;
|
||||
case is_float($var):
|
||||
echo str_repeat(" ", $cnt)."float(".$var.")".PHP_EOL;
|
||||
break;
|
||||
case is_bool($var):
|
||||
echo str_repeat(" ", $cnt)."bool(".($var === true ? "true":"false").")".PHP_EOL;
|
||||
break;
|
||||
case is_string($var):
|
||||
echo str_repeat(" ", $cnt)."string(".strlen($var).") \"$var\"".PHP_EOL;
|
||||
break;
|
||||
case is_resource($var):
|
||||
echo str_repeat(" ", $cnt)."resource() of type (".get_resource_type($var).")".PHP_EOL;
|
||||
break;
|
||||
case is_object($var):
|
||||
echo str_repeat(" ", $cnt)."object(".get_class($var).")".PHP_EOL;
|
||||
break;
|
||||
case is_null($var):
|
||||
echo str_repeat(" ", $cnt)."NULL".PHP_EOL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function kill($pid){
|
||||
switch(Utils::getOS()){
|
||||
case "win":
|
||||
ob_start();
|
||||
passthru("%WINDIR%\\System32\\taskkill.exe /F /PID ".((int) $pid));
|
||||
ob_end_clean();
|
||||
exec("taskkill.exe /F /PID ".((int) $pid)." > NUL");
|
||||
break;
|
||||
case "mac":
|
||||
case "linux":
|
||||
default:
|
||||
ob_start();
|
||||
passthru("kill -9 ".((int) $pid));
|
||||
ob_end_clean();
|
||||
exec("kill -9 ".((int) $pid)." > /dev/null 2>&1");
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,8 +220,9 @@ function console($message, $EOL = true, $log = true, $level = 1){
|
||||
logg($replaced, "console", false, $level);
|
||||
}
|
||||
if(ENABLE_ANSI === true){
|
||||
$add = "";
|
||||
if(preg_match("/\[([a-zA-Z0-9]*)\]/", $message, $matches) > 0){
|
||||
$add = "\x1b";
|
||||
$add .= "\x1b";
|
||||
switch($matches[1]){
|
||||
case "ERROR":
|
||||
$add .= "[31;1m";
|
||||
@ -197,8 +241,8 @@ function console($message, $EOL = true, $log = true, $level = 1){
|
||||
$add = "";
|
||||
break;
|
||||
}
|
||||
$message = $time . $add . $message . "\x1b[0m";
|
||||
}
|
||||
$message = $time . $add . $message . "\x1b[0m";
|
||||
}else{
|
||||
$message = $replaced;
|
||||
}
|
||||
@ -206,9 +250,12 @@ function console($message, $EOL = true, $log = true, $level = 1){
|
||||
}
|
||||
}
|
||||
|
||||
function fatal_handler($errno, $errstr, $errfile, $errline){
|
||||
console("[ERROR] A level ".$errno." error happened: \"$errstr\" in \"$errfile\" at line $errline", true, true, 0);
|
||||
function error_handler($errno, $errstr, $errfile, $errline){
|
||||
if(error_reporting() === 0){ //@ error-control
|
||||
return false;
|
||||
}
|
||||
console("[ERROR] A level ".$errno." error happened: \"$errstr\" in \"$errfile\" at line $errline", true, true, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
function logg($message, $name, $EOL = true, $level = 2, $close = false){
|
||||
@ -219,7 +266,7 @@ function logg($message, $name, $EOL = true, $level = 2, $close = false){
|
||||
$fpointers = array();
|
||||
}
|
||||
if(!isset($fpointers[$name]) or $fpointers[$name] === false){
|
||||
$fpointers[$name] = @fopen(DATA_PATH."logs/".$name.".log", "ab");
|
||||
$fpointers[$name] = @fopen(DATA_PATH."/".$name.".log", "ab");
|
||||
}
|
||||
@fwrite($fpointers[$name], $message);
|
||||
if($close === true){
|
||||
|
@ -31,8 +31,8 @@ define("WINDOW_FURNACE", 2);
|
||||
|
||||
class Window{
|
||||
private $server;
|
||||
public function __construct(PocketMinecraftServer $server){
|
||||
|
||||
public function __construct(){
|
||||
$this->server = ServerAPI::request();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,11 +25,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
/***REM_START***/
|
||||
require_once(FILE_PATH."/src/math/Vector3.php");
|
||||
/***REM_END***/
|
||||
|
||||
abstract class Block extends Vector3{
|
||||
abstract class Block extends Position{
|
||||
public static $class = array(
|
||||
AIR => "AirBlock",
|
||||
STONE => "StoneBlock",
|
||||
@ -109,6 +105,8 @@ abstract class Block extends Vector3{
|
||||
SOUL_SAND => "SoulSandBlock",
|
||||
GLOWSTONE_BLOCK => "GlowstoneBlock",
|
||||
|
||||
CAKE_BLOCK => "CakeBlock",
|
||||
|
||||
TRAPDOOR => "TrapdoorBlock",
|
||||
|
||||
STONE_BRICKS => "StoneBricksBlock",
|
||||
@ -142,24 +140,26 @@ abstract class Block extends Vector3{
|
||||
public $isActivable = false;
|
||||
public $breakable = true;
|
||||
public $isFlowable = false;
|
||||
public $isSolid = true;
|
||||
public $isTransparent = false;
|
||||
public $isReplaceable = false;
|
||||
public $isPlaceable = true;
|
||||
public $inWorld = false;
|
||||
public $level = false;
|
||||
public $hasPhysics = false;
|
||||
public $isLiquid = false;
|
||||
public $x;
|
||||
public $y;
|
||||
public $z;
|
||||
public $isFullBlock = true;
|
||||
public $x = 0;
|
||||
public $y = 0;
|
||||
public $z = 0;
|
||||
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
$this->id = (int) $id;
|
||||
$this->meta = (int) $meta;
|
||||
$this->name = $name;
|
||||
$this->breakTime = 0.25;
|
||||
$this->breakTime = 0.20;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
final public function getName(){
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
@ -171,8 +171,8 @@ abstract class Block extends Vector3{
|
||||
return $this->meta & 0x0F;
|
||||
}
|
||||
|
||||
final public function position(Vector3 $v){
|
||||
$this->inWorld = true;
|
||||
final public function position(Position $v){
|
||||
$this->level = $v->level;
|
||||
$this->x = (int) $v->x;
|
||||
$this->y = (int) $v->y;
|
||||
$this->z = (int) $v->z;
|
||||
@ -189,25 +189,33 @@ abstract class Block extends Vector3{
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if($player->gamemode === CREATIVE){
|
||||
return 0.25;
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.15;
|
||||
}
|
||||
return $this->breakTime;
|
||||
}
|
||||
|
||||
public function getSide($side){
|
||||
$v = parent::getSide($side);
|
||||
if($this->level instanceof Level){
|
||||
return $this->level->getBlock($v);
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
final public function __toString(){
|
||||
return "Block ". $this->name ." (".$this->id.":".$this->meta.")";
|
||||
}
|
||||
|
||||
abstract function isBreakable(Item $item, Player $player);
|
||||
|
||||
abstract function onBreak(BlockAPI $level, Item $item, Player $player);
|
||||
abstract function onBreak(Item $item, Player $player);
|
||||
|
||||
abstract function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz);
|
||||
abstract function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz);
|
||||
|
||||
abstract function onActivate(BlockAPI $level, Item $item, Player $player);
|
||||
abstract function onActivate(Item $item, Player $player);
|
||||
|
||||
abstract function onUpdate(BlockAPI $level, $type);
|
||||
abstract function onUpdate($type);
|
||||
}
|
||||
|
||||
/***REM_START***/
|
||||
|
@ -32,11 +32,14 @@ class Item{
|
||||
MELON_SEEDS => "MelonSeedsItem",
|
||||
SIGN => "SignItem",
|
||||
WOODEN_DOOR => "WoodenDoorItem",
|
||||
BUCKET => "BucketItem",
|
||||
IRON_DOOR => "IronDoorItem",
|
||||
CAKE => "CakeItem",
|
||||
BED => "BedItem",
|
||||
PAINTING => "PaintingItem",
|
||||
COAL => "CoalItem",
|
||||
APPLE => "AppleItem",
|
||||
SPAWN_EGG => "SpawnEggItem",
|
||||
DIAMOND => "DiamondItem",
|
||||
STICK => "StickItem",
|
||||
BOWL => "BowlItem",
|
||||
@ -48,6 +51,11 @@ class Item{
|
||||
IRON_PICKAXE => "IronPickaxeItem",
|
||||
IRON_AXE => "IronAxeItem",
|
||||
IRON_HOE => "IronHoeItem",
|
||||
WOODEN_SWORD => "WoodenSwordItem",
|
||||
WOODEN_SHOVEL => "WoodenShovelItem",
|
||||
WOODEN_PICKAXE => "WoodenPickaxeItem",
|
||||
WOODEN_AXE => "WoodenAxeItem",
|
||||
FLINT_STEEL => "FlintSteelItem",
|
||||
);
|
||||
protected $block;
|
||||
protected $id;
|
||||
@ -67,17 +75,20 @@ class Item{
|
||||
$this->block = BlockAPI::get($this->id, $this->meta);
|
||||
$this->name = $this->block->getName();
|
||||
}
|
||||
if($this->isTool() !== false){
|
||||
$this->maxStackSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
final public function getName(){
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function isPlaceable(){
|
||||
final public function isPlaceable(){
|
||||
return (($this->block instanceof Block) and $this->block->isPlaceable === true);
|
||||
}
|
||||
|
||||
public function getBlock(){
|
||||
final public function getBlock(){
|
||||
if($this->block instanceof Block){
|
||||
return $this->block;
|
||||
}else{
|
||||
@ -85,30 +96,152 @@ class Item{
|
||||
}
|
||||
}
|
||||
|
||||
public function getID(){
|
||||
final public function getID(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMetadata(){
|
||||
final public function getMetadata(){
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
public function getMaxStackSize(){
|
||||
final public function getMaxStackSize(){
|
||||
return $this->maxStackSize;
|
||||
}
|
||||
|
||||
public function isPickaxe(){ //Returns false or level of the pickaxe
|
||||
final public function getFuelTime(){
|
||||
if(!isset(FuelData::$duration[$this->id])){
|
||||
return false;
|
||||
}
|
||||
if($this->id !== BUCKET or $this->meta === 10){
|
||||
return FuelData::$duration[$this->id];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final public function getSmeltItem(){
|
||||
if(!isset(SmeltingData::$product[$this->id])){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isset(SmeltingData::$product[$this->id][0]) and !is_array(SmeltingData::$product[$this->id][0])){
|
||||
return BlockAPI::getItem(SmeltingData::$product[$this->id][0], SmeltingData::$product[$this->id][1]);
|
||||
}
|
||||
|
||||
if(!isset(SmeltingData::$product[$this->id][$this->meta])){
|
||||
return false;
|
||||
}
|
||||
|
||||
return BlockAPI::getItem(SmeltingData::$product[$this->id][$this->meta][0], SmeltingData::$product[$this->id][$this->meta][1]);
|
||||
|
||||
}
|
||||
|
||||
public function useOn($object, $force = false){
|
||||
if($this->isTool() or $force === true){
|
||||
if(($object instanceof Entity) and !$this->isSword()){
|
||||
$this->meta += 2;
|
||||
}else{
|
||||
$this->meta++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final public function isTool(){
|
||||
return ($this->id === FLINT_STEEL or $this->id === SHEARS or $this->isPickaxe() !== false or $this->isAxe() !== false or $this->isShovel() !== false or $this->isSword() !== false);
|
||||
}
|
||||
|
||||
final public function getMaxDurability(){
|
||||
if(!$this->isTool() and $this->isHoe() === false and $this->id !== BOW){
|
||||
return false;
|
||||
}
|
||||
|
||||
$levels = array(
|
||||
2 => 33,
|
||||
1 => 60,
|
||||
3 => 132,
|
||||
4 => 251,
|
||||
5 => 1562,
|
||||
FLINT_STEEL => 65,
|
||||
SHEARS => 239,
|
||||
BOW => 385,
|
||||
);
|
||||
|
||||
if(($type = $this->isPickaxe()) === false){
|
||||
if(($type = $this->isAxe()) === false){
|
||||
if(($type = $this->isSword()) === false){
|
||||
if(($type = $this->isShovel()) === false){
|
||||
if(($type = $this->isHoe()) === false){
|
||||
$type = $this->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $levels[$type];
|
||||
}
|
||||
|
||||
final public function isPickaxe(){ //Returns false or level of the pickaxe
|
||||
switch($this->id){
|
||||
case IRON_PICKAXE:
|
||||
return 3;
|
||||
return 4;
|
||||
case WOODEN_PICKAXE:
|
||||
return 1;
|
||||
case STONE_PICKAXE:
|
||||
return 2;
|
||||
case DIAMOND_PICKAXE:
|
||||
return 4;
|
||||
case GOLD_PICKAXE:
|
||||
return 3;
|
||||
case DIAMOND_PICKAXE:
|
||||
return 5;
|
||||
case GOLD_PICKAXE:
|
||||
return 2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final public function isAxe(){
|
||||
switch($this->id){
|
||||
case IRON_AXE:
|
||||
return 4;
|
||||
case WOODEN_AXE:
|
||||
return 1;
|
||||
case STONE_AXE:
|
||||
return 3;
|
||||
case DIAMOND_AXE:
|
||||
return 5;
|
||||
case GOLD_AXE:
|
||||
return 2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final public function isSword(){
|
||||
switch($this->id){
|
||||
case IRON_SWORD:
|
||||
return 4;
|
||||
case WOODEN_SWORD:
|
||||
return 1;
|
||||
case STONE_SWORD:
|
||||
return 3;
|
||||
case DIAMOND_SWORD:
|
||||
return 5;
|
||||
case GOLD_SWORD:
|
||||
return 2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final public function isShovel(){
|
||||
switch($this->id){
|
||||
case IRON_SHOVEL:
|
||||
return 4;
|
||||
case WOODEN_SHOVEL:
|
||||
return 1;
|
||||
case STONE_SHOVEL:
|
||||
return 3;
|
||||
case DIAMOND_SHOVEL:
|
||||
return 5;
|
||||
case GOLD_SHOVEL:
|
||||
return 2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -135,7 +268,7 @@ class Item{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
public function onActivate(Level $level, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,13 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class DoorBlock extends TransparentBlock{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
$this->isSolid = false;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true and $face === 1){
|
||||
$blockUp = $level->getBlockFace($block, 1);
|
||||
$blockDown = $level->getBlockFace($block, 0);
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($face === 1){
|
||||
$blockUp = $this->getSide(1);
|
||||
$blockDown = $this->getSide(0);
|
||||
if($blockUp->isReplaceable === false or $blockDown->isTransparent === true){
|
||||
return false;
|
||||
}
|
||||
@ -44,52 +45,49 @@ class DoorBlock extends TransparentBlock{
|
||||
2 => 2,
|
||||
3 => 5,
|
||||
);
|
||||
$next = $level->getBlockFace($block, $face[(($direction + 2) % 4)]);
|
||||
$next2 = $level->getBlockFace($block, $face[$direction]);
|
||||
$next = $this->getSide($face[(($direction + 2) % 4)]);
|
||||
$next2 = $this->getSide($face[$direction]);
|
||||
$metaUp = 0x08;
|
||||
if($next->getID() === $this->id or ($next2->isTransparent === false and $next->isTransparent === true)){ //Door hinge
|
||||
$metaUp |= 0x01;
|
||||
}
|
||||
$level->setBlock($blockUp, $this->id, $metaUp); //Top
|
||||
$this->level->setBlock($blockUp, BlockAPI::get($this->id, $metaUp)); //Top
|
||||
|
||||
$this->meta = $direction & 0x03;
|
||||
$level->setBlock($block, $this->id, $this->meta); //Bottom
|
||||
$this->level->setBlock($block, $this); //Bottom
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onBreak(BlockAPI $level, Item $item, Player $player){
|
||||
if($this->inWorld === true){
|
||||
public function onBreak(Item $item, Player $player){
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
$down = $level->getBlockFace($this, 0);
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === $this->id){
|
||||
$level->setBlock($down, 0, 0);
|
||||
$this->level->setBlock($down, new AirBlock());
|
||||
}
|
||||
}else{
|
||||
$up = $level->getBlockFace($this, 1);
|
||||
$up = $this->getSide(1);
|
||||
if($up->getID() === $this->id){
|
||||
$level->setBlock($up, 0, 0);
|
||||
$this->level->setBlock($up, new AirBlock());
|
||||
}
|
||||
}
|
||||
$level->setBlock($this, 0, 0);
|
||||
$this->level->setBlock($this, new AirBlock());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if(($this->meta & 0x08) === 0x08){ //Top
|
||||
$down = $level->getBlockFace($this, 0);
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === $this->id){
|
||||
$meta = $down->getMetadata() ^ 0x04;
|
||||
$level->setBlock($down, $this->id, $meta);
|
||||
$this->level->setBlock($down, BlockAPI::get($this->id, $meta));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}else{
|
||||
$this->meta ^= 0x04;
|
||||
$level->setBlock($this, $this->id, $this->meta);
|
||||
$this->level->setBlock($this, $this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -25,9 +25,15 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class FallableBlock extends GenericBlock{
|
||||
class FallableBlock extends SolidBlock{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
$this->hasPhysics = true;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$ret = $this->level->setBlock($this, $this, true, false, true);
|
||||
ServerAPI::request()->api->block->blockUpdate(clone $this, BLOCK_UPDATE_NORMAL);
|
||||
return $ret;
|
||||
}
|
||||
}
|
@ -29,5 +29,7 @@ class FlowableBlock extends TransparentBlock{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
$this->isFlowable = true;
|
||||
$this->isFullBlock = false;
|
||||
$this->isSolid = false;
|
||||
}
|
||||
}
|
@ -30,30 +30,40 @@ class GenericBlock extends Block{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
return $this->level->setBlock($this, $this, true, false, true);
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item, Player $player){
|
||||
return $this->breakable;
|
||||
return ($this->breakable);
|
||||
}
|
||||
|
||||
public function onBreak(BlockAPI $level, Item $item, Player $player){
|
||||
if($this->inWorld === true){
|
||||
$level->setBlock($this, AIR, 0);
|
||||
return true;
|
||||
public function onBreak(Item $item, Player $player){
|
||||
return $this->level->setBlock($this, new AirBlock(), true, false, true);
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($this->hasPhysics === true and $type === BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === AIR or ($down instanceof LiquidBlock)){
|
||||
$data = array(
|
||||
"x" => $this->x + 0.5,
|
||||
"y" => $this->y + 0.5,
|
||||
"z" => $this->z + 0.5,
|
||||
"Tile" => $this->id,
|
||||
);
|
||||
$server = ServerAPI::request();
|
||||
$this->level->setBlock($this, new AirBlock(), false, false, true);
|
||||
$e = $server->api->entity->add($this->level, ENTITY_FALLING, FALLING_SAND, $data);
|
||||
$server->api->entity->spawnToAll($e);
|
||||
$server->api->block->blockUpdateAround(clone $this, BLOCK_UPDATE_NORMAL, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate(BlockAPI $level, $type){
|
||||
return false;
|
||||
}
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
return false;
|
||||
public function onActivate(Item $item, Player $player){
|
||||
return $this->isActivable;
|
||||
}
|
||||
}
|
@ -31,5 +31,7 @@ class LiquidBlock extends TransparentBlock{
|
||||
$this->isLiquid = true;
|
||||
$this->breakable = false;
|
||||
$this->isReplaceable = true;
|
||||
$this->isSolid = false;
|
||||
$this->isFullBlock = true;
|
||||
}
|
||||
}
|
@ -28,5 +28,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class SolidBlock extends GenericBlock{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
$this->isSolid = true;
|
||||
$this->isFullBlock = true;
|
||||
}
|
||||
}
|
@ -28,10 +28,14 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class StairBlock extends TransparentBlock{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
if(($this->meta & 0x04) === 0x04){
|
||||
$this->isFullBlock = true;
|
||||
}else{
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$faces = array(
|
||||
0 => 0,
|
||||
1 => 2,
|
||||
@ -42,15 +46,17 @@ class StairBlock extends TransparentBlock{
|
||||
if(($fy > 0.5 and $face !== 1) or $face === 0){
|
||||
$this->meta |= 0x04; //Upside-down stairs
|
||||
}
|
||||
$level->setBlock($block, $this->id, $this->meta);
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array($this->id, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -34,5 +34,6 @@ class TransparentBlock extends GenericBlock{
|
||||
$this->isTransparent = true;
|
||||
$this->isReplaceable = false;
|
||||
$this->isPlaceable = true;
|
||||
$this->isSolid = true;
|
||||
}
|
||||
}
|
@ -28,9 +28,10 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class LadderBlock extends TransparentBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(LADDER, $meta, "Ladder");
|
||||
$this->isSolid = false;
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($target->isTransparent === false){
|
||||
$faces = array(
|
||||
2 => 2,
|
||||
@ -38,7 +39,9 @@ class LadderBlock extends TransparentBlock{
|
||||
4 => 4,
|
||||
5 => 5,
|
||||
);
|
||||
$level->setBlock($block, $this->id, $faces[$face]);
|
||||
if(isset($faces[$face])){
|
||||
$this->meta = $faces[$face];
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -28,10 +28,11 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class SignPostBlock extends TransparentBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(SIGN_POST, $meta, "Sign Post");
|
||||
$this->isSolid = false;
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true and $face !== 0){
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($face !== 0){
|
||||
$faces = array(
|
||||
2 => 2,
|
||||
@ -40,25 +41,34 @@ class SignPostBlock extends TransparentBlock{
|
||||
5 => 5,
|
||||
);
|
||||
if(!isset($faces[$face])){
|
||||
$level->setBlock($block, SIGN_POST, 0);
|
||||
$this->meta = floor((($player->entity->yaw + 180) * 16 / 360) + 0.5) & 0x0F;
|
||||
$this->level->setBlock($block, BlockAPI::get(SIGN_POST, $this->meta));
|
||||
return true;
|
||||
}else{
|
||||
$level->setBlock($block, WALL_SIGN, $faces[$face]);
|
||||
$this->meta = $faces[$face];
|
||||
$this->level->setBlock($block, BlockAPI::get(WALL_SIGN, $this->meta));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onBreak(BlockAPI $level, Item $item, Player $player){
|
||||
if($this->inWorld === true){
|
||||
$level->setBlock($this, 0, 0, true, true);
|
||||
return true;
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === AIR){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem(SIGN, 0, 1));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onBreak(Item $item, Player $player){
|
||||
$this->level->setBlock($this, new AirBlock(), true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array(SIGN, 0, 1),
|
||||
|
@ -30,9 +30,30 @@ class TorchBlock extends FlowableBlock{
|
||||
parent::__construct(TORCH, $meta, "Torch");
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true and $face !== 0){
|
||||
if($target->isTransparent === false){
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
$side = $this->getMetadata();
|
||||
$faces = array(
|
||||
1 => 4,
|
||||
2 => 5,
|
||||
3 => 2,
|
||||
4 => 3,
|
||||
5 => 0,
|
||||
6 => 0,
|
||||
0 => 0,
|
||||
);
|
||||
|
||||
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === FENCE)){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id, 0, 1));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($target->isTransparent === false and $face !== 0){
|
||||
$faces = array(
|
||||
1 => 5,
|
||||
2 => 4,
|
||||
@ -40,9 +61,13 @@ class TorchBlock extends FlowableBlock{
|
||||
4 => 2,
|
||||
5 => 1,
|
||||
);
|
||||
$level->setBlock($block, $this->id, $faces[$face]);
|
||||
$this->meta = $faces[$face];
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}elseif($this->getSide(0)->isTransparent === false or $this->getSide(0)->getID() === FENCE){
|
||||
$this->meta = 0;
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -29,10 +29,14 @@ class TrapdoorBlock extends TransparentBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(TRAPDOOR, $meta, "Trapdoor");
|
||||
$this->isActivable = true;
|
||||
if(($this->meta & 0x04) === 0x04){
|
||||
$this->isFullBlock = false;
|
||||
}else{
|
||||
$this->isFullBlock = true;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
if($target->isTransparent === false and $face !== 0 and $face !== 1){
|
||||
}
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if(($target->isTransparent === false or $target->getID() === SLAB) and $face !== 0 and $face !== 1){
|
||||
$faces = array(
|
||||
2 => 0,
|
||||
3 => 1,
|
||||
@ -43,20 +47,18 @@ class TrapdoorBlock extends TransparentBlock{
|
||||
if($fy > 0.5){
|
||||
$this->meta |= 0x08;
|
||||
}
|
||||
$level->setBlock($block, $this->id, $this->meta);
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array($this->id, 0, 1),
|
||||
);
|
||||
}
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
$this->meta ^= 0x04;
|
||||
$level->setBlock($this, $this->id, $this->meta);
|
||||
$this->level->setBlock($this, $this);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -25,44 +25,16 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class WallSignBlock extends TransparentBlock{
|
||||
/***REM_START***/
|
||||
require_once("SignPost.php");
|
||||
/***REM_END***/
|
||||
|
||||
class WallSignBlock extends SignPostBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(WALL_SIGN, $meta, "Wall Sign");
|
||||
TransparentBlock::__construct(WALL_SIGN, $meta, "Wall Sign");
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true and $face !== 0){
|
||||
if($face !== 0){
|
||||
$faces = array(
|
||||
2 => 2,
|
||||
3 => 3,
|
||||
4 => 4,
|
||||
5 => 5,
|
||||
);
|
||||
if(!isset($faces[$face])){
|
||||
$level->setBlock($block, SIGN_POST, 0);
|
||||
return true;
|
||||
}else{
|
||||
$level->setBlock($block, WALL_SIGN, $faces[$face]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function onUpdate($type){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onBreak(BlockAPI $level, Item $item, Player $player){
|
||||
if($this->inWorld === true){
|
||||
$level->setBlock($this, AIR, 0, true, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array(SIGN, 0, 1),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -25,9 +25,14 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class StillWaterBlock extends LiquidBlock{
|
||||
|
||||
/***REM_START***/
|
||||
require_once("Water.php");
|
||||
/***REM_END***/
|
||||
|
||||
class StillWaterBlock extends WaterBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(STILL_WATER, $meta, "Still Water");
|
||||
LiquidBlock::__construct(STILL_WATER, $meta, "Still Water");
|
||||
}
|
||||
|
||||
}
|
@ -30,4 +30,88 @@ class WaterBlock extends LiquidBlock{
|
||||
parent::__construct(WATER, $meta, "Water");
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$ret = $this->level->setBlock($this, $this, true, false, true);
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(clone $this, 10, BLOCK_UPDATE_NORMAL);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
$newId = $this->id;
|
||||
$level = $this->meta & 0x07;
|
||||
if($type !== BLOCK_UPDATE_NORMAL){
|
||||
return false;
|
||||
}
|
||||
|
||||
$falling = $this->meta >> 3;
|
||||
$down = $this->getSide(0);
|
||||
|
||||
if($falling === 0){
|
||||
$countSources = 0;
|
||||
$maxLevel = $level;
|
||||
$hasPath = false;
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b->isFlowable === true and $level < 0x07){
|
||||
$d = $b->getSide(0);
|
||||
$this->level->setBlock($b, new WaterBlock($level + 1), false, false, true);
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($b, 0, 0, $this->level), 10, BLOCK_UPDATE_NORMAL);
|
||||
}elseif($b instanceof WaterBlock){
|
||||
$oLevel = $b->getMetadata();
|
||||
$oFalling = $oLevel >> 3;
|
||||
$oLevel &= 0x07;
|
||||
if($oFalling === 0){
|
||||
if($oLevel === 0){
|
||||
++$countSources;
|
||||
$maxLevel = 1;
|
||||
$hasPath = true;
|
||||
}elseif($oLevel < 0x07 and ($oLevel + 1) <= $maxLevel){
|
||||
$maxLevel = $oLevel + 1;
|
||||
$hasPath = true;
|
||||
}elseif(($level + 1) < $oLevel){
|
||||
$this->level->setBlock($b, new WaterBlock($level + 1), false, false, true);
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($b, 0, 0, $this->level), 10, BLOCK_UPDATE_NORMAL);
|
||||
}elseif($level === $oLevel){
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($b, 0, 0, $this->level), 10, BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if($countSources >= 2){
|
||||
$level = 0; //Source block
|
||||
}elseif($maxLevel < $level){
|
||||
$level = $maxLevel;
|
||||
}elseif($maxLevel === $level and $level > 0 and $hasPath === false){
|
||||
if($level < 0x07){
|
||||
++$level;
|
||||
}else{
|
||||
$newId = AIR;
|
||||
$level = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($down->isFlowable){
|
||||
$this->level->setBlock($down, new WaterBlock(0b1001), false, false, true);
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($down, 0, 0, $this->level), 5, BLOCK_UPDATE_NORMAL);
|
||||
return false;
|
||||
}elseif($down instanceof LiquidBlock){
|
||||
if($down instanceof WaterBlock and ($down->getMetadata() >> 3) === 0){
|
||||
$this->level->setBlock($down, new WaterBlock(0b1000 & min($down->getMetadata(), 1)), false, false, true);
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($down, 0, 0, $this->level), 5, BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}else{
|
||||
$falling = 0;
|
||||
}
|
||||
|
||||
$newMeta = ($falling << 0x03) | $level;
|
||||
if($newMeta !== $this->meta or $newId !== $this->id){
|
||||
$this->id = $newId;
|
||||
$this->meta = $newMeta;
|
||||
$this->level->setBlock($this, $this, false, false, true);
|
||||
ServerAPI::request()->api->block->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), 10, BLOCK_UPDATE_NORMAL);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -34,8 +34,10 @@ class AirBlock extends TransparentBlock{
|
||||
$this->isTransparent = true;
|
||||
$this->isReplaceable = true;
|
||||
$this->isPlaceable = false;
|
||||
$this->inWorld = false;
|
||||
$this->hasPhysics = false;
|
||||
$this->isSolid = false;
|
||||
$this->isFullBlock = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -29,11 +29,18 @@ class BedBlock extends TransparentBlock{
|
||||
public function __construct($type = 0){
|
||||
parent::__construct(BED_BLOCK, $type, "Bed Block");
|
||||
$this->isActivable = true;
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
public function onActivate(Item $item, Player $player){
|
||||
$player->dataPacket(MC_CLIENT_MESSAGE, array(
|
||||
"message" => "This bed has been corrupted by your hands!"
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === false){
|
||||
$faces = array(
|
||||
0 => 3,
|
||||
@ -42,56 +49,48 @@ class BedBlock extends TransparentBlock{
|
||||
3 => 5,
|
||||
);
|
||||
$d = $player->entity->getDirection();
|
||||
$next = $level->getBlockFace($block, $faces[(($d + 3) % 4)]);
|
||||
$downNext = $level->getBlockFace($next, 0);
|
||||
$next = $this->getSide($faces[(($d + 3) % 4)]);
|
||||
$downNext = $this->getSide(0);
|
||||
if($next->isReplaceable === true and $downNext->isTransparent === false){
|
||||
$meta = (($d + 3) % 4) & 0x03;
|
||||
$level->setBlock($block, $this->id, $meta);
|
||||
$level->setBlock($next, $this->id, $meta | 0x08);
|
||||
$this->level->setBlock($block, BlockAPI::get($this->id, $meta));
|
||||
$this->level->setBlock($next, BlockAPI::get($this->id, $meta | 0x08));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onBreak(BlockAPI $level, Item $item, Player $player){
|
||||
if($this->inWorld === true){//Checks if the block was in the world or not. Just in case
|
||||
$blockNorth = $level->getBlockFace($this, 2); //Gets the blocks around them
|
||||
$blockSouth = $level->getBlockFace($this, 3);
|
||||
$blockEast = $level->getBlockFace($this, 5);
|
||||
$blockWest = $level->getBlockFace($this, 4);
|
||||
public function onBreak(Item $item, Player $player){
|
||||
$blockNorth = $this->getSide(2); //Gets the blocks around them
|
||||
$blockSouth = $this->getSide(3);
|
||||
$blockEast = $this->getSide(5);
|
||||
$blockWest = $this->getSide(4);
|
||||
|
||||
if(($this->meta & 0x08) === 0x08){ //This is the Top part of bed
|
||||
if($blockNorth->getID() === $this->id and $blockNorth->meta !== 0x08){ //Checks if the block ID and meta are right
|
||||
$level->setBlock($blockNorth, 0, 0);
|
||||
$this->level->setBlock($blockNorth, new AirBlock());
|
||||
}elseif($blockSouth->getID() === $this->id and $blockSouth->meta !== 0x08){
|
||||
$level->setBlock($blockSouth, 0, 0);
|
||||
$this->level->setBlock($blockSouth, new AirBlock());
|
||||
}elseif($blockEast->getID() === $this->id and $blockEast->meta !== 0x08){
|
||||
$level->setBlock($blockEast, 0, 0);
|
||||
$this->level->setBlock($blockEast, new AirBlock());
|
||||
}elseif($blockWest->getID() === $this->id and $blockWest->meta !== 0x08){
|
||||
$level->setBlock($blockWest, 0, 0);
|
||||
}else{
|
||||
return false;
|
||||
$this->level->setBlock($blockWest, new AirBlock());
|
||||
}
|
||||
return true;
|
||||
}else{ //Bottom Part of Bed
|
||||
if($blockNorth->getID() === $this->id and ($blockNorth->meta & 0x08) === 0x08){
|
||||
$level->setBlock($blockNorth, 0, 0);
|
||||
$this->level->setBlock($blockNorth, new AirBlock());
|
||||
}elseif($blockSouth->getID() === $this->id and ($blockSouth->meta & 0x08) === 0x08){
|
||||
$level->setBlock($blockSouth, 0, 0);
|
||||
$this->level->setBlock($blockSouth, new AirBlock());
|
||||
}elseif($blockEast->getID() === $this->id and ($blockEast->meta & 0x08) === 0x08){
|
||||
$level->setBlock($blockEast, 0, 0);
|
||||
$this->level->setBlock($blockEast, new AirBlock());
|
||||
}elseif($blockWest->getID() === $this->id and ($blockWest->meta & 0x08) === 0x08){
|
||||
$level->setBlock($blockWest, 0, 0);
|
||||
}else{
|
||||
return false;
|
||||
$this->level->setBlock($blockWest, new AirBlock());
|
||||
}
|
||||
}
|
||||
$this->level->setBlock($this, new AirBlock());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
|
@ -30,6 +30,30 @@ class FireBlock extends FlowableBlock{
|
||||
parent::__construct(FIRE, $meta, "Fire");
|
||||
$this->isReplaceable = true;
|
||||
$this->breakable = false;
|
||||
$this->isFullBlock = true;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array();
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
for($s = 0; $s <= 5; ++$s){
|
||||
$side = $this->getSide($s);
|
||||
if($side->getID() !== AIR and !($side instanceof LiquidBlock)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}elseif($type === BLOCK_UPDATE_RANDOM){
|
||||
if($this->getSide(0)->getID() !== NETHERRACK){
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -29,18 +29,4 @@ class TNTBlock extends SolidBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(TNT, 0, "TNT");
|
||||
}
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($this->inWorld === true){
|
||||
$player->dataPacket(MC_EXPLOSION, array(
|
||||
"x" => $this->x,
|
||||
"y" => $this->y,
|
||||
"z" => $this->z,
|
||||
"radius" => 2,
|
||||
"records" => array(),
|
||||
));
|
||||
}
|
||||
return array(
|
||||
array(TNT, 0, 1),
|
||||
);
|
||||
}
|
||||
}
|
54
src/material/block/nonfull/Cake.php
Normal file
54
src/material/block/nonfull/Cake.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class CakeBlock extends TransparentBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(CAKE_BLOCK, 0, "Cake Block");
|
||||
$this->isFullBlock = false;
|
||||
$this->isActivable = true;
|
||||
$this->meta = $meta & 0x07;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array();
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if($player->entity->getHealth() < 20){
|
||||
++$this->meta;
|
||||
$player->entity->heal(3, "cake");
|
||||
if($this->meta >= 0x06){
|
||||
$this->level->setBlock($this, new AirBlock());
|
||||
}else{
|
||||
$this->level->setBlock($this, $this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,8 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class CobwebBlock extends FlowableBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(COBWEB, 0, "Cobweb");
|
||||
$this->isFlowable = true;
|
||||
$this->isSolid = true;
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array();
|
@ -28,6 +28,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class FenceBlock extends TransparentBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(FENCE, 0, "Fence");
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
|
||||
}
|
@ -29,9 +29,13 @@ class FenceGateBlock extends TransparentBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(FENCE_GATE, $meta, "Fence Gate");
|
||||
$this->isActivable = true;
|
||||
if(($this->meta & 0x04) === 0x04){
|
||||
$this->isFullBlock = true;
|
||||
}else{
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
}
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$faces = array(
|
||||
0 => 3,
|
||||
1 => 0,
|
||||
@ -39,17 +43,15 @@ class FenceGateBlock extends TransparentBlock{
|
||||
3 => 2,
|
||||
);
|
||||
$this->meta = $faces[$player->entity->getDirection()] & 0x03;
|
||||
$level->setBlock($block, $this->id, $this->meta);
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array($this->id, 0, 1),
|
||||
);
|
||||
}
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
$faces = array(
|
||||
0 => 3,
|
||||
1 => 0,
|
||||
@ -57,7 +59,7 @@ class FenceGateBlock extends TransparentBlock{
|
||||
3 => 2,
|
||||
);
|
||||
$this->meta = ($faces[$player->entity->getDirection()] & 0x03) | ((~$this->meta) & 0x04);
|
||||
$level->setBlock($this, $this->id, $this->meta);
|
||||
$this->level->setBlock($this, $this);
|
||||
return true;
|
||||
}
|
||||
}
|
63
src/material/block/nonfull/IronDoor.php
Normal file
63
src/material/block/nonfull/IronDoor.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class IronDoorBlock extends DoorBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(IRON_DOOR_BLOCK, $meta, "Iron Door Block");
|
||||
//$this->isActivable = true;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.95;
|
||||
case 4:
|
||||
return 1.25;
|
||||
case 3:
|
||||
return 1.9;
|
||||
case 2:
|
||||
return 0.65;
|
||||
case 1:
|
||||
return 3.75;
|
||||
default:
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array(IRON_DOOR, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -35,31 +35,35 @@ class SlabBlock extends TransparentBlock{
|
||||
3 => "Cobblestone",
|
||||
4 => "Brick",
|
||||
5 => "Stone Brick",
|
||||
6 => "Nether Brick",
|
||||
7 => "Quartz",
|
||||
//6 => "Nether Brick",
|
||||
6 => "Quartz",
|
||||
);
|
||||
$this->name = (($this->meta & 0x08) === 0x08 ? "Upper ":"") . $names[$this->meta & 0x07] . " Slab";
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
$this->isFullBlock = true;
|
||||
}else{
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$this->meta = $this->meta & 0x07;
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$this->meta &= 0x07;
|
||||
if($face === 0){
|
||||
if($target->getID() === SLAB and ($target->getMetadata() & 0x08) === 0x08 and ($target->getMetadata() & 0x07) === ($this->meta & 0x07)){
|
||||
$level->setBlock($target, DOUBLE_SLAB, $this->meta & 0x07);
|
||||
$this->level->setBlock($target, BlockAPI::get(DOUBLE_SLAB, $this->meta));
|
||||
return true;
|
||||
}else{
|
||||
$this->meta |= 0x08;
|
||||
}
|
||||
}elseif($face === 1){
|
||||
if($target->getID() === SLAB and ($target->getMetadata() & 0x08) === 0 and ($target->getMetadata() & 0x07) === ($this->meta & 0x07)){
|
||||
$level->setBlock($target, DOUBLE_SLAB, $this->meta & 0x07);
|
||||
$this->level->setBlock($target, BlockAPI::get(DOUBLE_SLAB, $this->meta));
|
||||
return true;
|
||||
}
|
||||
}elseif(!$player->entity->inBlock($block->x, $block->y, $block->z)){
|
||||
}elseif(!$player->entity->inBlock($block)){
|
||||
if($block->getID() === SLAB){
|
||||
if(($block->getMetadata() & 0x07) === ($this->meta & 0x07)){
|
||||
$level->setBlock($block, DOUBLE_SLAB, $this->meta & 0x07);
|
||||
$this->level->setBlock($block, BlockAPI::get(DOUBLE_SLAB, $this->meta));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -74,14 +78,37 @@ class SlabBlock extends TransparentBlock{
|
||||
if($block->getID() === SLAB and ($target->getMetadata() & 0x07) !== ($this->meta & 0x07)){
|
||||
return false;
|
||||
}
|
||||
$level->setBlock($block, $this->id, $this->meta);
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.4;
|
||||
case 4:
|
||||
return 0.5;
|
||||
case 3:
|
||||
return 0.75;
|
||||
case 2:
|
||||
return 0.25;
|
||||
case 1:
|
||||
return 1.5;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array($this->id, $this->meta & 0x07, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
53
src/material/block/nonfull/SnowLayer.php
Normal file
53
src/material/block/nonfull/SnowLayer.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
-
|
||||
/ \
|
||||
/ \
|
||||
/ PocketMine \
|
||||
/ MP \
|
||||
|\ @shoghicp /|
|
||||
|. \ / .|
|
||||
| .. \ / .. |
|
||||
| .. | .. |
|
||||
| .. | .. |
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
\ | /
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class SnowLayerBlock extends FlowableBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(SNOW_LAYER, $meta, "Snow Layer");
|
||||
$this->isReplaceable = true;
|
||||
$this->isSolid = false;
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === AIR){ //Replace wit common break method
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isShovel() !== false){
|
||||
return array(
|
||||
array(SNOWBALL, 0, 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -30,10 +30,30 @@ class CoalOreBlock extends SolidBlock{
|
||||
parent::__construct(COAL_ORE, 0, "Coal Ore");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
case 3:
|
||||
return 1.15;
|
||||
case 2:
|
||||
return 0.4;
|
||||
case 1:
|
||||
return 2.25;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array(263, 0, 1), //Coal
|
||||
array(COAL, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
|
@ -30,10 +30,24 @@ class DiamondOreBlock extends SolidBlock{
|
||||
parent::__construct(DIAMOND_ORE, 0, "Diamond Ore");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 3){
|
||||
if($item->isPickaxe() >= 4){
|
||||
return array(
|
||||
array(264, 0, 1),
|
||||
array(DIAMOND, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
|
@ -30,4 +30,39 @@ class GlowingRedstoneOreBlock extends SolidBlock{
|
||||
parent::__construct(GLOWING_REDSTONE_ORE, 0, "Glowing Redstone Ore");
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_SCHEDULED or $type === BLOCK_UPDATE_RANDOM){
|
||||
$this->level->setBlock($this, BlockAPI::get(REDSTONE_ORE, $this->meta), false);
|
||||
return BLOCK_UPDATE_WEAK;
|
||||
}else{
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 4){
|
||||
return array(
|
||||
//array(331, 4, mt_rand(4, 5)),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -30,4 +30,27 @@ class GoldOreBlock extends SolidBlock{
|
||||
parent::__construct(GOLD_ORE, 0, "Gold Ore");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 4){
|
||||
return array(
|
||||
array(GOLD_ORE, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -30,4 +30,29 @@ class IronOreBlock extends SolidBlock{
|
||||
parent::__construct(IRON_ORE, 0, "Iron Ore");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
case 3:
|
||||
return 1.15;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 3){
|
||||
return array(
|
||||
array(IRON_ORE, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -30,10 +30,26 @@ class LapisOreBlock extends SolidBlock{
|
||||
parent::__construct(LAPIS_ORE, 0, "Lapis Ore");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
case 3:
|
||||
return 1.15;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 2){
|
||||
if($item->isPickaxe() >= 3){
|
||||
return array(
|
||||
array(351, 4, mt_rand(4, 8)),
|
||||
array(DYE, 4, mt_rand(4, 8)),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
|
@ -29,6 +29,16 @@ class RedstoneOreBlock extends SolidBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(REDSTONE_ORE, 0, "Redstone Ore");
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL or $type === BLOCK_UPDATE_TOUCH){
|
||||
$this->level->setBlock($this, BlockAPI::get(GLOWING_REDSTONE_ORE, $this->meta), false);
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
return BLOCK_UPDATE_WEAK;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 2){
|
||||
return array(
|
||||
|
@ -28,17 +28,25 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class BrownMushroomBlock extends FlowableBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(BROWN_MUSHROOM, 0, "Brown Mushroom");
|
||||
$this->isFlowable = true;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
if($down->isTransparent === false){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
return true;
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === false){
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -26,25 +26,60 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
*/
|
||||
|
||||
class CactusBlock extends TransparentBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(CACTUS, 0, "Cactus");
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(CACTUS, $meta, "Cactus");
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
if($down->getID() === SAND or $down->getID() === CACTUS){
|
||||
$block0 = $level->getBlockFace($block, 2);
|
||||
$block1 = $level->getBlockFace($block, 3);
|
||||
$block2 = $level->getBlockFace($block, 4);
|
||||
$block3 = $level->getBlockFace($block, 5);
|
||||
if($block0->isFlowable === true and $block1->isFlowable === true and $block2->isFlowable === true and $block3->isFlowable === true){
|
||||
$level->setBlock($block, $this->id, 0);
|
||||
return true;
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() !== SAND and $down->getID() !== CACTUS){ //Replace wit common break method
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id));
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === BLOCK_UPDATE_RANDOM){
|
||||
if($this->getSide(0)->getID() !== CACTUS){
|
||||
if($this->meta == 0x0F){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->level->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
if($b->getID() === AIR){
|
||||
$this->level->setBlock($b, new CactusBlock());
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
$this->level->setBlock($this, $this);
|
||||
}else{
|
||||
++$this->meta;
|
||||
$this->level->setBlock($this, $this);
|
||||
}
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === SAND or $down->getID() === CACTUS){
|
||||
$block0 = $this->getSide(2);
|
||||
$block1 = $this->getSide(3);
|
||||
$block2 = $this->getSide(4);
|
||||
$block3 = $this->getSide(5);
|
||||
if($block0->isTransparent === true and $block1->isTransparent === true and $block2->isTransparent === true and $block3->isTransparent === true){
|
||||
$this->level->setBlock($this, $this);
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array($this->id, 0, 1),
|
||||
);
|
||||
}
|
||||
}
|
@ -28,15 +28,24 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class CyanFlowerBlock extends FlowableBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(CYAN_FLOWER, 0, "Cyan Flower");
|
||||
$this->isFlowable = true;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === 2 or $down->getID() === 3 or $down->getID() === 60){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -28,15 +28,24 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class DandelionBlock extends FlowableBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(DANDELION, 0, "Dandelion");
|
||||
$this->isFlowable = true;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === 2 or $down->getID() === 3 or $down->getID() === 60){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -28,8 +28,17 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class DeadBushBlock extends FlowableBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(DEAD_BUSH, 0, "Dead Bush");
|
||||
$this->isFlowable = true;
|
||||
$this->isReplaceable = true;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -25,25 +25,60 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class MelonStemBlock extends TransparentBlock{
|
||||
class MelonStemBlock extends FlowableBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(MELON_STEM, $meta, "Melon Stem");
|
||||
$this->isActivable = true;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === FARMLAND){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
$this->level->setBlock($block, $this);
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem(MELON_SEEDS, 0, mt_rand(0, 2)));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->level->setBlock($this, $this);
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b->getID() === MELON_BLOCK){
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
$side = $this->getSide(mt_rand(2,5));
|
||||
$d = $side->getSide(0);
|
||||
if($side->getID() === AIR and ($d->getID() === FARMLAND or $d->getID() === GRASS or $d->getID() === DIRT)){
|
||||
$this->level->setBlock($side, new MelonBlock());
|
||||
}
|
||||
}
|
||||
}
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if($item->getID() === DYE and $item->getMetadata() === 0x0F){ //Bonemeal
|
||||
$level->setBlock($this, $this->id, 0x07);
|
||||
$this->meta = 0x07;
|
||||
$this->level->setBlock($this, $this);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -28,17 +28,25 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class RedMushroomBlock extends FlowableBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(RED_MUSHROOM, 0, "Red Mushroom");
|
||||
$this->isFlowable = true;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
if($down->isTransparent === false){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
return true;
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === false){
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class SaplingBlock extends TransparentBlock{
|
||||
class SaplingBlock extends FlowableBlock{
|
||||
const OAK = 0;
|
||||
const SPRUCE = 1;
|
||||
const BIRCH = 2;
|
||||
@ -34,7 +34,6 @@ class SaplingBlock extends TransparentBlock{
|
||||
public function __construct($meta = Sapling::OAK){
|
||||
parent::__construct(SAPLING, $meta, "Sapling");
|
||||
$this->isActivable = true;
|
||||
$this->isFlowable = true;
|
||||
$names = array(
|
||||
0 => "Oak Sapling",
|
||||
1 => "Spruce Sapling",
|
||||
@ -43,37 +42,45 @@ class SaplingBlock extends TransparentBlock{
|
||||
$this->name = $names[$this->meta & 0x03];
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === GRASS or $down->getID() === DIRT or $down->getID() === FARMLAND){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
$this->level->setBlock($block, $this);
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if($item->getID() === DYE and $item->getMetadata() === 0x0F){ //Bonemeal
|
||||
TreeObject::growTree($level, $this);
|
||||
TreeObject::growTree($this->level, $this, new Random(), $this->meta & 0x03);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate(BlockAPI $level, $type){
|
||||
if($this->inWorld !== true){
|
||||
return false;
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem($this->id));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
if($type === BLOCK_UPDATE_RANDOM and mt_rand(0,2) === 0){ //Growth
|
||||
}elseif($type === BLOCK_UPDATE_RANDOM){ //Growth
|
||||
if(mt_rand(1,7) === 1){
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
TreeObject::growTree($level, $this);
|
||||
TreeObject::growTree($this->level, $this, new Random(), $this->meta & 0x03);
|
||||
}else{
|
||||
$this->meta |= 0x08;
|
||||
$this->level->setBlock($this->x, $this->y, $this->z, $this->id, $this->meta);
|
||||
$this->level->setBlock($this, $this);
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}else{
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class SugarcaneBlock extends TransparentBlock{
|
||||
public function __construct(){
|
||||
parent::__construct(SUGARCANE_BLOCK, 0, "Sugarcane");
|
||||
class SugarcaneBlock extends FlowableBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(SUGARCANE_BLOCK, $meta, "Sugarcane");
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
@ -36,35 +36,55 @@ class SugarcaneBlock extends TransparentBlock{
|
||||
);
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
if($down->getID() === SUGARCANE_BLOCK){
|
||||
$level->setBlock($block, $this->id, 0);
|
||||
return true;
|
||||
}elseif($down->getID() === GRASS or $down->getID() === DIRT or $down->getID() === SAND){
|
||||
$block0 = $level->getBlockFace($down, 2);
|
||||
$block1 = $level->getBlockFace($down, 3);
|
||||
$block2 = $level->getBlockFace($down, 4);
|
||||
$block3 = $level->getBlockFace($down, 5);
|
||||
/*$block4 = $level->getBlockFace($block, 2);
|
||||
$block5 = $level->getBlockFace($block, 3);
|
||||
$block6 = $level->getBlockFace($block, 4);
|
||||
$block7 = $level->getBlockFace($block, 5);*/
|
||||
if($block0->getID() === WATER or $block0->getID() === STILL_WATER
|
||||
or $block1->getID() === WATER or $block1->getID() === STILL_WATER
|
||||
or $block2->getID() === WATER or $block2->getID() === STILL_WATER
|
||||
or $block3->getID() === WATER or $block3->getID() === STILL_WATER
|
||||
/*or $block4->getID() === WATER or $block4->getID() === STILL_WATER
|
||||
or $block5->getID() === WATER or $block5->getID() === STILL_WATER
|
||||
or $block6->getID() === WATER or $block6->getID() === STILL_WATER
|
||||
or $block7->getID() === WATER or $block7->getID() === STILL_WATER*/){
|
||||
$level->setBlock($block, $this->id, 0);
|
||||
return true;
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === true and $down->getID() !== SUGARCANE_BLOCK){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem(SUGARCANE));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === BLOCK_UPDATE_RANDOM){
|
||||
if($this->getSide(0)->getID() !== SUGARCANE_BLOCK){
|
||||
if($this->meta === 0x0F){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->level->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
if($b->getID() === AIR){
|
||||
$this->level->setBlock($b, new SugarcaneBlock());
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
$this->level->setBlock($this, $this);
|
||||
}else{
|
||||
++$this->meta;
|
||||
$this->level->setBlock($this, $this);
|
||||
}
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === SUGARCANE_BLOCK){
|
||||
$this->level->setBlock($block, new SugarcaneBlock());
|
||||
return true;
|
||||
}elseif($down->getID() === GRASS or $down->getID() === DIRT or $down->getID() === SAND){
|
||||
$block0 = $down->getSide(2);
|
||||
$block1 = $down->getSide(3);
|
||||
$block2 = $down->getSide(4);
|
||||
$block3 = $down->getSide(5);
|
||||
if(($block0 instanceof WaterBlock)
|
||||
or ($block1 instanceof WaterBlock)
|
||||
or ($block2 instanceof WaterBlock)
|
||||
or ($block3 instanceof WaterBlock)){
|
||||
$this->level->setBlock($block, new SugarcaneBlock());
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -28,7 +28,6 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
class TallGrassBlock extends FlowableBlock{
|
||||
public function __construct($meta = 1){
|
||||
parent::__construct(TALL_GRASS, $meta, "Tall Grass");
|
||||
$this->isFlowable = true;
|
||||
$this->isReplaceable = true;
|
||||
$names = array(
|
||||
0 => "Dead Shrub",
|
||||
@ -38,10 +37,20 @@ class TallGrassBlock extends FlowableBlock{
|
||||
$this->name = $names[$this->meta & 0x03];
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
$drops = array();
|
||||
if(mt_rand(1,10) === 1){//Seeds
|
||||
$drops[] = array(295, 0, 1);
|
||||
$drops[] = array(WHEAT_SEEDS, 0, 1);
|
||||
}
|
||||
return $drops;
|
||||
}
|
||||
|
@ -31,25 +31,49 @@ class WheatBlock extends FlowableBlock{
|
||||
$this->isActivable = true;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
$down = $level->getBlockFace($block, 0);
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === FARMLAND){
|
||||
$level->setBlock($block, $this->id, $this->getMetadata());
|
||||
$this->level->setBlock($block, $this);
|
||||
$this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if($item->getID() === DYE and $item->getMetadata() === 0x0F){ //Bonemeal
|
||||
$level->setBlock($this, $this->id, 0x07);
|
||||
$this->meta = 0x07;
|
||||
$this->level->setBlock($this, $this);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace wit common break method
|
||||
ServerAPI::request()->api->entity->drop($this, BlockAPI::getItem(WHEAT_SEEDS, 0, 1));
|
||||
$this->level->setBlock($this, new AirBlock(), false);
|
||||
return BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->level->setBlock($this, $this);
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}else{
|
||||
return BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
$drops = array();
|
||||
if($this->meta >= 0x07){
|
||||
|
@ -32,7 +32,7 @@ class BedrockBlock extends SolidBlock{
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item, Player $player){
|
||||
if($player->gamemode === CREATIVE){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -30,4 +30,33 @@ class BricksBlock extends SolidBlock{
|
||||
parent::__construct(BRICKS_BLOCK, 0, "Bricks");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.4;
|
||||
case 4:
|
||||
return 0.5;
|
||||
case 3:
|
||||
return 0.75;
|
||||
case 2:
|
||||
return 0.25;
|
||||
case 1:
|
||||
return 1.5;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array(BRICKS_BLOCK, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -25,33 +25,109 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class BurningFurnaceBlock extends SolidBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(BURNING_FURNACE, $meta, "Burning Furnace");
|
||||
$this->isActivable = true;
|
||||
}
|
||||
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
$faces = array(
|
||||
0 => 4,
|
||||
1 => 2,
|
||||
2 => 5,
|
||||
3 => 3,
|
||||
);
|
||||
$level->setBlock($block, $this->id, $faces[$player->entity->getDirection()]);
|
||||
$this->meta = $faces[$player->entity->getDirection()];
|
||||
$this->level->setBlock($block, $this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
public function onBreak(Item $item, Player $player){
|
||||
$this->level->setBlock($this, new AirBlock(), true, true);
|
||||
return true;
|
||||
}
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array(FURNACE, 0, 1),
|
||||
);
|
||||
|
||||
public function onActivate(Item $item, Player $player){
|
||||
|
||||
$server = ServerAPI::request();
|
||||
$t = $server->api->tile->get($this);
|
||||
$furnace = false;
|
||||
if($t !== false){
|
||||
$furnace = $t;
|
||||
}else{
|
||||
return array();
|
||||
$furnace = $server->api->tile->add($this->level, TILE_FURNACE, $this->x, $this->y, $this->z, array(
|
||||
"Items" => array(),
|
||||
"id" => TILE_FURNACE,
|
||||
"x" => $this->x,
|
||||
"y" => $this->y,
|
||||
"z" => $this->z
|
||||
));
|
||||
}
|
||||
|
||||
if($furnace->class !== TILE_FURNACE or ($player->gamemode & 0x01) === 0x01){
|
||||
return true;
|
||||
}
|
||||
$player->windowCnt++;
|
||||
$player->windowCnt = $id = max(2, $player->windowCnt % 16);
|
||||
$player->windows[$id] = $furnace;
|
||||
$player->dataPacket(MC_CONTAINER_OPEN, array(
|
||||
"windowid" => $id,
|
||||
"type" => WINDOW_FURNACE,
|
||||
"slots" => FURNACE_SLOTS,
|
||||
"title" => "Furnace",
|
||||
));
|
||||
$slots = array();
|
||||
for($s = 0; $s < FURNACE_SLOTS; ++$s){
|
||||
$slot = $furnace->getSlot($s);
|
||||
if($slot->getID() > 0 and $slot->count > 0){
|
||||
$slots[] = $slot;
|
||||
}else{
|
||||
$slots[] = BlockAPI::getItem(AIR, 0, 0);
|
||||
}
|
||||
}
|
||||
$player->dataPacket(MC_CONTAINER_SET_CONTENT, array(
|
||||
"windowid" => $id,
|
||||
"count" => count($slots),
|
||||
"slots" => $slots
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.7;
|
||||
case 4:
|
||||
return 0.9;
|
||||
case 3:
|
||||
return 1.35;
|
||||
case 2:
|
||||
return 0.45;
|
||||
case 1:
|
||||
return 2.65;
|
||||
default:
|
||||
return 17.5;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
$drops = array();
|
||||
if($item->isPickaxe() >= 1){
|
||||
$drops[] = array(FURNACE, 0, 1);
|
||||
}
|
||||
$t = ServerAPI::request()->api->tile->get($this);
|
||||
if($t !== false and $t->class === TILE_FURNACE){
|
||||
for($s = 0; $s < FURNACE_SLOTS; ++$s){
|
||||
$slot = $t->getSlot($s);
|
||||
if($slot->getID() > AIR and $slot->count > 0){
|
||||
$drops[] = array($slot->getID(), $slot->getMetadata(), $slot->count);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $drops;
|
||||
}
|
||||
}
|
@ -25,22 +25,50 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
class ChestBlock extends SolidBlock{
|
||||
class ChestBlock extends TransparentBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(CHEST, $meta, "Chest");
|
||||
$this->isActivable = true;
|
||||
}
|
||||
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
if($block->inWorld === true){
|
||||
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
|
||||
|
||||
$faces = array(
|
||||
0 => 4,
|
||||
1 => 2,
|
||||
2 => 5,
|
||||
3 => 3,
|
||||
);
|
||||
$level->setBlock($block, $this->id, $faces[$player->entity->getDirection()]);
|
||||
$facesc = array(
|
||||
2 => 4,
|
||||
3 => 2,
|
||||
4 => 5,
|
||||
5 => 3,
|
||||
);
|
||||
$chest = false;
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$c = $this->getSide($side);
|
||||
if($c instanceof ChestBlock){
|
||||
/*if($chest !== false){ //No chests in the middle
|
||||
return false;
|
||||
}*/
|
||||
$chest = array($side, $c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($chest !== false and ($chest[1]->getSide($chest[0]) instanceof ChestBlock)){ //Already double chest
|
||||
return false;
|
||||
}
|
||||
|
||||
if($chest !== false){
|
||||
$this->meta = $facesc[$chest[0]];
|
||||
$this->level->setBlock($chest[1], new ChestBlock($this->meta));
|
||||
}else{
|
||||
$this->meta = $faces[$player->entity->getDirection()];
|
||||
}
|
||||
$this->level->setBlock($block, $this);
|
||||
$server = ServerAPI::request();
|
||||
$server->api->tileentity->add(TILE_CHEST, $this->x, $this->y, $this->z, array(
|
||||
$server->api->tile->add($this->level, TILE_CHEST, $this->x, $this->y, $this->z, array(
|
||||
"Items" => array(),
|
||||
"id" => TILE_CHEST,
|
||||
"x" => $this->x,
|
||||
@ -49,42 +77,25 @@ class ChestBlock extends SolidBlock{
|
||||
));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onBreak(BlockAPI $level, Item $item, Player $player){
|
||||
if($this->inWorld === true){
|
||||
$server = ServerAPI::request();
|
||||
$t = $server->api->tileentity->get($this);
|
||||
if($t !== false){
|
||||
if(is_array($t)){
|
||||
foreach($t as $ts){
|
||||
if($ts->class === TILE_CHEST){
|
||||
$server->api->tileentity->remove($ts->id);
|
||||
}
|
||||
}
|
||||
}elseif($t->class === TILE_CHEST){
|
||||
$server->api->tileentity->remove($t->id);
|
||||
}
|
||||
}
|
||||
$level->setBlock($this, 0, 0);
|
||||
public function onBreak(Item $item, Player $player){
|
||||
$this->level->setBlock($this, new AirBlock(), true, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
public function onActivate(Item $item, Player $player){
|
||||
$top = $this->getSide(1);
|
||||
if($top->isTransparent !== true){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
$server = ServerAPI::request();
|
||||
$t = $server->api->tileentity->get($this);
|
||||
$t = $server->api->tile->get($this);
|
||||
$chest = false;
|
||||
if($t !== false){
|
||||
if(is_array($t)){
|
||||
$chest = array_shift($t);
|
||||
}else{
|
||||
$chest = $t;
|
||||
}
|
||||
}else{
|
||||
$chest = $server->api->tileentity->add(TILE_CHEST, $this->x, $this->y, $this->z, array(
|
||||
$chest = $server->api->tile->add($this->level, TILE_CHEST, $this->x, $this->y, $this->z, array(
|
||||
"Items" => array(),
|
||||
"id" => TILE_CHEST,
|
||||
"x" => $this->x,
|
||||
@ -93,36 +104,56 @@ class ChestBlock extends SolidBlock{
|
||||
));
|
||||
}
|
||||
|
||||
if($chest->class !== TILE_CHEST){
|
||||
return false;
|
||||
if($chest->class !== TILE_CHEST or ($player->gamemode & 0x01) === 0x01){
|
||||
return true;
|
||||
}
|
||||
$id = $player->windowCnt = $player->windowCnt++ % 255;
|
||||
$player->windowCnt++;
|
||||
$player->windowCnt = $id = max(2, $player->windowCnt % 16);
|
||||
$player->windows[$id] = $chest;
|
||||
$player->dataPacket(MC_CONTAINER_OPEN, array(
|
||||
"windowid" => $id,
|
||||
"type" => WINDOW_CHEST,
|
||||
"slots" => 27,
|
||||
"slots" => CHEST_SLOTS,
|
||||
"title" => "Chest",
|
||||
));
|
||||
foreach($chest->data["Items"] as $slot){
|
||||
if($slot["Slot"] < 0 or $slot["Slot"] >= 27){
|
||||
continue;
|
||||
}
|
||||
$player->dataPacket(MC_CONTAINER_SET_SLOT, array(
|
||||
"windowid" => $id,
|
||||
"slot" => $slot["Slot"],
|
||||
"block" => $slot["id"],
|
||||
"stack" => $slot["Count"],
|
||||
"meta" => $slot["Damage"],
|
||||
$server->api->player->broadcastPacket($server->api->player->getAll($this->level), MC_TILE_EVENT, array(
|
||||
"x" => $this->x,
|
||||
"y" => $this->y,
|
||||
"z" => $this->z,
|
||||
"case1" => 1,
|
||||
"case2" => 2,
|
||||
));
|
||||
$slots = array();
|
||||
for($s = 0; $s < CHEST_SLOTS; ++$s){
|
||||
$slot = $chest->getSlot($s);
|
||||
if($slot->getID() > AIR and $slot->count > 0){
|
||||
$slots[] = $slot;
|
||||
}else{
|
||||
$slots[] = BlockAPI::getItem(AIR, 0, 0);
|
||||
}
|
||||
}
|
||||
$player->dataPacket(MC_CONTAINER_SET_CONTENT, array(
|
||||
"windowid" => $id,
|
||||
"count" => count($slots),
|
||||
"slots" => $slots
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
$drops = array(
|
||||
array($this->id, 0, 1),
|
||||
);
|
||||
$t = ServerAPI::request()->api->tile->get($this);
|
||||
if($t !== false and $t->class === TILE_CHEST){
|
||||
for($s = 0; $s < CHEST_SLOTS; ++$s){
|
||||
$slot = $t->getSlot($s);
|
||||
if($slot->getID() > AIR and $slot->count > 0){
|
||||
$drops[] = array($slot->getID(), $slot->getMetadata(), $slot->count);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $drops;
|
||||
}
|
||||
}
|
@ -30,4 +30,9 @@ class ClayBlock extends SolidBlock{
|
||||
parent::__construct(CLAY_BLOCK, 0, "Clay Block");
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array(CLAY, 0, 4),
|
||||
);
|
||||
}
|
||||
}
|
@ -30,4 +30,33 @@ class CobblestoneBlock extends SolidBlock{
|
||||
parent::__construct(COBBLESTONE, 0, "Cobblestone");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.4;
|
||||
case 4:
|
||||
return 0.5;
|
||||
case 3:
|
||||
return 0.75;
|
||||
case 2:
|
||||
return 0.25;
|
||||
case 1:
|
||||
return 1.5;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array(COBBLESTONE, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -30,4 +30,27 @@ class DiamondBlock extends SolidBlock{
|
||||
parent::__construct(DIAMOND_BLOCK, 0, "Diamond Block");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.95;
|
||||
case 4:
|
||||
return 1.25;
|
||||
default:
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 4){
|
||||
return array(
|
||||
array(DIAMOND_BLOCK, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -31,9 +31,12 @@ class DirtBlock extends SolidBlock{
|
||||
$this->isActivable = true;
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if($item->isHoe()){
|
||||
$level->setBlock($this, FARMLAND, 0);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->useOn($this);
|
||||
}
|
||||
$this->level->setBlock($this, BlockAPI::get(FARMLAND, 0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -40,10 +40,35 @@ class DoubleSlabBlock extends SolidBlock{
|
||||
);
|
||||
$this->name = "Double " . $names[$this->meta & 0x07] . " Slab";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.4;
|
||||
case 4:
|
||||
return 0.5;
|
||||
case 3:
|
||||
return 0.75;
|
||||
case 2:
|
||||
return 0.25;
|
||||
case 1:
|
||||
return 1.5;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 1){
|
||||
return array(
|
||||
array(SLAB, $this->meta & 0x07, 2),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,11 @@ the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
*/
|
||||
|
||||
/***REM_START***/
|
||||
require_once("BurningFurnace.php");
|
||||
/***REM_END***/
|
||||
|
||||
|
||||
class FurnaceBlock extends BurningFurnaceBlock{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct($meta);
|
||||
@ -32,5 +37,4 @@ class FurnaceBlock extends BurningFurnaceBlock{
|
||||
$this->name = "Furnace";
|
||||
$this->isActivable = true;
|
||||
}
|
||||
|
||||
}
|
@ -30,4 +30,9 @@ class GlowstoneBlock extends SolidBlock{
|
||||
parent::__construct(GLOWSTONE_BLOCK, 0, "Glowstone");
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
return array(
|
||||
array(GLOWSTONE_DUST, 0, mt_rand(2, 4)),
|
||||
);
|
||||
}
|
||||
}
|
@ -30,4 +30,27 @@ class GoldBlock extends SolidBlock{
|
||||
parent::__construct(GOLD_BLOCK, 0, "Gold Block");
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item, Player $player){
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
return 0.20;
|
||||
}
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.6;
|
||||
case 4:
|
||||
return 0.75;
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if($item->isPickaxe() >= 4){
|
||||
return array(
|
||||
array(GOLD_BLOCK, 0, 1),
|
||||
);
|
||||
}else{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@ -36,30 +36,18 @@ class GrassBlock extends SolidBlock{
|
||||
);
|
||||
}
|
||||
|
||||
public function onActivate(BlockAPI $level, Item $item, Player $player){
|
||||
public function onActivate(Item $item, Player $player){
|
||||
if($item->getID() === DYE and $item->getMetadata() === 0x0F){
|
||||
for($c = 0; $c < 15; ++$c){
|
||||
$x = mt_rand($this->x - 2, $this->x + 2);
|
||||
$z = mt_rand($this->z - 2, $this->z + 2);
|
||||
$b = $level->getBlock(new Vector3($x, $this->y + 1, $z));
|
||||
$d = $level->getBlock(new Vector3($x, $this->y, $z));
|
||||
if($b->getID() === AIR and $d->getID() === GRASS){
|
||||
$arr = array(
|
||||
array(DANDELION, 0),
|
||||
array(CYAN_FLOWER, 0),
|
||||
array(TALL_GRASS, 1),
|
||||
array(TALL_GRASS, 1),
|
||||
array(TALL_GRASS, 1),
|
||||
array(TALL_GRASS, 1),
|
||||
array(AIR, 0),
|
||||
);
|
||||
$t = $arr[mt_rand(0, count($arr) - 1)];
|
||||
$level->setBlock($b, $t[0], $t[1]);
|
||||
}
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
TallGrassObject::growGrass($this->level, $this, new Random());
|
||||
return true;
|
||||
}elseif($item->isHoe()){
|
||||
$level->setBlock($this, FARMLAND, 0);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->useOn($this);
|
||||
}
|
||||
$this->level->setBlock($this, new FarmlandBlock());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -30,4 +30,15 @@ class GravelBlock extends FallableBlock{
|
||||
parent::__construct(GRAVEL, 0, "Gravel");
|
||||
}
|
||||
|
||||
public function getDrops(Item $item, Player $player){
|
||||
if(mt_rand(1,10) === 1){
|
||||
return array(
|
||||
array(FLINT, 0, 1),
|
||||
);
|
||||
}
|
||||
return array(
|
||||
array(GRAVEL, 0, 1),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user