Compare commits

..

753 Commits

Author SHA1 Message Date
ea17ff9d9b Alpha_1.3.5 release 2013-08-20 12:25:49 +02:00
1b72ef8827 Better Player:close() cleanup 2013-08-20 11:31:37 +02:00
a34595292d Allow armor replacing (changing armor to another armor) 2013-08-20 11:23:55 +02:00
e42314ade7 Fixed block durability 2013-08-20 04:53:22 +02:00
5683dca9f6 Fixed crash 2013-08-20 02:57:37 +02:00
b5c935559f Alpha_1.3.4 2013-08-20 02:32:47 +02:00
7a37b0e4bf Quartz slabs 2013-08-20 02:24:15 +02:00
19b3ac4a99 Fixed disconnection 2013-08-20 02:15:18 +02:00
bf1b00f0e6 Correct teleporting with the new player list handling 2013-08-20 02:06:14 +02:00
7102787aa9 Added correct handling of RemovePlayer packet for in-game player list 2013-08-20 01:42:45 +02:00
d26d657b95 Fixed /difficulty 2013-08-20 01:16:24 +02:00
3374bbcc9e Chest animations for everyone! Woo! 2013-08-20 00:26:37 +02:00
8d408996f4 Double chest checks, chest opening broadcast 2013-08-19 21:05:09 +02:00
68e78ba40b Implemented basic tool durability 2013-08-19 17:37:08 +02:00
a7b739d17f Fixed hotbar reset bugs in block placement 2013-08-19 17:04:02 +02:00
78c242eac4 Fixed armor hotbar reset bug 2013-08-19 16:51:40 +02:00
7e6758fb60 Alpha_1.3.4dev 2013-08-18 21:32:26 +02:00
39658ef63f Automatic recovery of corrupted maps 2013-08-18 21:31:47 +02:00
4f1ce9adee Revert "Merge pull request #682 from Humerus/patch-1"
This reverts commit 04c641b79b, reversing
changes made to ba9b800eff.

Revert
2013-08-18 13:17:01 +02:00
87a67804c4 Merge pull request #677 from Humerus/master
Enabled autosave via an option in server.properties.
2013-08-18 04:11:53 -07:00
04c641b79b Merge pull request #682 from Humerus/patch-1
I'm bored x2.
2013-08-09 21:22:01 -07:00
9c9939440f I'm bored x2. 2013-08-09 22:57:32 -04:00
ba9b800eff Merge pull request #599 from MinecrafterJPN/master
Fixed player.block.activate
2013-08-09 04:44:10 -07:00
62b589295e Enabled autosave 2013-08-08 23:02:38 -04:00
b6d86c287c Update ServerAPI.php 2013-08-08 22:58:32 -04:00
792a4bd98e Changed IRC Link 2013-08-02 13:01:47 +02:00
28790e0fb3 Changed chcp to normal Unicode 2013-08-01 19:32:17 +02:00
b77e7dd05c Added weird water 2013-08-01 19:31:39 +02:00
4c73629b9e Object check - Fixes #537 2013-07-31 22:38:17 -05:00
330e06b892 Players can no longer be given air (causes client crash) through /give.
Fixes #567.
2013-07-31 22:08:34 -05:00
f3f6828699 Object check on getting distance for PvP attacks
Fixes #586, although I'm not entirely sure what's causing the object to be invalid in the first case, so this is a temporal fix.
2013-07-31 21:45:23 -05:00
c1e1f5195b Fix for players connecting with a blank username field
Fix for players connecting with a blank username field (#636).
2013-07-31 16:45:56 -05:00
a60d41d489 Merge pull request #634 from williamtdr/patch-1
Fix for fly kick when player is standing on Fence
2013-07-31 14:37:04 -07:00
5975bd9d32 Fix for fly kick when player is standing on Fence
Fix for Issue #631 (Player kicked for flying when standing on fence).
2013-07-31 00:44:41 -05:00
e67b583cbe Added Player::realmsData for future checking 2013-07-23 19:02:32 +02:00
4755dee47d Fixed player count bug 2013-07-23 17:33:37 +02:00
fd5d981aa5 Revert "Better Command Permissions Check"
This reverts commit b42222c461.
2013-07-23 16:13:59 +02:00
a93b2cf954 Revert "Minor fix to command.check"
This reverts commit ed9eadd1a0.
2013-07-23 16:13:51 +02:00
16e65560a8 Revert "Update Deprecation.php"
This reverts commit 08000257fb.
2013-07-23 16:13:44 +02:00
32d658122b Fixed player.block.activate 2013-07-22 21:59:29 +09:00
1cf2741f96 Moved chat disconnect broadcast 2013-07-21 23:42:07 +02:00
47c934cee2 Reordered instructions 2013-07-21 23:36:14 +02:00
3606c392f2 Disallow packet receival on Player disconnect 2013-07-21 23:35:03 +02:00
6d4465eb67 Fixed High CPU Usage. setPosition now uses prepared statements. 2013-07-15 21:44:47 +09:00
08000257fb Update Deprecation.php 2013-07-15 12:50:03 +09:30
ed9eadd1a0 Minor fix to command.check 2013-07-15 12:15:23 +09:00
b42222c461 Better Command Permissions Check 2013-07-15 12:08:28 +09:00
635cd677eb minor armor api fix. 2013-07-14 17:50:14 +09:30
56f500d520 Merge branch 'master' of https://github.com/PocketMine/PocketMine-MP 2013-07-13 23:59:39 +02:00
3202678594 Compiler changes 2013-07-13 23:59:23 +02:00
a68676a247 Added setArmor and getArmor 2013-07-13 18:18:10 +09:00
7efed17b74 Possible fix for armor crash 2013-07-04 23:33:56 +02:00
b776d9d5fc Fixed ghost armor 2013-07-04 22:01:28 +02:00
5237867319 Fixed Armor AIR crash 2013-07-04 21:48:35 +02:00
402fc087ca Armor fix 2013-07-04 20:40:35 +02:00
1727e18e31 Updated for Minecraft: PE 0.7.2 2013-07-04 20:24:13 +02:00
03b4e40bf4 Ooops! 2013-07-03 18:12:22 +02:00
8f1c34fdc5 Added whitelist to Query 2013-07-03 18:08:53 +02:00
84bb66357e Cast floats as integers on Level::getBlock() and Level::setBlock() 2013-07-03 10:59:32 +02:00
c00bfe3908 Fixed async thread get 2013-06-25 01:22:02 +02:00
3fb99e118c Added item save check 2013-06-20 22:10:39 +02:00
1d2de1f038 Fixed DEFLATEPacket notification 2013-06-17 10:03:20 +02:00
d177af3297 Fixed #410 2013-06-17 09:29:54 +02:00
8dcdf55264 Frequent memory checks 2013-06-17 09:27:17 +02:00
5a168836c5 Fixed setting the difficulty via command 2013-06-17 03:29:44 +02:00
ce1e95195b Alpha_1.3.3dev 2013-06-17 02:53:29 +02:00
cf5e2f63db Fixed pthreads infinite loop when string length was <= 0 2013-06-17 01:07:58 +02:00
d4c4f8817d Pushed fix for #391 2013-06-17 00:44:18 +02:00
b6a1d42870 Preparing Alpha_1.3.2 fix update 2013-06-16 17:51:31 +02:00
84a5f0fce5 Tweaked block break times #254 2013-06-16 17:33:24 +02:00
c136eb2b2e Fixed #400 2013-06-16 17:31:55 +02:00
d0a021de73 Improved #401 2013-06-16 17:28:12 +02:00
155c918bb8 Fixed Leaf Decay loops causing Lag Spikes, fixed #391 [gh#391] 2013-06-16 17:18:15 +02:00
19d0c70669 Added simple Matrices 2013-06-16 14:34:06 +02:00
02721c09a4 Possible fix for #391 2013-06-15 21:24:06 +02:00
204a4ce831 Updated PHP version 2013-06-14 14:43:43 +02:00
a118e626c2 Changed Languages
Other people that checks issues might not understand Spanish or Korean.
So, the people that use other languages might do it, as an exception,
but we won't add it to the Guidelines. Doing that would encourage it.
2013-06-14 13:49:35 +02:00
01d5612ed8 CONTRIBUTING Better Reading 2013-06-14 19:11:04 +09:30
59aa317546 Update CONTRIBUTING.md with Additional Language Issue stuff.
We need to consider non-English speakers as well.
2013-06-14 19:10:28 +09:30
4c9cbaf1ee Possible fix for #391 2013-06-14 02:56:29 +02:00
18562317c3 Added Packet Count check 2013-06-14 00:21:43 +02:00
f51630c572 Fixes to DEFLATE 2013-06-13 19:53:04 +02:00
847590645d Added CONTRIBUTING.md 2013-06-13 16:46:04 +02:00
fbf22cec39 Fixed #386 Adding items use the correct item max stack size [gh#386] 2013-06-13 10:44:00 +02:00
0dd3d4a457 Alpha_1.3.2dev 2013-06-12 22:48:31 +02:00
f521d16ce3 Alpha_1.3.1 release 2013-06-12 22:18:00 +02:00
72ec318481 Fixed crafting inside a chest 2013-06-12 22:01:42 +02:00
99554caa69 Added some type checks 2013-06-12 20:46:23 +02:00
bfffa35246 Async checks each second 2013-06-12 19:50:37 +02:00
09a388f8de Fixed type again 2013-06-12 19:41:03 +02:00
a7149ad9ef Fixed field type 2013-06-12 19:40:09 +02:00
471de2d1c5 Changed domain 2013-06-12 19:38:34 +02:00
aa7d9b5e05 Added full async operations in a separate Thread 2013-06-12 19:38:11 +02:00
2e23ce8beb Ban API fly fixed 2013-06-12 17:11:37 +02:00
e4871ee0c4 Faster packet broadcast 2013-06-12 17:10:10 +02:00
86469a1031 Fix 2013-06-12 16:43:29 +02:00
533c179622 Added Client Lag detection 2013-06-12 16:25:11 +02:00
4321a03935 Mini fix 2013-06-12 16:11:15 +02:00
68f0a91d56 Fixed Chunk max upload 2013-06-12 16:10:50 +02:00
5e231c846c Chat checks 2013-06-12 14:55:38 +02:00
7d3992bcc2 Improved some events 2013-06-12 14:51:36 +02:00
c83d4d955f Improved Player::blocked 2013-06-12 13:46:44 +02:00
ff7fa066a5 Entities are now updated on block updates 2013-06-12 12:20:56 +02:00
9619ebc2af Fixed lag issues when breaking blocks 2013-06-12 12:13:51 +02:00
0a4beaf051 Fix 2013-06-12 00:07:20 +02:00
2957f35194 Fixed incorrect player count at login 2013-06-12 00:06:09 +02:00
5afd26b1b6 Reduced stats server timeout 2013-06-11 23:08:07 +02:00
152ebcbc17 Fixed Memory Stats collection 2013-06-11 18:55:08 +02:00
73c155090c Fixed UP/Down speed 2013-06-11 18:50:47 +02:00
89cb879f1f Fixed pigs dropping leather 2013-06-11 17:42:47 +02:00
a45858ad94 Fixed #373 2013-06-11 17:01:51 +02:00
c8e157156e Added bandwidth usage measurement to Window Status 2013-06-11 11:00:02 +02:00
6563169527 Removed libedit support temporally 2013-06-11 10:43:50 +02:00
7e67f50da5 Creative players pickup item sound 2013-06-11 00:55:48 +02:00
393b57c535 Few level generation changes 2013-06-10 17:35:11 +02:00
bda5e62788 Fixed syntax 2013-06-10 17:13:34 +02:00
579175b3bc Ore Generation 2013-06-10 17:11:04 +02:00
808f5473d0 Added more Vector math 2013-06-10 17:10:49 +02:00
4284211bd1 Change 2013-06-10 17:10:40 +02:00
33733cd608 New API version 2013-06-10 17:10:18 +02:00
1e14485444 Increased support Y radius 2013-06-10 15:47:53 +02:00
c42fd790ff Fixed error 2013-06-10 15:36:45 +02:00
2ef1f0c9d0 Fixed #364 added despawn timer for arrows [gh#364] 2013-06-10 10:37:33 +02:00
abcb5828ed Fixed #361 2013-06-10 01:29:14 +02:00
ee7c767c16 Limited player upload peak using CLI max-chunks-per-second parameter 2013-06-10 01:20:28 +02:00
affd67debe Added ore generation to Superflat 2013-06-10 01:06:48 +02:00
79555e4029 Fixed Sign update bug 2013-06-09 23:26:03 +02:00
e1c0139ab3 Possible fix for signs bug 2013-06-09 23:02:01 +02:00
ca8be7b047 Lowered max lag acceptance to resend packets 2013-06-09 21:55:43 +02:00
3ab3526404 Improved Player::orderChunks() 2013-06-09 21:35:37 +02:00
523c4390fa Fixed entities not updating 2013-06-09 20:55:37 +02:00
508ee7e1d6 Removed outdated functions 2013-06-09 20:40:18 +02:00
4a5783b57b Large improvement in chunk sending 2013-06-09 20:37:45 +02:00
31490576d2 Added packet loss kicks and packet recovery repetition 2013-06-09 19:07:58 +02:00
b4f95fad11 Fix 2013-06-09 18:53:39 +02:00
8c190ead7f Fixed sand getting block updates 2013-06-09 18:52:56 +02:00
fef0b27f7c Changed speed check 2013-06-09 16:36:44 +02:00
cbe0692696 Players can put out fires 2013-06-09 15:14:30 +02:00
1cc19ae1e8 Fire can be broken 2013-06-09 14:59:55 +02:00
2976db25c3 Basic implementation of Fire 2013-06-09 14:59:02 +02:00
2f6ddb6aa4 Less complete inventory sending 2013-06-09 13:51:45 +02:00
099bedf8ee New speed limit 2013-06-09 13:37:27 +02:00
bd1875f5e4 Added chunk_split() to crash dumps 2013-06-09 13:18:58 +02:00
d82399e686 Fixed #359 crash dump name not compatible with Windows 2013-06-09 13:11:55 +02:00
4f10b1cb7c Fixed #358 2013-06-09 13:02:38 +02:00
ba53a0927f Removed debug message 2013-06-09 06:00:36 +02:00
9b88a4a73f Player packet handling rewrite, fix #350 2013-06-09 05:56:48 +02:00
715b92b681 Typo 2013-06-08 19:27:18 +02:00
1014052a57 Removed /invisible 2013-06-08 19:23:16 +02:00
ac486ec970 Removed generator setting 2013-06-08 18:55:08 +02:00
5a278f8a16 Fixed regeneration acting on all gamemodes 2013-06-08 18:47:30 +02:00
7404279f15 Added spawn-animals and spawn-mobs 2013-06-08 18:34:28 +02:00
5f40ab84f0 Fixed memory tracking error 2013-06-08 18:26:24 +02:00
3061b8eb3c Added a check to memory tracking 2013-06-08 17:48:17 +02:00
e58ef1f62c Added automatic memory usage tracking 2013-06-08 17:45:33 +02:00
4803f14a21 Removed chat repeating lag issues 2013-06-08 17:25:15 +02:00
409cc0931f Fixed some indexes 2013-06-08 17:21:02 +02:00
9874bd199e Marked chat packets as not recoverable 2013-06-08 17:05:39 +02:00
1a822460d8 Fixed DEFLATEPacket return 2013-06-08 16:59:49 +02:00
8d2862a744 Fixed ladders 2013-06-08 16:36:53 +02:00
4f3e49b6a9 Packet loss limit lowered 2013-06-08 14:47:36 +02:00
f1c278915d Possible fix for memory leak 2013-06-08 14:46:34 +02:00
169d122774 Fixed typo 2013-06-08 14:31:19 +02:00
ccc5e1b628 SignPosts drop being without a support block 2013-06-08 14:30:47 +02:00
5786ba7a35 Moved blocks around 2013-06-08 14:30:26 +02:00
cd932d5c07 Snow Layer is broken on update 2013-06-08 14:23:30 +02:00
bfa65e1e7d Time is sent on change 2013-06-08 14:19:10 +02:00
16a8566fca Time now is displayed correctly 2013-06-08 14:17:38 +02:00
28480424c5 Fixed crash 2013-06-08 13:45:42 +02:00
54227b1d86 Possible memory leak fix 2013-06-08 13:43:47 +02:00
04390e758d Fixed #347 2013-06-08 13:25:17 +02:00
3e46fc1fdd Fixed crafting in some cases where item was replaced 2013-06-08 13:11:16 +02:00
97dd718e4f Fixed #348 2013-06-08 12:51:28 +02:00
883b18078f Removed clientID from checks 2013-06-08 02:22:20 +02:00
8bef816061 Added PMF_LEVEL_DEFLATE_LEVEL 2013-06-08 01:59:00 +02:00
13bfaaf7b8 Fixed crash after level unload 2013-06-08 01:50:03 +02:00
164b420af6 Tiles and Entities won't get wiped on level unload 2013-06-08 01:40:39 +02:00
38c50c2fec Fixed API unloading 2013-06-08 01:40:13 +02:00
157237e3ef Proper Level checks on unload 2013-06-08 00:57:21 +02:00
20b83319de Added stop Chunked on Player::close() 2013-06-08 00:43:39 +02:00
1ce23ab8d7 Added DEFLATEPacket protocol support
https://gist.github.com/shoghicp/5729825
2013-06-08 00:41:34 +02:00
4f3700f13a Fixes indexes 2013-06-07 20:35:05 +02:00
129e099f88 Fixed Entity metadata sending, sheeps on fire 2013-06-07 20:32:38 +02:00
9d1369bfe9 Fixed items being consumed on CREATIVE mode 2013-06-07 20:02:25 +02:00
6fa0ef652e Using !== instead of != in recipe checks 2013-06-07 19:36:14 +02:00
71e556a181 Fixed crafting repeated items 2013-06-07 19:30:30 +02:00
51f4faf22e Bonemeal usage count 2013-06-07 19:25:23 +02:00
8e127e60a0 Another fix 2013-06-07 19:18:35 +02:00
3023df2033 Function fix 2013-06-07 19:14:42 +02:00
3463db04a6 Fixed tool metadata [partial] 2013-06-07 19:14:09 +02:00
e9683ff5d2 Fixed eating 2013-06-07 19:04:02 +02:00
64dca86342 Fix overloaded property 2013-06-07 17:36:57 +02:00
6a13705970 Fixed Level PMF 2013-06-07 16:42:31 +02:00
afbde5c7ac Added server.tick event deprecation notice 2013-06-07 16:29:16 +02:00
6f2b2f98d6 Removed debug messages 2013-06-07 16:17:02 +02:00
05ae6cdef3 Better event system 2013-06-07 16:15:19 +02:00
e7c6a0c817 Another typo 2013-06-07 14:02:50 +02:00
81524362c0 Fixed typo 2013-06-07 14:02:22 +02:00
35c0c21c8d Better /kill command, ensures death 2013-06-07 12:54:45 +02:00
c37c6da42d Fixed #339 Creative players have their inventory cleared on death [gh#339] 2013-06-07 12:51:12 +02:00
3fa1bd3a05 Merge branch 'master' of https://github.com/PocketMine/PocketMine-MP 2013-06-07 12:44:15 +02:00
fdb7af5df2 Chests and furnaces drop their items on break 2013-06-07 12:44:10 +02:00
a463e0c09e Revert 67919a6 2013-06-07 09:29:38 +09:30
67919a68e1 Added Lave Bucket as Fuel Check 2013-06-07 09:17:31 +09:30
45ee7ea7ae Correct armor checks 2013-06-07 00:43:15 +02:00
e3e7919652 Fixed wool on sheeps 2013-06-06 23:55:14 +02:00
139d8b38b5 Fixed spawn eggs & buckets on creative ,pde 2013-06-06 23:31:46 +02:00
96c11adc89 Fixed typo 2013-06-06 23:05:38 +02:00
82aa76be17 Added Spawn Eggs 2013-06-06 23:02:44 +02:00
7970b8aeed Buckets 2013-06-06 22:49:43 +02:00
ab3fcfc148 Correct drops for Snow and Cake 2013-06-06 22:44:20 +02:00
28f6a964d4 Added cake eating 2013-06-06 22:24:19 +02:00
306cc9f00c Fixed #333 2013-06-06 21:51:05 +02:00
c1f79fa2f8 Fixed craftin recipes with wildcard 2013-06-06 19:51:24 +02:00
1179369666 Refixed recipe 2013-06-06 19:32:35 +02:00
0bd8d0b0d0 Fixed recipe mixture 2013-06-06 19:31:15 +02:00
67b0b97005 Fix lava buckets on furnaces 2013-06-06 19:09:23 +02:00
5e45567c1d Fixed some slot sending 2013-06-06 19:02:30 +02:00
adce1ad920 Fixed equipment error message 2013-06-06 18:32:49 +02:00
8b1c251a59 Fixes crafting 2013-06-06 18:27:10 +02:00
8b9b05991d Fixed crash 2013-06-06 17:49:38 +02:00
5cb06579cd Another fast network fix 2013-06-06 17:34:42 +02:00
63933ed1fc Fast network fix 2013-06-06 17:31:55 +02:00
4b408675cf Minecraft: Pocket Edition 0.7.0 dev. release
* Crafting enabled, report bugs
* Chat handler
2013-06-06 17:14:09 +02:00
1f4df559e0 Final fix #324 2013-06-05 18:25:16 +02:00
89ef299333 Fixed #324 2013-06-05 16:30:12 +02:00
3d3383bea7 Fix #317 - removed phpseclib 2013-06-05 15:10:40 +02:00
c95c231cfc Possible fix for #323 - Use phtreads release from pecl 2013-06-05 14:40:09 +02:00
d614f3c9da Revert "New Language Output preparation"
This reverts commit 6993528af2.
2013-06-05 14:22:04 +02:00
6993528af2 New Language Output preparation 2013-06-05 21:45:41 +09:30
18b437eec9 Fixed Entity update 2013-06-05 13:15:40 +02:00
67b533a44d Removed debug thing 2013-06-05 12:59:50 +02:00
5def864aca Removed server.tick event 2013-06-05 12:58:58 +02:00
911577e9b8 Fixed syntax error 2013-06-05 12:36:31 +02:00
fbf897d1be Fixed level event duplication on some cases 2013-06-05 12:20:57 +02:00
a5bc95e733 Fixed entities being updated when they shouldn't 2013-06-05 12:11:04 +02:00
2dd188a0bd Old pthreads release 2013-06-04 22:34:39 +02:00
a830555d90 Added a normal Temporal Generator 2013-06-04 22:31:34 +02:00
8bf10c523e Fixed Level Generation block updates 2013-06-04 20:08:14 +02:00
7e13ae2bda Leave improvement 2013-06-04 19:51:16 +02:00
7527c57e1e Fixed #274 #301 Leaves now disappear [gh#274,301] 2013-06-04 19:41:13 +02:00
06a0f169dd Better auto-save, less resource and disk usage 2013-06-04 18:45:30 +02:00
f12620f376 Possible fix for #323 2013-06-04 17:42:32 +02:00
dce9b3140a Plant growth & scheduled updates! 2013-06-04 17:23:03 +02:00
be9676ebe5 Added server_engine to query 2013-06-04 11:25:05 +02:00
bd6e3901a6 More fix 2013-06-04 11:01:59 +02:00
6f8963bdcd Correct line offset in Plugins 2013-06-04 10:58:11 +02:00
033a1673f0 Added bandwidth measure 2013-06-04 10:55:20 +02:00
0c7c36cc03 Fixed unrelated packet loss kicks 2013-06-04 10:06:21 +02:00
e01a3e6811 Increased packet loss allowance 2013-06-04 01:59:35 +02:00
566cee2b0b New way to measure Ping 2013-06-04 01:12:22 +02:00
03e059a190 Added player.spawn and player.respawn 2013-06-04 00:13:12 +02:00
f80326b714 Limited length of messages to 100 2013-06-04 00:10:57 +02:00
1935e2bbf7 Disallow weird characters in chat 2013-06-04 00:08:58 +02:00
e43b4e67c6 Disallow sending empty chat messages 2013-06-03 23:33:52 +02:00
45267ea074 Fixed crash when players try to chat [MCPE 0.7.0] 2013-06-03 23:33:07 +02:00
45efcc5faa Fixed undefined $message 2013-06-03 23:28:24 +02:00
15c9b7214d Fixed crash at unload 2013-06-03 23:26:47 +02:00
be83eaf521 Correct call of destruct chain to release PMF file locks at unload 2013-06-03 23:24:33 +02:00
f2927df2b3 Renamed TileEntity to Tile (TileEntityAPI, TileEntity class, variables) 2013-06-03 19:19:00 +02:00
5bba03eb09 Refactored EntityAPI and TileEntityAPI 2013-06-03 19:11:46 +02:00
588379a430 Added player.teleport.level 2013-06-03 18:51:33 +02:00
dc22e1b81c Kick players on high packet loss 2013-06-03 18:27:17 +02:00
f55fb8d490 Player actions and bows [WiP] 2013-06-03 16:31:33 +02:00
d1f2f82c6d Fixed #313 Entities are updated depending on near block updates [gh#313] 2013-06-03 12:20:07 +02:00
4b6e456c65 Possible solution for #317 [gh#317] 2013-06-03 11:16:12 +02:00
a8b8427065 Updated secure random number generator ith harder entropy distillation 2013-06-02 18:01:34 +02:00
ec22034ad7 Plugin version 2, include extra data 2013-06-02 17:55:59 +02:00
c7a3fc4931 Fixed time checking on Linux 2013-06-02 13:32:36 +02:00
91e414fb87 Added phpseclib for future usage 2013-06-02 13:29:24 +02:00
1b50bd6e0f FInal fix #312 2013-06-02 12:54:21 +02:00
ffd8ac2879 Fix again #312 - Vector3 2013-06-02 12:48:04 +02:00
9ead05a6fa Fixed #312 Position::getSide() now returns a Position object instead of a Vector3 one 2013-06-02 12:46:27 +02:00
4f39818cae Added something to test 2013-06-02 12:22:41 +02:00
15ab47070a Sand now falls through Liquids when placed just on top of them 2013-06-02 11:34:02 +02:00
b72d4ac407 Fixed #311 Check for Liquids, ladders and cobweb for flying 2013-06-02 11:20:16 +02:00
0ca18864f3 Fixes #311 2013-06-02 10:22:28 +09:30
54b73e5f82 Added block cloning fix 2013-06-01 19:58:54 +02:00
24ba7cbbd1 New direct block method, better block placement sending 2013-06-01 00:32:23 +02:00
722eb6d1f9 Added -uclibc for Android 2013-05-31 23:09:15 +02:00
1638e68c53 Another build script fix 2013-05-31 23:03:41 +02:00
75bb2a6399 New method EntityAPI::getRadius() 2013-05-31 18:58:59 +02:00
a890cdc023 Performance improvements - removed Player action queue 2013-05-31 14:43:53 +02:00
66fc483156 Better item pickup 2013-05-31 14:30:07 +02:00
1376cc860d Removed API::action() 2013-05-31 14:29:46 +02:00
732f5f5168 Fixed compile script *again* 2013-05-31 13:46:56 +02:00
66e635daeb New Entity update system, scheduled updates when needed only 2013-05-31 13:44:06 +02:00
3ac4b0af68 Entities spawn with their motion 2013-05-31 12:04:43 +02:00
d7f74a6725 Removed incorrect unloaded chunk detection 2013-05-31 11:53:50 +02:00
0522052c75 New compile script 2013-05-31 00:48:25 +02:00
e6dbd61308 Drops do not get into blocks 2013-05-30 19:54:55 +02:00
848554bc0c Correct falling sand drop position 2013-05-30 19:34:31 +02:00
fc02572065 Drops now have starting speed, correct entity motion at spawn 2013-05-30 18:55:50 +02:00
09efcec605 Better entity position sending using motion update 2013-05-30 16:45:44 +02:00
4507072980 Fixed sand falling replacing other blocks 2013-05-30 16:33:08 +02:00
2c8d527025 Increased view-distance by default, due to Fancy Graphics in 0.7.0 2013-05-30 16:19:58 +02:00
9919a709e9 Vector3 => Position fix 2013-05-30 13:13:36 +02:00
3825edaaab Better item spawning on falling entity break 2013-05-30 12:51:56 +02:00
6e5924a183 Typo fixed 2013-05-30 12:49:35 +02:00
a795b64bab Added new Block properties (Block::isSolid, Block::isFullBlock) 2013-05-30 12:47:24 +02:00
8d00ef381d Fixed Hardcore flags 2013-05-29 23:30:07 +02:00
b564868467 Fixed #305 Made BlockAPI check for flowable blocks instead of transparent blocks [gh#305] 2013-05-29 23:25:43 +02:00
450b5d9560 Updated TileEntity API [fixes #306] 2013-05-29 23:13:01 +02:00
25de7a68d5 API version update 2013-05-29 23:12:23 +02:00
6e2f7af6b4 Added hardcore mode 2013-05-29 22:58:43 +02:00
2f05a03e51 Fixed #304 Calculate Server Time Offset [gh#304] 2013-05-29 18:20:48 +02:00
ddec63c4d4 Fixed cleanup 2013-05-29 15:00:41 +02:00
6242089b28 Removed incomplete generator 2013-05-29 14:09:36 +02:00
1fbf475ace Mini fix 2013-05-29 14:08:30 +02:00
2271d45fd9 Fixed Mac compilation 2013-05-29 14:03:39 +02:00
f6ab39a526 Fixed falling entities falling upwards 2013-05-29 12:18:35 +02:00
71584288dc Fixed Entity floor drag 2013-05-29 12:11:12 +02:00
e67a7a510e Gravel is able to drop Flint 2013-05-29 11:57:58 +02:00
8192b41693 Fixed #303 Checking plants position on normal block update 2013-05-29 11:53:57 +02:00
4a969257d1 #303 Torches are able to be placed on top of Fences [gh#303] 2013-05-29 11:53:55 +02:00
fde93debb4 Fixed @brandon15811 typo 2013-05-29 01:13:57 +03:00
620486a4a0 Merge pull request #302 from brandon15811/patch-1
Add script for android/rpi cross-compiling
2013-05-28 14:39:27 -07:00
0d12039623 Added TileEntity::setText(1,2,3,4) 2013-05-28 23:35:33 +02:00
00427a076e Add script for android/rpi cross-compiling 2013-05-28 16:33:51 -05:00
58fd67d2ed Falling Entities, better Physics [not final] 2013-05-28 22:03:58 +02:00
cb03daf28a Removed duplicate in compile script 2013-05-28 11:05:38 +02:00
3d28f519c7 Revert "Fix for pthreads and cross_compile"
This reverts commit 6b61bc11d0.
2013-05-28 08:23:13 +02:00
6b61bc11d0 Fix for pthreads and cross_compile 2013-05-28 08:06:44 +02:00
c9d0cf3698 Added env. variable to specify the number of threads [gh#300] 2013-05-27 23:20:06 +02:00
5d6669201b Fixed compile script 2013-05-27 21:24:13 +02:00
d8f6e9ff0e Pass compile options via env. variables 2013-05-27 20:36:49 +02:00
929c27e339 Changed the order of some build instructions 2013-05-27 18:16:58 +02:00
a92e4f6acd Disable not needed cURL functions 2013-05-27 16:36:31 +02:00
b7bc0826af Autodetection of native machine and code optimization 2013-05-27 14:23:10 +02:00
044b25ccd2 Faster chunk distance ordering 2013-05-26 19:58:23 +02:00
90effd173b Faster chunk sending algorithm 2013-05-26 19:57:41 +02:00
fc80a85c8c Faster network stack on overflow conditions 2013-05-26 19:57:19 +02:00
06c57a3aae Fixed #293 player.armor data not being correct [gh#293] 2013-05-26 16:16:36 +02:00
6d54495402 Cached Utils::getIP() method 2013-05-26 16:15:30 +02:00
838e7ad010 Hide rcon.password in the crash log 2013-05-26 16:11:21 +02:00
6262fbffcb Send correct entity motion 2013-05-26 14:06:26 +02:00
7622151a21 Pine & Spruce trees fixed 2013-05-26 13:36:33 +02:00
aefcfad296 Added more features to the World Generator 2013-05-26 13:22:22 +02:00
424dba2fdd Filling a chunk triggers the block change saving algorithm 2013-05-26 12:48:20 +02:00
7c3b8807e9 Alpha_1.3.1dev version 2013-05-26 12:16:23 +02:00
f6a395e7b7 Possible fix for #289 [gh#289] 2013-05-26 12:04:26 +02:00
d92056fe77 Fixed typo in deop 2013-05-26 17:36:45 +09:30
161a271127 Merge pull request #290 from sfan5/patch-1
Allow DeOPing disconnected players
2013-05-26 01:03:07 -07:00
8ec11b35ad Set up base for upcoming Mob MobAI and MobAPI 2013-05-26 17:27:16 +09:30
df4a29d7d6 Allow DeOPing disconnected players 2013-05-26 09:55:03 +03:00
00de63986b Alpha_1.3 stable release 2013-05-26 01:18:44 +02:00
60c0345c81 Fixed cobweb 2013-05-26 00:49:20 +02:00
b39677cc96 Added LevelAPI::unloadLevel(Level $level) 2013-05-26 00:37:18 +02:00
72f8f00c5d Autorecovery of bad chunks 2013-05-25 23:46:02 +02:00
ce391160f4 Added hostile mobs drops 2013-05-25 23:21:21 +02:00
7111bc5e64 Improved updated messages 2013-05-25 22:56:09 +02:00
7a5df07ee5 Fixed #220 Players now drop items on death [gh#220] 2013-05-25 22:36:13 +02:00
7ade4762b9 Fixed #288 [gh#288] 2013-05-25 21:19:24 +02:00
a153f2ebdc Minifix 2013-05-25 19:29:24 +02:00
a538543e4c Fixed #287 Items dropped will be deleted if picked up in creative mode [gh#287] 2013-05-25 19:27:29 +02:00
5e1dddaba0 Added correct clay blocks 2013-05-25 19:20:37 +02:00
f224c26084 Furnaces and Burning items 2013-05-25 19:06:31 +02:00
221da1685e Fixed #281 client crashes due to packet recovery 2013-05-25 14:07:08 +02:00
e34b407538 Fixed #283 server crash when placing brown mushrooms [gh#283] 2013-05-24 23:56:35 +02:00
b8834890b6 Temporal fix for player crashing 2013-05-22 16:31:59 +02:00
03062c4e54 Fixed #204 Packet recovery algorithm can recover unsent chunks [gh#204] 2013-05-22 12:17:31 +02:00
929aebc1bf added ticks to error logs 2013-05-21 23:02:56 +02:00
363501d988 Fixed #275 2013-05-21 23:01:56 +02:00
9857f40175 Removed notice message 2013-05-21 20:44:02 +02:00
29b96fa855 Merge pull request #273 from greyson/master
Nearer-original tree generation
2013-05-21 11:29:51 -07:00
49716cfb18 Fixed packet-related stuff 2013-05-21 20:29:10 +02:00
acc373525f Removed MT Random generator namespace 2013-05-21 20:14:03 +02:00
c29d3a3e56 Better (more original) looking trees 2013-05-21 14:03:42 -04:00
b7083032f3 Updated settings, less memory usage 2013-05-21 19:50:59 +02:00
c9cecaf218 Fixes 2013-05-21 19:29:57 +02:00
9dbdab8060 Added } 2013-05-21 19:19:50 +02:00
8c5d0f070d Changed flying checks 2013-05-21 19:17:13 +02:00
73c5e7d7bc Added more food sources 2013-05-21 18:52:56 +02:00
4766424cb3 Fixed moving to fast message during Player blocking 2013-05-21 18:40:00 +02:00
8e8002c479 Fixed crash 2013-05-21 15:52:37 +02:00
409f0670bd Added sendUsage() port 2013-05-21 11:06:38 +02:00
ee12b41c39 Allow-flight disables speed checks 2013-05-21 08:24:17 +02:00
cd30f51979 Added startup errors display 2013-05-20 23:39:15 +02:00
6dc1e99f5a Merge pull request #269 from greyson/master
added libedit/readline support
2013-05-20 13:32:54 -07:00
cca453cc06 Feature complete: 'libedit' 2013-05-20 16:26:06 -04:00
ff8de264c0 Added "readline" support using libedit. 2013-05-20 16:17:11 -04:00
c6121e88bf Optionally disabled libedit based on results of compile 2013-05-20 16:17:11 -04:00
27050b9ec4 Internal ticker autocalculation 2013-05-20 17:21:04 +02:00
43071dd0ac RCON bad reading fixed 2013-05-20 17:20:35 +02:00
281d3b037f Fixed #255 Player and item bounding boxes 2013-05-20 16:53:57 +02:00
13b00988f0 Added GLOWSTONE constant 2013-05-20 16:44:28 +02:00
228075851c Correct Ice drop 2013-05-20 16:38:41 +02:00
47b54cfd28 Fixed #270 Blocks that need to be broken with a pickaxe now give correct drops & items 2013-05-20 16:33:09 +02:00
8336b4c91b Added libedit download/compile 2013-05-20 03:53:58 -04:00
713f16771f Added some socket options to cURL 2013-05-20 09:43:32 +02:00
aa14539274 Added execute bit to scripts 2013-05-20 08:26:04 +02:00
98c790d731 Fixed #265 2013-05-20 00:28:58 +02:00
00a41e7e11 Correct Slab checking error 2013-05-20 00:24:13 +02:00
ae13512627 Added index 2013-05-19 23:03:59 +02:00
95f2f347ff Updated Level::setMiniChunk() and Level::setRawBlock 2013-05-19 23:03:09 +02:00
48b5afac46 Packet broadcast to players 2013-05-19 22:49:40 +02:00
b9e3acd017 Do not grow trees on incorrect blocks 2013-05-19 21:00:38 +02:00
2fc542d93d Added trees to the flat preset 2013-05-19 20:54:43 +02:00
a7a45dfe96 Updated flat preset, do not allow empty Level names 2013-05-19 20:53:12 +02:00
bb9067acd7 Fixed #262 2013-05-19 19:32:40 +02:00
68855bdd4f Buffered block changes and sending big changes with Chunk Packets 2013-05-19 19:27:55 +02:00
10ed95a469 Don't fire change events if block has not changed 2013-05-19 17:53:40 +02:00
04f0500822 MTU used correctly 2013-05-19 17:11:21 +02:00
e3de52ba8b Fixed bigRaw packets reliability 2013-05-19 16:47:57 +02:00
2c4a428698 Packets bigger than the MTU are automagically split in different packets 2013-05-19 13:51:02 +02:00
b481c26839 Fixed teleporting to worlds with spaces 2013-05-19 13:32:27 +02:00
e163223134 Implemented safe_var_dump() 2013-05-19 03:39:33 +02:00
295363a381 New Player::directBigRawPacket() method 2013-05-19 02:50:04 +02:00
db97c0c5f7 Updated hook 2013-05-18 21:04:58 +02:00
d28780fa05 Updated Travis repo 2013-05-18 21:03:00 +02:00
a7709f827f Updated repository URL 2013-05-18 21:00:16 +02:00
22cc3d4d83 Clear Plugin file error during a crash 2013-05-18 19:47:50 +02:00
f485124190 Fixed #257 2013-05-18 19:12:50 +02:00
b48f486620 Fixed no params aliases 2013-05-18 19:04:31 +02:00
e3bf38e0b2 Plugin API: Allow Plugins without Main class 2013-05-18 18:24:48 +02:00
7297f8d2c0 Level Generation API updated 2013-05-18 15:22:07 +02:00
c408ee07b1 Player spawning on unknown worlds will be redirected properly to the main world 2013-05-18 15:21:54 +02:00
6adc41f301 Fixed #256 Signs not attaching to walls 2013-05-18 13:26:31 +02:00
af85c7ce45 Added Perlin noise generator 2013-05-18 13:16:35 +02:00
22d9cefe96 Fixed build 2013-05-18 11:24:31 +02:00
5faeff9e16 Fixed PMF metadata set 2013-05-18 11:19:08 +02:00
e81d68c8d0 Added trees to teh SuperflatGenerator 2013-05-18 11:02:00 +02:00
3c4d4f5cff Updated pthreads version 2013-05-18 02:53:35 +02:00
5ea6052a8a New Level Generator API & Support for MC Superflat Presets 2013-05-18 02:05:56 +02:00
edb93d6312 Fixed #254 2013-05-17 18:45:02 +02:00
3bb7114e7c Fixed PMFLevel::getBlock() not converting to int 2013-05-17 15:08:56 +02:00
d71a088460 Added MC_REMOVE_PLAYER 2013-05-17 14:33:14 +02:00
6db36c238f Allow OPping disconnected players 2013-05-17 14:02:01 +02:00
09fabfc87e Fixed getting spawn seed 2013-05-17 13:56:18 +02:00
2377cf7199 Index fix 2013-05-17 13:19:44 +02:00
b82e9b2895 Fixed already loaded worlds 2013-05-17 13:14:52 +02:00
651398e500 Fixed #249 2013-05-17 12:33:42 +02:00
2b89b51621 Fixed #251 implode() error 2013-05-17 12:30:39 +02:00
f3fe0a6d27 Merge pull request #250 from zhuowei/master
Fixed a few missing methods due to the Multiworld conversion fixed #248
2013-05-16 22:20:38 -07:00
4678b57c75 Fixed a few missing methods due to multiworld conversion 2013-05-16 19:03:18 -07:00
7bbda6dd67 Detect non loaded chunks 2013-05-16 20:24:05 +02:00
4564765470 Added "player.teleport" 2013-05-16 19:39:15 +02:00
2305322ed0 tp help 2013-05-16 19:13:36 +02:00
848a69b28a /tp [player] w:[world] & simple /spawn 2013-05-16 19:13:03 +02:00
6a0cc4e122 Fixed teleport pitch 2013-05-16 18:13:08 +02:00
beb84ca013 Teleport fixes 2013-05-16 18:11:26 +02:00
9dd1568c40 New Player::getSpawn() 2013-05-16 18:05:05 +02:00
66322d7719 Selector aliases & @world & /spawnpoint 2013-05-16 18:02:24 +02:00
ad4959f8c0 Fixed selectors 2013-05-16 17:44:43 +02:00
fceb076b9b Better speed measure 2013-05-16 17:31:26 +02:00
1dbbf08f1b Use other things instead of array_shift 2013-05-16 17:30:34 +02:00
5277555d33 Relative teleporting 2013-05-16 17:21:39 +02:00
7d49847ae7 Correct teleport message 2013-05-16 17:14:02 +02:00
3cc4546f93 Fixed Level::nextSave 2013-05-16 17:07:28 +02:00
9a3f887f44 Attacking entities fixed 2013-05-16 16:41:54 +02:00
1f8987183b Removed libevent 2013-05-16 16:12:15 +02:00
072e1328f1 Updated pthreads version 2013-05-15 23:37:54 +02:00
d071497747 Fixed redstone scheduled update 2013-05-15 23:30:47 +02:00
e0e724bcc3 Saving entities/tiles 2013-05-15 23:30:46 +02:00
fb69cf3392 Chunk unloading fixed 2013-05-15 23:30:45 +02:00
f1e4bb0f62 Scheduled saving 2013-05-15 23:30:44 +02:00
244fde8143 Chunk unloading 2013-05-15 23:30:43 +02:00
3f532d419c Saplings 2013-05-15 23:30:43 +02:00
6f59e2eaad Time API working with changes 2013-05-15 23:30:42 +02:00
5ee2cda4a6 Level-independient time change 2013-05-15 23:30:41 +02:00
e63677a23d Level saving 2013-05-15 23:30:40 +02:00
78baa237e3 Remove teleporting players from the other world 2013-05-15 23:30:39 +02:00
3fca7ab6a5 Don't fire events in different worlds 2013-05-15 23:30:38 +02:00
9e55de134f Added /seed 2013-05-15 23:30:37 +02:00
bcbc65ed5e Added /spawn [world] [player] 2013-05-15 23:30:36 +02:00
838e08b33b Fixed metadata packing 2013-05-15 23:30:36 +02:00
991436993f Fixed things 2013-05-15 23:30:35 +02:00
cef4347a02 Fixed error with world teleporting 2013-05-15 23:30:34 +02:00
de5be4168d Fixed RCON non-blocking sockets 2013-05-15 23:30:33 +02:00
33bd66c1da Added world teleporting 2013-05-15 23:30:33 +02:00
7de0835ad9 Chat Selectors [@player] 2013-05-15 23:30:32 +02:00
d0d5c1bb79 CMD Selectors [@all, @player, @random] 2013-05-15 23:30:31 +02:00
c6c82f7e55 Player scheduled actions get cleaned 2013-05-15 23:30:30 +02:00
5dade755eb Fixed Player memory leak 2013-05-15 23:30:29 +02:00
24c0e2742a Fixes 2013-05-15 23:30:29 +02:00
c27cca6741 More fixes :D 2013-05-15 23:30:28 +02:00
7236f4aad6 Few fixes 2013-05-15 23:30:25 +02:00
2254e87ce4 PMF & Multiworld [part 3] 2013-05-15 23:30:24 +02:00
5938747083 PMF & Multiworld [part 2] 2013-05-15 23:30:22 +02:00
9b212ae034 New stats 2013-05-15 23:30:21 +02:00
db8f50f408 PMF & Multiworld [part 1] 2013-05-15 23:30:20 +02:00
bbbc54f606 New API version 2013-05-15 23:30:19 +02:00
703803eb6b New pthreads version 2013-05-12 12:32:02 +02:00
60b559d64b Added webhook 2013-05-12 13:19:57 +03:00
6610f82ceb Updated PHP version 2013-05-12 11:48:23 +02:00
73867f1f80 Updated ZLIB version 2013-05-10 21:49:45 +09:30
cfb2d939a4 Added little bits of comments to the BanAPI for better understanding by newbies. 2013-05-10 18:38:32 +09:30
5b6724a452 Mac machines are detected 2013-04-29 00:46:36 +03:00
4ec2bed44d More fix 2013-04-27 01:02:30 +02:00
2a4d2a92ab Fix :DD (remove temp. feature) 2013-04-27 00:49:59 +02:00
47e9a7b6a1 Fix :D 2013-04-27 00:43:42 +02:00
d7a54123e2 New Event ConsoleLoop 2013-04-27 00:39:59 +02:00
3cae25cebd Fix ^^ 2013-04-27 00:27:37 +02:00
e0727d2e57 Fix 2013-04-27 00:21:22 +02:00
77ecdb8727 Event test in ConsoleAPI 2013-04-27 00:15:01 +02:00
21150cd239 Added Event and libevent to README.md 2013-04-26 23:55:03 +02:00
cea84879e7 OCD 2013-04-26 23:35:07 +02:00
e43c45768d Added Event support 2013-04-26 23:25:26 +02:00
d48a1a6ce3 Fixed typo 2013-04-26 23:15:06 +02:00
83cce9cdf3 *changes* 2013-04-26 23:01:13 +02:00
d56328b16a Added PHP event and libevent2 for testing 2013-04-26 21:22:56 +02:00
8aa047b3f0 Removed obsolete methods from the Utils class 2013-04-26 19:56:08 +02:00
c4ff8921f1 StackableArrays class 2013-04-25 20:29:45 +02:00
6a4010a9af Fixed plugins not generating their config file 2013-04-25 18:52:14 +02:00
8149c9e7ca Better plugin list in the Error dump 2013-04-25 18:31:03 +02:00
a3a2155026 Removed startup binary I/O test 2013-04-25 18:30:44 +02:00
173784752e Added GIT_COMMIT to the Error dump 2013-04-25 17:54:32 +02:00
33a614c615 Removed libevent dependency 2013-04-25 17:29:32 +02:00
515fcf0890 Updated build script path 2013-04-24 22:27:45 +02:00
72208d9159 Added shmop to build script 2013-04-24 20:32:25 +02:00
31ffe8017f Updated build script for libevent 2013-04-24 19:37:02 +02:00
9624b9c35e Added libevent dependency 2013-04-24 00:41:37 +02:00
9b07994913 Chat & Console fixes 2013-04-23 19:21:08 +02:00
fea6e9c432 Fixed Container::check() blacklist 2013-04-23 18:21:37 +02:00
13aa73d26e Added correct Painting placing checks & bigger Paintings 2013-04-23 15:32:09 +02:00
dffbfa0754 PlayerAPI teleport commands now return a correct name 2013-04-23 12:42:43 +02:00
2e4724c596 Added Query protocol description 2013-04-23 12:18:08 +02:00
3378c44542 Added output redirection to kill() 2013-04-23 11:59:34 +02:00
093bf3ddee Query now checks for the last token when changed (30-sec change) 2013-04-23 11:44:58 +02:00
85e3c08aa9 Added the "rcon.port", "rcon.threads", "rcon.clients-per-thread" ghost properties 2013-04-23 11:39:39 +02:00
8345fd02c4 Set default gamemode to SURVIVAL 2013-04-23 10:49:25 +02:00
1c03fb0de9 Removed the rcon.port property, being the same as the server 2013-04-23 10:33:15 +02:00
2ae0cf65c5 Added protocol info to README.md 2013-04-23 02:00:22 +02:00
cb42e5832b Added documentation for RCON and Query 2013-04-23 01:21:34 +02:00
ee73ccc0e2 Remoced "hostip" from Query 2013-04-23 01:17:39 +02:00
cc2addfe92 Implemented Query protocol 2013-04-23 00:58:26 +02:00
be7e5cd67a Unknown packets are always discarded even if they have been processed 2013-04-22 23:46:34 +02:00
e428b4cfc4 Limited RCON threads to one and added a auth timeout 2013-04-22 23:33:46 +02:00
f466e1f791 Added Player::getSlot() for consistency 2013-04-22 21:01:53 +02:00
bb9a6146fd Raised the speed limit 2013-04-22 19:20:25 +02:00
34ca8baa29 Fixed "player.interact" event only being fired with weird conditions 2013-04-22 18:46:35 +02:00
d552042094 Fixed #166 2013-04-22 17:25:45 +02:00
6457055be3 Added TimeAPI command responses 2013-04-22 16:51:04 +02:00
02bbfb60b6 Increased RCON max clients per thread to 25 (total 100 clients) 2013-04-22 16:46:48 +02:00
b759863bb1 Changed /list to be the same as vanilla 2013-04-22 16:39:33 +02:00
e81793174b Multiple RCON clients per thread, allow external connections 2013-04-22 16:28:24 +02:00
d08807abaf Added 4 RCON threads 2013-04-22 14:29:30 +02:00
1cb3e25bf9 Added RCON protocol 2013-04-22 14:22:52 +02:00
70056b8d1f Save config filles automatically after adding new defaults 2013-04-22 00:05:56 +02:00
2f1e37ce6c Updated Spyc library 2013-04-21 22:29:44 +02:00
80488784f9 Updated cURL release 2013-04-21 22:23:52 +02:00
55b8401967 Updated pthreads version 2013-04-21 22:22:43 +02:00
269e63ab50 Rewrite /defaultgamemode command to allow multiple values 2013-04-20 21:00:52 +02:00
d0d8d281d2 Revert "Added coordinates command. Displays your coordinates"
This reverts commit 4434fe2a5b.
2013-04-20 20:56:58 +02:00
4434fe2a5b Added coordinates command. Displays your coordinates 2013-04-20 14:45:35 +09:30
82c72f8beb Added defaultgamemode command 2013-04-20 12:26:26 +09:30
083110ffd0 Fixed #194 Implemented armor damage reduction 2013-04-19 14:31:41 +02:00
0bea234788 Fixed #206 2013-04-19 13:53:58 +02:00
e444f2a9e0 Fixed #208 2013-04-19 13:40:02 +02:00
38950969dd Added Player::setSpawn(Vector3 $pos) method 2013-04-18 22:34:12 +02:00
9a4c3f8c9f Revert "Updated PHP version on .travis.yml"
This reverts commit e4e649ec49.
2013-04-18 20:37:07 +02:00
c3a0600ffd Added __get() magic methods to Player and set some properties private 2013-04-18 20:22:20 +02:00
78167a3cd4 Fixed players not getting their inventory reset on gamemode change 2013-04-18 19:33:51 +02:00
724e9d9bb2 Fixed changing gamemodes 2013-04-18 17:25:07 +02:00
8b41246f2d Added "player.gamemode.change" 2013-04-18 17:18:42 +02:00
e4e649ec49 Updated PHP version on .travis.yml 2013-04-18 17:10:14 +02:00
639ca67a10 Blocked again opening of chests in Creative mode 2013-04-18 17:05:26 +02:00
96baeaaad2 Fixed VIEW gamemode crash 2013-04-18 16:54:48 +02:00
bcb76b51f4 Fixed setting more gamemodes 2013-04-18 16:43:00 +02:00
3577667039 New VIEW gamemode 2013-04-18 16:40:30 +02:00
5848d283da Correct MC_LOGIN_STATUS usage 2013-04-18 16:16:54 +02:00
8f724ffc46 Resend slot on change 2013-04-17 23:29:44 +02:00
26c2f61da0 Added fix so players aren't targeted by name completion by default 2013-04-17 23:02:53 +02:00
fd8166c836 Obligatory Creative mode item enforcement 2013-04-17 22:57:44 +02:00
bc80c01348 Return output of commands on ConsoleAPI::run() method 2013-04-17 20:24:10 +02:00
e0a59486eb Force inventory sending on death 2013-04-17 20:15:51 +02:00
393f54fe28 /give compatible with "item-enforcement" = off 2013-04-17 19:48:13 +02:00
1885cdf3a2 Changed item enforcement option name 2013-04-17 19:41:46 +02:00
e65731e3ec Item enforcement optional for packet sending 2013-04-17 19:38:29 +02:00
f7f05d4175 Paintings are removed at usage 2013-04-17 19:32:06 +02:00
cd8211a9d3 Fixed client-side item duplication 2013-04-17 19:31:15 +02:00
09301f0e5f Added a way to send Player's inventory directly 2013-04-17 19:25:53 +02:00
5e4ef9732b Oops! 2013-04-17 17:23:12 +02:00
44cb66837e Fixed torch sides 2013-04-17 17:22:57 +02:00
f195168132 Fixed Player not getting in survival mode removed due to BlockAPI checking Server default gamemode 2013-04-17 17:13:36 +02:00
32e0085c1e Allow placing torches on top of side blocks 2013-04-17 17:10:05 +02:00
b34e55eec5 Torches drop when no supporting block is present 2013-04-17 17:09:48 +02:00
758070e478 Optimized block updates 2013-04-17 16:41:36 +02:00
2790f60491 Added Redstone Ore block update 2013-04-17 16:36:37 +02:00
d8bf5ce711 Added Cakes 2013-04-16 20:00:41 +02:00
bbbdaa30d1 Better online player list 2013-04-16 19:48:33 +02:00
2438c9535b Only shown available commands in help 2013-04-16 19:46:14 +02:00
3d48eec887 Allow looking the help of an alias 2013-04-16 19:41:37 +02:00
f1cb29cc8b Increased Socket buffer size 2013-04-16 19:11:03 +02:00
710ed5c704 Improved block updates and Scheduled block updates [part1] 2013-04-16 17:15:39 +02:00
3c40c8734f Changed PHP directory [migration included] 2013-04-15 16:02:43 +02:00
80aaf9923c Fixed packets being discarded due to a bad ordering 2013-04-14 23:19:55 +02:00
cad9908f94 Added new network reliability identifiers 2013-04-14 18:47:50 +02:00
9ad73b00c8 Removed online broadcast 2013-04-14 18:47:34 +02:00
fb805f2b0f Re-fixed #200 2013-04-14 17:08:05 +02:00
e0791b9bae Log out message 2013-04-14 17:00:13 +02:00
10d34a7ce6 Fixed 0x60 packets being received 2013-04-14 16:58:54 +02:00
69b78a9dd6 Send Usage data again 2013-04-14 16:30:26 +02:00
8442c0529e Added player.connect (pre-join) 2013-04-14 16:19:27 +02:00
77da9d3a7c Chat messages are shown on the server log 2013-04-14 16:19:16 +02:00
5e9e2b2a7d Commands are executed as console by default 2013-04-14 16:10:41 +02:00
88a4116398 Fixed #200 Running in a folder with spaces 2013-04-14 13:10:04 +02:00
633f7233b4 New network reliability layer 2013-04-14 13:04:57 +02:00
a92518ef9e Fixed console messages without [TAG] 2013-04-14 13:01:50 +02:00
0c051fb02e Removed MP chat tag 2013-04-13 20:03:07 +02:00
e71b6946f3 Fixed /help paging 2013-04-13 20:01:27 +02:00
d157299c7a Updated console texts and help 2013-04-13 19:47:20 +02:00
82d49b0343 PluginAPI API error to warning 2013-04-13 18:55:29 +02:00
790b9c19b6 Fixed hack check crash 2013-04-13 16:22:05 +02:00
439d0ead4f Default equipment fix 2013-04-13 14:37:01 +02:00
3ae18c85b1 Round coords at spawn 2013-04-13 14:34:04 +02:00
74c4fab58d Space 2013-04-13 14:32:58 +02:00
199fbb644b Fixed spawning despawned entities 2013-04-13 14:21:58 +02:00
4867533ab7 Removed TNT explosion on break 2013-04-13 13:47:37 +02:00
452df5b2f8 Added Buckets 2013-04-13 13:42:55 +02:00
c334bbce12 Item change protection 2013-04-13 13:37:14 +02:00
8d7fafe167 Removed /crash 2013-04-13 13:23:05 +02:00
996bf6b366 Updated PHP & pthreads version 2013-04-13 13:02:41 +02:00
1cf61fc829 Fixed #196 syntax error 2013-04-13 11:55:45 +02:00
75a2bf122f Added "disallow-crafting" to enable item protection 2013-04-12 23:11:07 +02:00
159d1c5024 Added missing parameters 2013-04-12 23:09:28 +02:00
e2b68a01d1 UDP Sokcet port blocking exit 2013-04-12 20:35:39 +02:00
bab3b8274a Explosions 2013-04-12 20:35:16 +02:00
a6615560bc fix. 2013-04-12 14:21:09 +02:00
62735c8e41 Changed messages 2013-04-12 14:20:52 +02:00
5c2a2ecd6d Added a security radius for flying 2013-04-12 14:09:36 +02:00
432eb36b83 Fixed support check height difference 2013-04-12 14:06:12 +02:00
7388a32869 Fixed flying check support range 2013-04-12 14:04:57 +02:00
83a63ef805 Added login packet protection 2013-04-12 13:59:21 +02:00
c45cd5e12a Fixed a crash 2013-04-12 13:58:25 +02:00
c138cb2797 Fixed player death name 2013-04-12 13:55:26 +02:00
feaecbcd60 First usage report 5 minutes after the server restart. 2013-04-11 23:16:29 +02:00
3e4efbb26a Fixed players not being able to move after being damaged 2013-04-11 22:40:18 +02:00
b9498275a4 Fixed /invisible not working 2013-04-11 22:35:47 +02:00
f7af97c651 Direct fix for speed hack 2013-04-09 21:07:35 +02:00
076691ec52 Added fixes for hacks like Health protection and speed hack 2013-04-09 21:02:46 +02:00
2763401be3 /give now checks correctly 2013-04-09 20:44:57 +02:00
a3b7f12803 /banip add <player> works banning the Player's IP 2013-04-09 19:52:10 +02:00
eac72bb8ae Added "player.flying" event, ops can always fly 2013-04-09 19:11:45 +02:00
7b8a27f7b0 Removed time-per-second property 2013-04-09 19:04:01 +02:00
6ba7486097 Gamemode check for flying 2013-04-09 18:58:32 +02:00
4dd66b450c Flying damage & kicks less random 2013-04-09 18:57:41 +02:00
2b741a2913 Fixed crashes, added flying check 2013-04-09 18:44:13 +02:00
2043534003 Removed constant property file write 2013-04-09 17:39:36 +02:00
7e37a60a67 Changed property names for consistency (migration included) 2013-04-09 17:35:37 +02:00
f093286fb2 Disallow joining invisible servers 2013-04-09 17:26:30 +02:00
7c9eec7869 Added a parameter to remove directly the async thread 2013-04-09 17:23:29 +02:00
79ca735fb0 Fixed a weird, random, pthreads-caused crash 2013-04-09 17:21:49 +02:00
533b175b66 Syntax error 2013-04-09 17:09:21 +02:00
2c81518c5d OP players are automatically whitelisted 2013-04-09 17:08:44 +02:00
dccfbfd572 Added "view-distance" setting to change chunk sending radius 2013-04-09 17:07:17 +02:00
e88c337229 Added the "spawn-protection" property to define the protection radius 2013-04-09 17:02:03 +02:00
5f55cdf26a Added pvp server property 2013-04-09 16:58:52 +02:00
3e3521086b Fixed crash due to new API changes 2013-04-08 23:07:01 +02:00
01e31fc82e Updated test to reflect changes 2013-04-08 22:59:34 +02:00
b66e784a12 Removed GMP dependency, using bundled BCMath 2013-04-08 20:23:44 +02:00
20694f2c77 Changes to Threads 2013-04-07 14:35:39 +02:00
539c8046d8 Removed deprecated chat() method in server 2013-04-07 13:47:11 +02:00
1d32e82265 Usage sending in background 2013-04-07 12:28:34 +02:00
12f9c12fe4 Changed default file permissions 2013-04-07 12:15:34 +02:00
0060c3f10d Duplicated chunk loading speed 2013-04-05 16:33:47 +02:00
6456d2383b Added a spawn protection 2013-04-05 15:51:19 +02:00
793aaf87c0 /op and /deop needs the player connected 2013-04-05 15:37:18 +02:00
f7de979de1 Added commands to whitelist 2013-04-05 15:14:32 +02:00
82a789687c Added /me 2013-04-05 15:13:17 +02:00
026353399b Added /tell 2013-04-05 15:09:25 +02:00
febfbb19c4 Updated /gamemode command to follow Minecraft structure 2013-04-05 14:09:02 +02:00
45bbc86830 Username completion & better gamemode change 2013-04-05 14:04:51 +02:00
3d8c9db430 Fixed #183 Players taking damage landing on water (temp. fix) 2013-04-05 12:43:18 +02:00
8405c74b42 Fixed #186 players not teleporting due to speed check 2013-04-05 12:41:05 +02:00
93cfa035d4 Fixed #187 Opening Chests with solid blocks on top 2013-04-05 12:37:08 +02:00
463e82a1e7 Changed final public methods 2013-04-04 12:04:03 +02:00
cd946a7273 Added fix to Utils::getOS() method 2013-04-03 19:21:12 +02:00
074c1b5295 Added a fix so higher PMF version files doesn't get loaded 2013-04-03 13:20:18 +02:00
ad6b48a599 Updated README.md 2013-04-03 12:43:54 +02:00
e77db15c21 Error suppression 2013-04-03 12:30:51 +02:00
683fd03f45 Set process title PHP 5.5 function fallback 2013-04-03 12:28:57 +02:00
dbc357c266 Removed killing php to end the process 2013-04-03 12:21:12 +02:00
e0747a9c44 PHP 5.5 2013-04-03 11:38:50 +02:00
cdc164729c Added server.unknownpacket to receive unknown packets 2013-04-02 20:45:30 +02:00
4e8e132fcf Added damage for Axe, Pickaxe, and Shovel 2013-04-02 16:37:08 +02:00
77fa1608c1 Fixed #179 2013-04-02 16:33:15 +02:00
e3a858a089 Merge pull request #179 from williamtdr/master
Updated Player.php for sword damage amounts
2013-04-02 07:27:55 -07:00
eeb9b925a5 Removed unnecessary left bracket causing syntax error
Sorry 'bout that.
2013-04-01 18:01:15 -05:00
082c4429cd Updated PECL pthreads release 2013-04-02 00:14:19 +02:00
314da7b30e Update Player.php
Swords now do proper damage amount
2013-04-01 12:03:38 -05:00
1129df6194 View connection lag in-game 2013-04-01 16:25:25 +02:00
1ef0a41944 Added Ping / Pong system 2013-04-01 16:03:43 +02:00
1cb30601b5 20 mini chunks / second 2013-04-01 14:54:08 +02:00
534898167e Improve loading on Y chunks 2013-04-01 14:49:13 +02:00
f53877c070 Fixed a few things
REALLY BUGGY!!! DO NOT USE THIS!
2013-03-31 15:03:13 +02:00
ecc2faffea Fixed #128 player death 2013-03-31 14:44:39 +02:00
66169d63c4 Force chunk resend on teleport 2013-03-31 13:50:13 +02:00
b83ef4e70b Automatically remove ANSI codes from chat 2013-03-31 13:36:19 +02:00
e2d4b49266 Remove single beds 2013-03-31 13:27:31 +02:00
1b92b1177c Fixed #176 bed breaking not removing origin block 2013-03-31 13:25:58 +02:00
251b88f8ba Limited Player tick time queue further 2013-03-31 13:20:05 +02:00
f8c6921ac4 Few protocol edits 2013-03-31 00:12:19 +01:00
2b03e71c97 Do not measure Y dimension for moving speed 2013-03-30 21:38:29 +01:00
263824fa01 Fixed division by zero 2013-03-30 21:35:59 +01:00
abf52079fc Chunk loading based on X,Y,Z (+1 dimension) 2013-03-30 21:35:50 +01:00
7312c57123 Improved internal Client IDs 2013-03-30 21:09:12 +01:00
f7a12b09f7 Better Player queue completion limited by time 2013-03-30 20:56:01 +01:00
949ab34b42 Added player.block.(break/place).invalid handling events 2013-03-30 20:26:15 +01:00
121fd51dc6 Fixed placing blocks on activable blocks 2013-03-30 19:51:21 +01:00
44fcf4a6ed Noob-proof memory-limit server property 2013-03-30 19:36:49 +01:00
a6cc0f8261 Same for Peak Memory usage 2013-03-30 19:34:08 +01:00
bd196c0fcb Typo 2013-03-30 19:33:18 +01:00
caa32edf6f Get REAL memory usage, not allocated 2013-03-30 19:33:05 +01:00
87ebe7fac4 Generic importing to PMF Level format 2013-03-30 14:08:22 +01:00
8c9f07f737 PMF Level format fixes 2013-03-30 14:08:11 +01:00
cbe160e655 Fixed #169 and fixed #168 2013-03-30 13:11:06 +01:00
efa8692bfa Added wget dependency 2013-03-30 02:25:12 +01:00
3f2cb86859 Normalized Item Names 2013-03-29 20:11:53 +01:00
6d39f54591 Removed $server constructor arguments because of ServerAPI::request() 2013-03-29 19:49:33 +01:00
af52b0a5b5 Fixed ACK/NACK range writing 2013-03-29 11:18:47 +01:00
257b330a53 Fixed ACK/NACK range reading 2013-03-29 11:07:45 +01:00
8a9e6426ca Optional teleport yaw & pitch 2013-03-29 10:56:28 +01:00
3f820d18d2 Removed teleport jerking 2013-03-29 10:54:58 +01:00
677e1f8ce0 Added Player automatic blocking during spawn or gamemode change 2013-03-28 17:59:45 +01:00
822adcae2d Packet Cleaning 2013-03-28 16:56:50 +01:00
4ea4431986 Less Server->Client NACK usage 2013-03-28 14:37:35 +01:00
e392a35598 Fixed client-side ACK & NACK 2013-03-28 14:08:45 +01:00
912e35f202 Fixed server-side NACK & ACK 2013-03-28 13:59:56 +01:00
f1a28f23ae New ACK/NACK structure & Packet multiple ressend issue 2013-03-28 13:56:11 +01:00
c68b4ebda6 Few packet loss system fixes 2013-03-28 13:10:51 +01:00
98976ac56c Fixed NACK handling - Works even with 90% packet loss 2013-03-28 13:00:18 +01:00
42d5296533 Fixed invalid ACK/NACK handling 2013-03-28 11:20:40 +01:00
6260d66bde Updated pthreads version in compiler 2013-03-28 10:59:33 +01:00
2861fe0703 New Plugin format includes multiple API versions 2013-03-27 18:02:10 +01:00
012ecbe40a Fixed #165 2013-03-27 15:53:48 +01:00
c5326131a2 Fixed a server crash related to #162 2013-03-25 20:26:20 +01:00
174160c65c Fixed incorrect gamemode change close message 2013-03-25 19:57:57 +01:00
a5998ff9a2 Start of API 6
Don't try making plugins with this until the stable release
2013-03-25 18:55:25 +01:00
ec5f255a71 Fixed bad PMFLevel::getXZ() logic 2013-03-25 18:54:25 +01:00
e7fcbe206f Create PMF Levels 2013-03-25 18:46:08 +01:00
89b38c25ce Raised ticks directive to 40 2013-03-25 16:46:01 +01:00
88a1f83545 Added protection for fast movements 2013-03-24 11:02:37 +01:00
14ab386b0f Fixed typo 2013-03-23 23:00:23 +01:00
7dbf421e99 Fixed things in PMF Level 2013-03-23 22:46:54 +01:00
0d3624e6a7 :DDDD 2013-03-23 18:27:21 +01:00
14ff3e0a9b Internal API's are now shown as Debug level 2013-03-23 18:26:18 +01:00
ae731c9093 Added the caseusername preference on offline player data 2013-03-23 18:21:40 +01:00
d613fa2138 Fixed Chest Slots not getting sent and shown 2013-03-23 17:44:32 +01:00
5e52bbdd16 Fixed Syntax Error 2013-03-23 17:33:06 +01:00
0b6ff03d5a Revert "API version changed to 6"
This reverts commit 1ff8945015.
2013-03-23 17:32:51 +01:00
1ff8945015 API version changed to 6 2013-03-23 17:18:02 +01:00
a603732bb4 PMF Level reader 2013-03-23 16:59:44 +01:00
23a7847350 Added Plugin List on sendUsage() 2013-03-23 13:14:14 +01:00
f07cd21dd1 Updated PMF 2013-03-23 13:04:02 +01:00
8bbd899689 Fixed #156 2013-03-22 14:44:22 +01:00
2a8c72dfc2 Updated the compile script 2013-03-22 13:51:53 +01:00
59763a35c7 Reverting 75a42ce26c 2013-03-21 17:03:22 +01:00
2e0d49a2ba Moved the RAKNET_MAGIC constant 2013-03-21 17:03:13 +01:00
6e4141f140 Changed the Utils::isOnline() method 2013-03-21 16:27:02 +01:00
75a42ce26c Added reload feature UNTESTED 2013-03-21 22:41:25 +10:30
38d361bb07 Added Wooden Tools Item Settings 2013-03-21 16:50:09 +10:30
13ae305bdd Change to dev version 2013-03-20 19:06:10 +01:00
189 changed files with 11674 additions and 4325 deletions

156
.gitignore vendored
View File

@ -2,130 +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
############
@ -138,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

View File

@ -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
View File

@ -0,0 +1,27 @@
![](http://www.pocketmine.net/favicon.png)
# 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!__

View File

@ -33,7 +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);

View File

@ -1,6 +1,6 @@
![](http://shoghicp.github.com/PocketMine-MP/favicon.png)
![](http://www.pocketmine.net/favicon.png)
# PocketMine-MP [![Build Status](https://travis-ci.org/shoghicp/PocketMine-MP.png?branch=master)](https://travis-ci.org/shoghicp/PocketMine-MP)
# PocketMine-MP [![Build Status](https://travis-ci.org/PocketMine/PocketMine-MP.png?branch=master)](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.net/)
### [FAQ: Frequently Asked Questions](https://github.com/shoghicp/PocketMine-MP/wiki/Frequently-Asked-Questions)
### [Plugin Repository](http://plugins.pocketmine.net/)
### [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)__

View File

@ -1,176 +0,0 @@
#!/bin/bash
COMPILER_VERSION="0.10"
PHP_VERSION="5.4.13"
ZEND_VM="GOTO"
ZLIB_VERSION="1.2.8"
GMP_VERSION="5.1.1"
PTHREADS_VERSION="0d5df071231478ff3b1982eb2b0d96cc24e39d9a"
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 libtool >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"libtool\""; 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"

View File

@ -31,37 +31,39 @@ class BanAPI{
private $banned;
private $ops;
private $bannedIPs;
private $cmdWL = array();
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", "De-ops a player", array($this, "commandHandler"));
$this->server->api->console->register("sudo", "Run a command as 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, "permissionsCheck"), 1);
$this->cmdWhitelist("help");
$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 cmdWhitelist($cmd){
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){
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)){
@ -71,19 +73,38 @@ class BanAPI{
}
public function permissionsCheck($data, $event){
if(isset($this->cmdWhitelist[$data["cmd"]])){
return true;
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->server->api->handle("console.check", $data) === true or $this->isOp($data["issuer"]->iusername)){
return;
}
}elseif($data["issuer"] === "console" or $data["issuer"] === "rcon"){
return;
}
return false;
break;
}
if($data["issuer"] instanceof Player){
if($this->server->api->handle("console.check", $data) === true or $this->isOp($data["issuer"]->username)){
return true;
}
}elseif($data["issuer"] === "console"){
return true;
}
return false;
}
public function commandHandler($cmd, $params, $issuer, $alias){
@ -101,27 +122,35 @@ class BanAPI{
break;
case "op":
$user = strtolower($params[0]);
if($user == ""){
$player = $this->server->api->player->get($user);
if(!($player instanceof Player)){
$this->ops->set($user);
$this->ops->save($user);
$output .= $user." is now op\n";
break;
}
$this->ops->set($user);
$this->ops->set($player->iusername);
$this->ops->save();
$output .= $user." is now op\n";
$this->server->api->chat->sendTo(false, "You are now op.", $user);
$output .= $player->iusername." is now op\n";
$this->server->api->chat->sendTo(false, "You are now op.", $player->iusername);
break;
case "deop":
$user = strtolower($params[0]);
if($user == ""){
$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";
$this->server->api->chat->sendTo(false, "You are not longer op.", $user);
$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 = strtolower(array_shift($params));
$player = $this->server->api->player->get($name);
@ -173,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;
@ -190,6 +219,11 @@ class BanAPI{
case "add":
case "ban":
$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";
@ -201,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;
@ -239,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;
@ -248,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 = "No Reason"){
$this->commandHandler("kick", array($username, $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){
@ -294,7 +328,9 @@ class BanAPI{
public function inWhitelist($username){
$username = strtolower($username);
if($this->server->api->dhandle("api.ban.whitelist.check", $ip) === false){
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;

View File

@ -25,18 +25,125 @@ 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, $multiple = false){
if($multiple === true){
@ -73,7 +180,7 @@ class BlockAPI{
}else{
$b = new GenericBlock($id, $meta);
}
if($v instanceof Vector3){
if($v instanceof Position){
$b->position($v);
}
return $b;
@ -90,35 +197,13 @@ class BlockAPI{
return $i;
}
public function setBlock(Vector3 $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){
@ -126,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])){
@ -138,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;
@ -150,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,
@ -158,74 +251,57 @@ 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;
$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);
return $this->cancelAction($target, $player, false);
}
if(!$target->isBreakable($item, $player) or $player->gamemode === ADVENTURE or ($player->lastBreak + $target->getBreakTime($item, $player)) >= microtime(true)){
return $this->cancelAction($target, $player);
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);
}
if($item->useOn($target) and ($player->gamemode & 0x01) === 0 and $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($player->gamemode !== CREATIVE and 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){
if($item->getID() === AIR or $item->count <= 0){
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("item.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);
}
@ -233,67 +309,68 @@ class BlockAPI{
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(($player->gamemode & 0x02) === 0x02){ //Adventure mode!!
return $this->cancelAction($block, $player, false);
}
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);
return true;
}
/*
public function flowLavaOn($source, $face){
$down = 0;
@ -640,25 +717,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){
@ -667,14 +725,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 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]);
}
}
}
}
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);
}
}
}

View File

@ -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));
}
}

View File

@ -27,65 +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->register("help", "Show available commands", array($this, "defaultCommands"));
$this->register("status", "Show server TPS and memory usage", array($this, "defaultCommands"));
$this->alias("lag", "status");
$this->register("difficulty", "Changes server difficulty", array($this, "defaultCommands"));
$this->register("invisible", "Changes server visibility", array($this, "defaultCommands"));
$this->register("say", "Broadcast a message", array($this, "defaultCommands"));
$this->register("save-all", "Save pending changes to disk", array($this, "defaultCommands"));
$this->register("stop", "Stops the server gracefully", array($this, "defaultCommands"));
$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";
break;
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);
}
@ -102,42 +97,50 @@ class ConsoleAPI{
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";
break;
}
$this->server->api->chat->broadcast("[Server] ".$s);
break;
case "save-all":
$this->server->save();
break;
case "?":
if($issuer !== "console"){
if($issuer !== "console" and $issuer !== "rcon"){
break;
}
case "help":
$max = ceil(count($this->help) / 5);
$page = isset($params[0]) ? min($max - 1, max(0, intval($params[0]) - 1)):0;
$output .= "- Showing help page ". ($page + 1) ." of $max (/help <page>) -\n";
$current = 0;
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){
$curpage = (int) ($current / 5);
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";
$output .= "/$c ".$h."\n";
}elseif($curpage > $page){
break;
}
}
++$current;
}
break;
@ -163,38 +166,92 @@ class ConsoleAPI{
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;
}
}
@ -202,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();
}
@ -211,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;
$this->wait();
$this->line = false;
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);
}
}
}

View File

@ -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 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 getAll(){
return $this->server->entities;
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;
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 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);
}
}
$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 and $player->eid !== $eid){
public function spawnAll(Player $player){
foreach($this->getAll($player->level) as $e){
if($e->class !== ENTITY_PLAYER){
$e->spawn($player);
}
}
}
public function spawnAll($player){
foreach($this->getAll() as $e){
$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);

View File

@ -26,120 +26,221 @@ 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->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){
}
}
public function saveAll(){
foreach($this->levels as $level){
$level->save();
}
}
public function __destruct(){
$this->saveAll();
foreach($this->levels as $level){
$this->unloadLevel($level, true);
}
}
public function getSpawn(){
return $this->server->spawn;
}
public function getChunk($X, $Z){
return $this->map->map[$X][$Z];
}
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();
}
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();
}
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;
}
}

View File

@ -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(){
}
}
}

View File

@ -27,84 +27,92 @@ 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("gamemode", "Changes the player gamemode", 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){
while(($player = $result->fetchArray()) !== false){
if(($player = $this->server->api->entity->get($player["EID"])) !== false){
if($player->getHealth() <= 0){
continue;
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){
continue;
}
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
}
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
}
return true;
}
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"]);
switch($e->class){
case ENTITY_PLAYER:
$message .= " was killed by ".$e->name;
break;
default:
$message .= " was killed";
break;
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;
break;
default:
$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";
$message = " hit the ground too hard";
break;
case "flying":
$message .= " tried to fly up to the sky";
break;
default:
$message .= " died";
$message = " died";
break;
}
}
$this->server->chat(false, $message);
$this->server->api->chat->broadcast($data["player"]->username . $message);
return true;
break;
}
@ -113,62 +121,117 @@ class PlayerAPI{
public function commandHandler($cmd, $params, $issuer, $alias){
$output = "";
switch($cmd){
case "gamemode":
$gm = -1;
$player = false;
if(!isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
$player = $issuer;
$gm = (int) $params[1];
}elseif(isset($params[1]) and isset($params[0])){
$player = $this->server->api->player->get($params[0]);
$gm = (int) $params[1];
}
if(!($player instanceof Player) or $gm < 0 or $gm > 2){
$output .= "Usage: /gamemode [player] <0 | 1 | 2>\n";
case "spawnpoint":
if(!($issuer instanceof Player)){
$output .= "Please run this command in-game.\n";
break;
}
}
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($player->setGamemode($gm)){
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(!isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
$name = $issuer->username;
$target = $params[1];
}elseif(isset($params[1]) and isset($params[0])){
$name = $params[0];
$target = $params[1];
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";
}
}else{
$output .= "Usage: /tp [player] <target>\n";
break;
}
if($this->teleport($name, $target)){
$output .= "\"$name\" teleported to \"$target\"\n";
}else{
$output .= "Couldn't teleport\n";
}
break;
case "tppos":
if(!isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0]) and ($issuer instanceof Player)){
$name = $issuer->username;
$x = (float) $params[0];
$y = (float) $params[1];
$z = (float) $params[2];
}elseif(isset($params[3]) and isset($params[2]) and isset($params[1]) and isset($params[0])){
$name = $params[0];
$x = (float) $params[1];
$y = (float) $params[2];
$z = (float) $params[3];
}else{
$output .= "Usage: /tp [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";
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";
}
}
break;
case "kill":
@ -179,65 +242,106 @@ class PlayerAPI{
$player = $this->get($params[0]);
}
if($player instanceof Player){
$this->server->api->entity->harm($player->eid, 20, "console", true);
$player->entity->harm(1000, "console", true);
$player->sendChat("Ouch. That looks like it hurt.\n");
}else{
$output .= "Usage: /kill [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)){
$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 = '".$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];
}
@ -257,17 +361,60 @@ 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);
$player->gamemode = $player->data->get("gamemode");
$this->server->query("INSERT OR REPLACE INTO players (clientID, ip, port, name) VALUES (".$player->clientID.", '".$player->ip."', ".$player->port.", '".$player->username."');");
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,
));
}
}
}
}
public function remove($CID){
if(isset($this->server->clients[$CID])){
$player = $this->server->clients[$CID];
$this->server->clients[$CID] = null;
unset($this->server->clients[$CID]);
$player->close();
if($player->username != "" and ($player->data instanceof Config)){
@ -275,8 +422,8 @@ class PlayerAPI{
}
$this->server->query("DELETE FROM players WHERE name = '".$player->username."';");
if($player->entity instanceof Entity){
$player->entity->player = null;
$player->entity = null;
unset($player->entity->player);
unset($player->entity);
}
$this->server->api->entity->remove($player->eid);
$player = null;
@ -287,24 +434,36 @@ class PlayerAPI{
public function getOffline($name){
$iname = strtolower($name);
$default = array(
"caseusername" => $name,
"position" => array(
"x" => $this->server->spawn["x"],
"y" => $this->server->spawn["y"],
"z" => $this->server->spawn["z"],
"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,
);
$data = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
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 = new Config(DATA_PATH."players/".$iname.".yml", CONFIG_YAML, $default);
}
if($this->server->gamemode === CREATIVE){
if(($this->server->gamemode & 0x01) === 0x01){
$data->set("health", 20);
}
$this->server->handle("player.offline.get", $data);

View File

@ -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(){
@ -56,9 +56,9 @@ class PluginAPI extends stdClass{
}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();
@ -82,35 +82,39 @@ class PluginAPI extends stdClass{
$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"]." #".intval($info["apiversion"])."\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($info["code"]) === 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 = $info["class"];
if(isset($info["apiversion"]) and intval($info["apiversion"]) > CURRENT_API_VERSION){
console("[ERROR] [PluginAPI] Plugin \"".$info["name"]."\" uses a newer API! It can crash or corrupt the server!");
}elseif(!isset($info["apiversion"]) or intval($info["apiversion"]) < CURRENT_API_VERSION){
console("[DEBUG] [PluginAPI] Plugin \"".$info["name"]."\" uses an old API", true, true, 2);
$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!");
}
$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");
if(method_exists($object, "__destruct")){
$object->__destruct();
if($info["class"] !== "none"){
$object = new $className($this->server->api, false);
if(!($object instanceof Plugin)){
console("[ERROR] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" doesn't use the Plugin Interface");
if(method_exists($object, "__destruct")){
$object->__destruct();
}
$object = null;
unset($object);
}else{
$this->plugins[$className] = array($object, $info);
}
$object = null;
unset($object);
}else{
$this->plugins[$className] = array($object, $info);
$this->plugins[md5($info["name"])] = array(new DummyPlugin($this->server->api, false), $info);
}
}
@ -130,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;
}
@ -138,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;
@ -173,7 +176,6 @@ class PluginAPI extends stdClass{
}
public function loadAll(){
console("[INFO] Loading Plugins...");
$dir = dir(DATA_PATH."plugins/");
while(false !== ($file = $dir->read())){
if($file{0} !== "."){
@ -186,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!!
}
@ -197,4 +200,15 @@ interface Plugin{
public function __construct(ServerAPI $api, $server = false);
public function init();
public function __destruct();
}
class DummyPlugin implements Plugin{
public function __construct(ServerAPI $api, $server = false){
}
public function init(){
}
public function __destruct(){
}
}

View File

@ -26,106 +26,83 @@ 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" => 1,
"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);
$this->server->api = $this;
$gitsha1 = false;
if(file_exists(FILE_PATH.".git/refs/heads/master")){ //Found Git information!
$gitsha1 = trim(file_get_contents(FILE_PATH.".git/refs/heads/master"));
console("[GIT] Commit \x1b[33m".$gitsha1);
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");
@ -135,12 +112,11 @@ class ServerAPI{
console("[ERROR] PocketMine API error");
}else{
$last = $info["development"]["date"];
if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false and $gitsha1 != $info["development"]["commit"]){
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");
@ -157,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");
@ -204,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"))){
@ -215,51 +164,77 @@ class ServerAPI{
}
$this->loadAPI("plugin", "PluginAPI"); //fix :(
$this->plugin->init();
$this->server->loadEntities();
}
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;
}
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://stats.pocketmine.net/usage.php", array(
"serverid" => $this->server->serverID,
"os" => Utils::getOS(),
"version" => MAJOR_VERSION,
"protocol" => CURRENT_PROTOCOL,
"online" => count($this->server->clients),
"max" => $this->server->maxClients,
));
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");
@ -286,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":
@ -300,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);
}
@ -332,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);
}
@ -351,56 +342,12 @@ class ServerAPI{
public function deleteEvent($id){
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":
@ -424,7 +371,7 @@ class ServerAPI{
break;
case "gamemode":
case "max-players":
case "port":
case "server-port":
case "debug":
case "difficulty":
case "time-per-second":
@ -438,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){
@ -455,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";
@ -464,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
View 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);
}
}
}

View File

@ -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[$id];
$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);
}
}
}

View File

@ -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,13 +121,17 @@ 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();
}
}
}

View File

@ -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;
}
}

View File

@ -28,6 +28,8 @@ 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",

File diff suppressed because it is too large Load Diff

View File

@ -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();
@ -99,45 +95,62 @@ class PocketMinecraftServer{
}
public function titleTick(){
$time = microtime(true);
if(ENABLE_ANSI === true){
echo "\x1b]0;PocketMine-MP ".MAJOR_VERSION." | Online ". count($this->clients)." | RAM ".round((memory_get_usage(true) / 1024) / 1024, 2)."MB | TPS ".$this->getTPS()."\x07";
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->action(1500000, '$this->titleTick();');
$this->schedule(30, array($this, "titleTick"), array(), true);
}
$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 * 15, 'if($this->getTPS() < 15){console("[WARNING] Can\'t keep up! Is the server overloaded?");}');
$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()));}');
$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;
}
}
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 COLLATE NOCASE);");
$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;
@ -150,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"];
@ -167,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":
@ -200,6 +211,59 @@ class PocketMinecraftServer{
}
}
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)){
@ -218,6 +282,10 @@ class PocketMinecraftServer{
console("[INTERNAL] New handler ".(is_array($callable) ? get_class($callable[0])."::".$callable[1]:$callable)." to special event ".$event." (ID ".$hnid.")", true, true, 3);
return $hnid;
}
public function dhandle($e, $d){
return $this->handle($e, $d);
}
public function handle($event, &$data){
$this->preparedSQL->selectHandlers->reset();
@ -225,8 +293,7 @@ class PocketMinecraftServer{
$this->preparedSQL->selectHandlers->bindValue(":name", $event, SQLITE3_TEXT);
$handlers = $this->preparedSQL->selectHandlers->execute();
$result = null;
if($handlers !== false and $handlers !== true){
console("[INTERNAL] Handling ".$event, true, true, 3);
if($handlers instanceof SQLite3Result){
$call = array();
while(($hn = $handlers->fetchArray(SQLITE3_ASSOC)) !== false){
$call[(int) $hn["ID"]] = true;
@ -266,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:
@ -313,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 * 25, '$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);
public function init(){
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")){
@ -456,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";
@ -481,68 +429,67 @@ 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;
}
@ -555,42 +502,24 @@ class PocketMinecraftServer{
$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"]),
@ -598,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(){
@ -664,46 +586,44 @@ class PocketMinecraftServer{
}
}
public function schedule($ticks,callable $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;
}
while(($action = $actions->fetchArray(SQLITE3_ASSOC)) !== false){
$return = eval(base64_decode($action["code"]));
if($action["repeat"] === 0 or $return === false){
$this->query("DELETE FROM actions WHERE ID = ".$action["ID"].";");
if($actions instanceof SQLite3Result){
while(($action = $actions->fetchArray(SQLITE3_ASSOC)) !== false){
$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();
}
$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,callable $func){

267
src/build/compile.sh Executable file
View 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"

View File

@ -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.2");
define("CURRENT_STRUCTURE", 5);
define("CURRENT_PROTOCOL", 9);
define("CURRENT_MINECRAFT_VERSION", "v0.6.1 alpha");
define("CURRENT_API_VERSION", 5);
define("CURRENT_PHP_VERSION", "5.4.13");
define("START_TIME", microtime(true));
define("MAJOR_VERSION", "Alpha_1.3.5");
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));
}

View File

@ -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);

View File

@ -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("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);

View File

@ -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,8 +147,10 @@ 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);
define("CAMERA", 456);
define("CAMERA", 456);

View File

@ -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***/

View File

@ -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){
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 false;
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){

View File

@ -31,8 +31,8 @@ define("WINDOW_FURNACE", 2);
class Window{
private $server;
public function __construct(PocketMinecraftServer $server){
public function __construct(){
$this->server = ServerAPI::request();
}
}

View File

@ -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***/

View File

@ -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,154 @@ 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++;
}
return true;
}
return false;
}
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,8 +270,8 @@ 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;
}
}
}

View File

@ -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){
if(($this->meta & 0x08) === 0x08){
$down = $level->getBlockFace($this, 0);
if($down->getID() === $this->id){
$level->setBlock($down, 0, 0);
}
}else{
$up = $level->getBlockFace($this, 1);
if($up->getID() === $this->id){
$level->setBlock($up, 0, 0);
}
public function onBreak(Item $item, Player $player){
if(($this->meta & 0x08) === 0x08){
$down = $this->getSide(0);
if($down->getID() === $this->id){
$this->level->setBlock($down, new AirBlock());
}
}else{
$up = $this->getSide(1);
if($up->getID() === $this->id){
$this->level->setBlock($up, new AirBlock());
}
$level->setBlock($this, 0, 0);
return true;
}
return false;
$this->level->setBlock($this, new AirBlock());
return true;
}
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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -31,5 +31,7 @@ class LiquidBlock extends TransparentBlock{
$this->isLiquid = true;
$this->breakable = false;
$this->isReplaceable = true;
$this->isSolid = false;
$this->isFullBlock = true;
}
}

View File

@ -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;
}
}

View File

@ -28,29 +28,35 @@ 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){
$faces = array(
0 => 0,
1 => 2,
2 => 1,
3 => 3,
);
$this->meta = $faces[$player->entity->getDirection()] & 0x03;
if(($fy > 0.5 and $face !== 1) or $face === 0){
$this->meta |= 0x04; //Upside-down stairs
}
$level->setBlock($block, $this->id, $this->meta);
return true;
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
$faces = array(
0 => 0,
1 => 2,
2 => 1,
3 => 3,
);
$this->meta = $faces[$player->entity->getDirection()] & 0x03;
if(($fy > 0.5 and $face !== 1) or $face === 0){
$this->meta |= 0x04; //Upside-down stairs
}
return false;
$this->level->setBlock($block, $this);
return true;
}
public function getDrops(Item $item, Player $player){
return array(
array($this->id, 0, 1),
);
if($item->isPickaxe() >= 1){
return array(
array($this->id, 0, 1),
);
}else{
return array();
}
}
}

View File

@ -33,6 +33,7 @@ class TransparentBlock extends GenericBlock{
$this->isFlowable = false;
$this->isTransparent = true;
$this->isReplaceable = false;
$this->isPlaceable = true;
$this->isPlaceable = true;
$this->isSolid = true;
}
}

View File

@ -28,17 +28,20 @@ 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){
if($target->isTransparent === false){
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
if($target->isTransparent === false){
$faces = array(
2 => 2,
3 => 3,
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;
}
}

View File

@ -28,37 +28,46 @@ 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){
if($face !== 0){
$faces = array(
2 => 2,
3 => 3,
4 => 4,
5 => 5,
);
if(!isset($faces[$face])){
$b = floor((($player->entity->yaw + 180) * 16 / 360) + 0.5) & 0x0F;
$level->setBlock($block, SIGN_POST, $b);
return true;
}else{
$level->setBlock($block, WALL_SIGN, $faces[$face]);
return true;
}
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
if($face !== 0){
$faces = array(
2 => 2,
3 => 3,
4 => 4,
5 => 5,
);
if(!isset($faces[$face])){
$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{
$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(

View File

@ -30,22 +30,47 @@ 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){
$faces = array(
1 => 5,
2 => 4,
3 => 3,
4 => 2,
5 => 1,
);
$level->setBlock($block, $this->id, $faces[$face]);
return true;
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,
3 => 3,
4 => 2,
5 => 1,
);
$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;
}
public function getDrops(Item $item, Player $player){
return array(
array($this->id, 0, 1),

View File

@ -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;
}
}

View File

@ -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),
);
}
}

View File

@ -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");
}
}

View File

@ -28,6 +28,90 @@ the Free Software Foundation, either version 3 of the License, or
class WaterBlock extends LiquidBlock{
public function __construct($meta = 0){
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;
}
}

View File

@ -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;
}
}

View File

@ -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,55 +49,47 @@ 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;
}
return true;
$this->level->setBlock($blockWest, new AirBlock());
}
}
return false;
}
$this->level->setBlock($this, new AirBlock());
return true;
}
public function getDrops(Item $item, Player $player){

View File

@ -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;
}
}

View File

@ -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),
);
}
}

View 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;
}
}

View File

@ -27,8 +27,9 @@ 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;
parent::__construct(COBWEB, 0, "Cobweb");
$this->isSolid = true;
$this->isFullBlock = false;
}
public function getDrops(Item $item, Player $player){
return array();

View File

@ -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;
}
}

View File

@ -29,27 +29,29 @@ class FenceGateBlock extends TransparentBlock{
public function __construct($meta = 0){
parent::__construct(FENCE_GATE, $meta, "Fence Gate");
$this->isActivable = true;
}
public function place(BlockAPI $level, Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
if($block->inWorld === true){
$faces = array(
0 => 3,
1 => 0,
2 => 1,
3 => 2,
);
$this->meta = $faces[$player->entity->getDirection()] & 0x03;
$level->setBlock($block, $this->id, $this->meta);
return true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
}else{
$this->isFullBlock = false;
}
return false;
}
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
$faces = array(
0 => 3,
1 => 0,
2 => 1,
3 => 2,
);
$this->meta = $faces[$player->entity->getDirection()] & 0x03;
$this->level->setBlock($block, $this);
return true;
}
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;
}
}

View 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();
}
}
}

View File

@ -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";
$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){
return array(
array($this->id, $this->meta & 0x07, 1),
);
}
if($item->isPickaxe() >= 1){
return array(
array($this->id, $this->meta & 0x07, 1),
);
}else{
return array();
}
}
}

View 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),
);
}
}
}

View File

@ -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();

View File

@ -30,13 +30,27 @@ 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();
}
}
}
}

View File

@ -29,5 +29,40 @@ class GlowingRedstoneOreBlock extends SolidBlock{
public function __construct(){
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();
}
}
}

View File

@ -29,5 +29,28 @@ class GoldOreBlock extends SolidBlock{
public function __construct(){
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();
}
}
}

View File

@ -29,5 +29,30 @@ class IronOreBlock extends SolidBlock{
public function __construct(){
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();
}
}
}

View File

@ -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();

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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),
);
}
}

View File

@ -28,16 +28,25 @@ 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;
}
}
}

View File

@ -28,16 +28,25 @@ 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;
}
}
}

View File

@ -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;
}
}

View File

@ -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 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(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;

View File

@ -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;
}
}

View File

@ -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);
if($down->getID() === GRASS or $down->getID() === DIRT or $down->getID() === FARMLAND){
$level->setBlock($block, $this->id, $this->getMetadata());
return true;
}
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){
$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;
}
if($type === BLOCK_UPDATE_RANDOM and mt_rand(0,2) === 0){ //Growth
if(($this->meta & 0x08) === 0x08){
TreeObject::growTree($level, $this);
}else{
$this->meta |= 0x08;
$this->level->setBlock($this->x, $this->y, $this->z, $this->id, $this->meta);
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;
}
}elseif($type === BLOCK_UPDATE_RANDOM){ //Growth
if(mt_rand(1,7) === 1){
if(($this->meta & 0x08) === 0x08){
TreeObject::growTree($this->level, $this, new Random(), $this->meta & 0x03);
}else{
$this->meta |= 0x08;
$this->level->setBlock($this, $this);
return BLOCK_UPDATE_RANDOM;
}
}else{
return BLOCK_UPDATE_RANDOM;
}
return true;
}
return false;
}

View File

@ -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){
@ -35,36 +35,56 @@ class SugarcaneBlock extends TransparentBlock{
array(SUGARCANE, 0, 1),
);
}
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;
}
}

View File

@ -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",
@ -37,11 +36,21 @@ 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;
}

View File

@ -31,24 +31,48 @@ 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);
if($down->getID() === FARMLAND){
$level->setBlock($block, $this->id, $this->getMetadata());
return true;
}
public function place(Item $item, Player $player, Block $block, Block $target, $face, $fx, $fy, $fz){
$down = $this->getSide(0);
if($down->getID() === FARMLAND){
$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();

View File

@ -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;

View File

@ -29,5 +29,34 @@ class BricksBlock extends SolidBlock{
public function __construct(){
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();
}
}
}

View File

@ -25,60 +25,38 @@ 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){
$faces = array(
0 => 4,
1 => 2,
2 => 5,
3 => 3,
);
$level->setBlock($block, $this->id, $faces[$player->entity->getDirection()]);
return true;
}
return false;
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,
);
$this->meta = $faces[$player->entity->getDirection()];
$this->level->setBlock($block, $this);
return true;
}
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_FURNACE){
$server->api->tileentity->remove($ts->id);
}
}
}elseif($t->class === TILE_FURNACE){
$server->api->tileentity->remove($t->id);
}
}
$level->setBlock($this, 0, 0);
return true;
}
return false;
public function onBreak(Item $item, Player $player){
$this->level->setBlock($this, new AirBlock(), true, true);
return true;
}
public function onActivate(BlockAPI $level, Item $item, Player $player){
public function onActivate(Item $item, Player $player){
$server = ServerAPI::request();
$t = $server->api->tileentity->get($this);
$t = $server->api->tile->get($this);
$furnace = false;
if($t !== false){
if(is_array($t)){
$furnace = array_shift($t);
}else{
$furnace = $t;
}
$furnace = $t;
}else{
$furnace = $server->api->tileentity->add(TILE_FURNACE, $this->x, $this->y, $this->z, 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,
@ -87,39 +65,69 @@ class BurningFurnaceBlock extends SolidBlock{
));
}
if($furnace->class !== TILE_FURNACE){
return false;
if($furnace->class !== TILE_FURNACE 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] = $furnace;
$player->dataPacket(MC_CONTAINER_OPEN, array(
"windowid" => $id,
"type" => WINDOW_FURNACE,
"slots" => 3,
"slots" => FURNACE_SLOTS,
"title" => "Furnace",
));
for($s = 0; $s < 3; ++$s){
$slots = array();
for($s = 0; $s < FURNACE_SLOTS; ++$s){
$slot = $furnace->getSlot($s);
if($slot->getID() > 0 and $slot->count > 0){
$player->dataPacket(MC_CONTAINER_SET_SLOT, array(
"windowid" => $id,
"slot" => $s,
"block" => $slot->getID(),
"stack" => $slot->count,
"meta" => $slot->getMetadata(),
));
$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){
if($item->isPickaxe() >= 1){
return array(
array(FURNACE, 0, 1),
);
}else{
return array();
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;
}
}

View File

@ -25,72 +25,77 @@ 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){
$block0 = $level->getBlockFace($block, 2);
$block1 = $level->getBlockFace($block, 3);
$block2 = $level->getBlockFace($block, 4);
$block3 = $level->getBlockFace($block, 5);
if($block0->getID() !== CHEST and $block1->getID() !== CHEST and $block2->getID() !== CHEST and $block3->getID() !== CHEST){
$faces = array(
0 => 4,
1 => 2,
2 => 5,
3 => 3,
);
$level->setBlock($block, $this->id, $faces[$player->entity->getDirection()]);
$server = ServerAPI::request();
$server->api->tileentity->add(TILE_CHEST, $this->x, $this->y, $this->z, array(
"Items" => array(),
"id" => TILE_CHEST,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z
));
return 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,
);
$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;
}
}
return false;
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->tile->add($this->level, TILE_CHEST, $this->x, $this->y, $this->z, array(
"Items" => array(),
"id" => TILE_CHEST,
"x" => $this->x,
"y" => $this->y,
"z" => $this->z
));
return true;
}
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;
}
public function onActivate(Item $item, Player $player){
$top = $this->getSide(1);
if($top->isTransparent !== true){
return true;
}
return false;
}
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;
}
$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,
@ -99,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",
));
for($s = 0; $s < 3; ++$s){
$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() > 0 and $slot->count > 0){
$player->dataPacket(MC_CONTAINER_SET_SLOT, array(
"windowid" => $id,
"slot" => $s,
"block" => $slot->getID(),
"stack" => $slot->count,
"meta" => $slot->getMetadata(),
));
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;
}
}

View File

@ -29,5 +29,10 @@ class ClayBlock extends SolidBlock{
public function __construct(){
parent::__construct(CLAY_BLOCK, 0, "Clay Block");
}
public function getDrops(Item $item, Player $player){
return array(
array(CLAY, 0, 4),
);
}
}

View File

@ -29,5 +29,34 @@ class CobblestoneBlock extends SolidBlock{
public function __construct(){
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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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){
return array(
array(SLAB, $this->meta & 0x07, 2),
);
if($item->isPickaxe() >= 1){
return array(
array(SLAB, $this->meta & 0x07, 2),
);
}else{
return array();
}
}
}

View File

@ -37,5 +37,4 @@ class FurnaceBlock extends BurningFurnaceBlock{
$this->name = "Furnace";
$this->isActivable = true;
}
}

View File

@ -29,5 +29,10 @@ class GlowstoneBlock extends SolidBlock{
public function __construct(){
parent::__construct(GLOWSTONE_BLOCK, 0, "Glowstone");
}
public function getDrops(Item $item, Player $player){
return array(
array(GLOWSTONE_DUST, 0, mt_rand(2, 4)),
);
}
}

View File

@ -29,5 +29,28 @@ class GoldBlock extends SolidBlock{
public function __construct(){
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();
}
}
}

View File

@ -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;

View File

@ -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