Compare commits

..

405 Commits

Author SHA1 Message Date
e44ed4da3b Enabled batch block sending again 2014-11-29 12:58:31 +01:00
a72488d41e Updated player movement processing and event handling 2014-11-29 12:43:34 +01:00
3930f379cf Updated light filter values 2014-11-29 11:58:50 +01:00
66ba327e62 Improved light spread algorithm even more 2014-11-29 11:27:22 +01:00
329ca62465 Improved light spread algorithm 2014-11-28 19:54:25 +01:00
26e47ef694 Removed old revert flag from Player->processMovement() 2014-11-28 14:49:06 +01:00
61ea149ff0 API 1.8.0 2014-11-28 14:44:56 +01:00
b3c3f896a3 Implemented light population, added Level->getFullLight() 2014-11-28 14:44:27 +01:00
d139e5f342 Removed temporal pthreads workaround 2014-11-28 13:01:25 +01:00
3abf36ad07 Fixed invalid worlds property being set by users 2014-11-28 12:47:28 +01:00
0bc9a9bdab Fixed armor dropping twice 2014-11-27 23:19:46 +01:00
98340522d9 Fixed items getting added on the same empty slot 2014-11-27 20:49:18 +01:00
6d09754ea7 Improved Inventory->addItem(), fixed breaking containers duplicating the last slot, removed not necessary slot changes 2014-11-27 20:10:55 +01:00
a3b1d318cc Fixed ladder crafting recipe 2014-11-27 20:02:38 +01:00
f866efb622 Removed unused Block->isLiquid property 2014-11-27 17:26:43 +01:00
b1c4578726 Fixed #2340 2014-11-27 16:18:43 +01:00
f4181a6e36 Bump Minecraft: PE version 2014-11-27 14:37:44 +01:00
38089af098 Improved global entity motion encoding using per-player queues 2014-11-27 14:26:36 +01:00
cd135b39ad Improved player spawn item in hand sending 2014-11-27 13:59:32 +01:00
dd3207cbd8 Possible fix for #2267, #2314 2014-11-27 13:47:17 +01:00
a7abd5ff9d Catch exceptions when chunks are unloaded 2014-11-27 13:35:54 +01:00
a3e50f6337 Properly close inventory windows from Players 2014-11-27 13:32:07 +01:00
441a98e60a Removed old trigger_error() calls, closes #2335 2014-11-27 13:16:39 +01:00
4a90ac270f Improved exception handling and debugging 2014-11-22 13:52:36 +01:00
a906a2988b Bumped Minecraft: PE version string 2014-11-22 13:44:34 +01:00
545f68382c Increased Fence, Fence Gate and Stone Wall Y bounding box 2014-11-22 13:44:05 +01:00
8249cac592 Catch corrupted chunk data errors 2014-11-20 22:02:00 +01:00
7b7bbe9105 Regenerate corrupt player data if invalid data is found 2014-11-20 21:58:27 +01:00
05679c7872 Merge branch 'master' of github.com:PocketMine/PocketMine-MP 2014-11-20 21:46:14 +01:00
8eb80be691 Remove duplicated tiles from chunk table automatically 2014-11-20 21:45:52 +01:00
f55b0d0b45 Merge pull request #2295 from LukeDarling/patch-1
Fixed Server->getOps() capitalization
2014-11-19 13:10:03 +01:00
754e0dbb49 Protect permission removal against bad plugins 2014-11-18 18:43:30 +01:00
525c8db779 Improved chunk loading/unloading 2014-11-18 18:33:24 +01:00
c7f578f297 Possible fix for #2297 2014-11-18 13:57:03 +01:00
19c030281f Fixed #1969 2014-11-18 13:53:38 +01:00
ca9fe1b89a Improved and fixed command exception message, closes #2301 2014-11-18 13:46:00 +01:00
9fd6a695f6 Fixed permission-related memory leak 2014-11-18 13:42:24 +01:00
c07b0ff35b Fixed tile entities not being placed in the correct array 2014-11-15 11:49:09 +01:00
00be3f0dd3 Fixed Server->getOps() capitalization
I'm not 100% sure, but I believe this is how it's supposed to be.
2014-11-15 00:01:57 -05:00
6796fca2b6 Merge pull request #2294 from LukeDarling/patch-1
fixed version message color
2014-11-15 14:20:14 +10:30
5657cce3db fixed version message color 2014-11-14 15:52:38 -05:00
05ac256cc3 Fixed Acacia / Dark Oak logs crafting recipes 2014-11-14 15:58:31 +01:00
49977c5410 Bumped weakref version, fixes travis builds 2014-11-14 10:30:06 +01:00
ca40bb678c Merge pull request #2288 from sekjun9878/master
Get timezone directly. Fixes #2287.
2014-11-13 23:08:22 +10:30
2068cc9cdf Merge pull request #2243 from PEMapModder/patch-1
cmd files comment syntax should be like this.
2014-11-13 21:42:25 +10:30
ea4617cedd Get timezone directly. Fixes #2287. 2014-11-13 21:13:12 +10:30
1a5544f68c Fixed Chunk tile indexes 2014-11-08 15:00:18 +01:00
0128a7aeb2 API version 1.7.1 (fixes) 2014-11-07 09:45:30 +01:00
fd954ce708 Fixed PlayerInventory->setItem() with null items 2014-11-07 09:43:36 +01:00
d63a82de0a MCPE protocol 20 2014-11-06 19:08:32 +01:00
92143d523c Added SetDifficultyPacket 2014-11-06 19:07:24 +01:00
1818e64c8e Merge branch 'master' into 0.10 2014-11-06 18:56:47 +01:00
7e1095e28d Reenabled collision against entities on move 2014-11-06 12:57:17 +01:00
f1519e6d13 Improved Level->getTile() to a direct lookup instead of linear search 2014-11-06 12:34:33 +01:00
3b9a9bcd5d Use proper indexes on Living->getLineOfSight() when a max length is set 2014-11-06 12:23:45 +01:00
263bff01c8 Change RuntimeException to InvalidStateException on BlockIterator 2014-11-06 12:16:12 +01:00
987d647b76 Return proper BlockIterator index, throw more exceptions, improved blockQueue performance 2014-11-06 12:12:31 +01:00
522b75645c Merge branch 'master' into 0.10 2014-11-05 19:04:36 +01:00
9eed0a579c Fixed red sand smelting recipe 2014-11-05 17:41:12 +01:00
064976d32b Fixed ladder recipe 2014-11-05 17:38:23 +01:00
2abb577178 Fixed String -> Wool recipe 2014-11-05 17:36:44 +01:00
127855c220 Fixed Snow block recipe 2014-11-05 17:36:06 +01:00
93c7a3c170 Fixed bonemeal recipe, closes #2260 2014-11-05 17:32:28 +01:00
31903a764a Fixed unloaded chunks residing on memory and getting loaded again causing crash, fixed spawn chunks getting unloaded by players 2014-11-04 17:16:02 +01:00
79bc1d6c85 Fixed server not stopping after a special crash 2014-11-04 17:15:20 +01:00
cc7f12739d Added vertical and horizontal collision detection to Entities 2014-11-04 12:23:42 +01:00
32dae93ef9 Removed unused imports 2014-11-04 12:08:24 +01:00
8fd6582e74 Automatically set Entity / Tile entity save identifiers 2014-11-04 12:04:08 +01:00
a5369b3570 Fixed unloading chunks 2014-11-04 11:18:34 +01:00
abbd33210a Possible fix for #2245 2014-11-04 00:19:50 +01:00
6b6222c09c Allow passing a Player source as last parameter on Inventory->addItem() and Inventory->removeItem() 2014-11-04 00:16:25 +01:00
a8c997d88a ¬¬ 2014-11-03 12:54:46 +01:00
6993718a83 Added EntityDamageByChildEntityEvent 2014-11-03 12:03:37 +01:00
86afecec89 Improved inventory sending, send single slots instead of full inventory as much as possible 2014-11-03 11:48:10 +01:00
29d1fd1fc8 Fixed player viewer list including themselves 2014-11-03 11:29:01 +01:00
af4eb2ab1e Create server.log properly on non-existent directories 2014-11-02 16:15:15 +01:00
f7baf46a54 Fire PlayerInteractEvent on 0xff face 2014-11-02 16:12:51 +01:00
75c0d8324c Fixed some inventory events not firing on players 2014-11-02 13:26:58 +01:00
da4334f06b Revert Armor then Inventory instead of Inventory then Armor on failed transaction 2014-11-01 23:02:59 +01:00
413bd3c0df Use SplFixedArray for improved performance 2014-11-01 22:12:35 +01:00
1a0428654b Updated timings command, give direct link to results 2014-11-01 21:20:44 +01:00
2803a38fd1 Fixed random block updates not firing 2014-11-01 20:26:13 +01:00
95a5ca7889 Added command message to /time add 2014-11-01 20:12:55 +01:00
240f14c425 Fixed #2253 2014-11-01 19:40:15 +01:00
cb9b6ab1d1 Fixed server not using the correct provided path if it did not exist 2014-11-01 19:23:10 +01:00
8a87280566 Added /time start and /time stop 2014-11-01 17:45:11 +01:00
4d97827d44 Improved level switching for players 2014-11-01 17:39:09 +01:00
f8f1e0e9df Despawn entities correctly from clients as they move 2014-11-01 16:47:40 +01:00
bf596ebf05 Fixed Query-related crash 2014-11-01 16:20:40 +01:00
90777014b6 Fixed Stone crash 2014-11-01 16:17:47 +01:00
4a78ffd2dd Fixed FallingSand crash 2014-11-01 16:15:09 +01:00
7c361a52d2 Fixed #2252 2014-11-01 13:52:20 +01:00
13fc0df92c Fixed #2251 2014-11-01 12:40:45 +01:00
d5012f6fcf Fixed server not stopping after a fatal error 2014-11-01 03:07:47 +01:00
4569a73f3d Fixed Entity being set position after being closed 2014-10-31 23:10:29 +01:00
66acb5cdd7 Possible fix for crashing server not stopping 2014-10-31 23:10:12 +01:00
8601405a88 Fixed CPU leak 2014-10-31 21:07:00 +01:00
ae06681b60 Added packet exception handling, updated RakLib 2014-10-31 19:14:59 +01:00
01ffb14e39 Fixed #2204 2014-10-31 17:34:45 +01:00
ce989876af Improved freeing chunks 2014-10-31 16:39:32 +01:00
f8d6ebabf3 Removed some calls 2014-10-31 15:57:07 +01:00
094b600a0c Updated NBT/DataPacket reading 2014-10-31 01:02:31 +01:00
82cfe6ea9c Updated NBT/DataPacket reading 2014-10-31 00:32:50 +01:00
4fba6d7c86 Merge branch 'master' into 0.10 2014-10-30 23:20:59 +01:00
f72d7284b9 Added EncapsulatedPacket reuse on broadcast 2014-10-30 23:20:28 +01:00
8f0527832f Removed extra AxisAlignedBB generation on Door and Trapdoor 2014-10-30 22:15:19 +01:00
f66944368d Update RakLib 2014-10-30 22:06:23 +01:00
7ab3c57b00 Optimized networking code & AxisAlignedBB 2014-10-30 22:06:07 +01:00
673b867ee8 Fixed players not loading chunks when stuck on a unloaded chunk 2014-10-30 20:05:40 +01:00
2424c8a76c Update RakLib, possible fix for notifyACK 2014-10-30 19:44:05 +01:00
92eb5cb0b8 Added LE Triad methods 2014-10-30 17:56:58 +01:00
fd46c71120 Updated RakLib 2014-10-30 17:18:43 +01:00
6a4259bf24 Updated RakLib 2014-10-30 17:04:19 +01:00
9a65279c6a Added ifndef for packets Binary 2014-10-30 16:41:11 +01:00
09a01be709 Added ifndef for NBT Binary 2014-10-30 16:32:57 +01:00
57d1847c50 Updated to receive new optimizations 2014-10-30 16:02:48 +01:00
6e8e2a79dd Fixed Event name being null 2014-10-30 14:52:11 +01:00
d8f9def7f4 Added preprocessor optimizations 2014-10-30 07:58:53 +01:00
8cb9dd9a14 Fixed #2244 2014-10-29 22:58:40 +01:00
c4c374e3fa Added extra chunk sending timings 2014-10-29 21:52:27 +01:00
d57e37896d Improved Region / RakLib 2014-10-29 17:43:21 +01:00
022a978ffb Added InventoryPickupArrowEvent 2014-10-29 16:29:00 +01:00
00b282d40c Improved cache pool cleanup times 2014-10-29 16:13:47 +01:00
8a768cea33 EntityDamageEvent and children now only fire if the attack is possible, moved event trigger to Entity->attack() 2014-10-29 16:02:40 +01:00
289bc56b4b Blocks now save their bounding box, fixed entity block collision check 2014-10-29 15:43:23 +01:00
6f64af3066 Reuse even more objects! 2014-10-29 14:23:51 +01:00
72c09045d5 Fixed Zombie drops crash 2014-10-29 13:21:54 +01:00
5e55c3a8f0 Fixed Chest->unpair() 2014-10-29 13:21:14 +01:00
afaa2cf722 Fixed Double Chest behavior 2014-10-29 12:57:26 +01:00
50cfeaa393 Fixed Stonecutter recipe 2014-10-29 12:36:34 +01:00
dda8b03349 Fixed Bowl recipe 2014-10-29 12:12:54 +01:00
56e848488a Fixed Trapdoor recipe 2014-10-29 12:10:48 +01:00
7e4f862634 Fixed typo in OfflinePlayer 2014-10-29 11:42:29 +01:00
577a7a1c3d cmd files comment syntax should be like this. 2014-10-29 17:20:36 +08:00
78f8d0280d Removed unused imports 2014-10-29 01:14:09 +01:00
0680b98380 Remove chunks from advanced cache after setting 2014-10-29 01:07:30 +01:00
cbe0fe5e46 Added Entity->onGround setting when entities keep moving without checks 2014-10-29 00:41:13 +01:00
7eed92e8fb Use Player->forceMovement on MovePlayerPacket non-tick revert 2014-10-29 00:31:17 +01:00
f772391866 Fixed InventoryPickupItemEvent 2014-10-28 22:05:54 +01:00
8c4faa8622 Added extra Exceptions 2014-10-28 21:07:12 +01:00
b6f7ee20fc Added Error -> Exception handling 2014-10-28 20:43:36 +01:00
0fce83c671 Fixed #2189 2014-10-28 13:27:30 +01:00
8080643cc9 Fixed plugins crashing the server when teleporting players on an invalid event 2014-10-28 13:18:40 +01:00
5bf2174cad Fixed UseItemPacket being able to be sent before spawning 2014-10-28 13:16:20 +01:00
34ae760def New way to spawn entities/tiles using a global register table, allow overriding default entity/tile classes via classes 2014-10-28 13:09:27 +01:00
a5b85c549a Added Snowballs 2014-10-28 12:13:31 +01:00
b9f1812f61 Disallow further modification of Signs by its creator after load/unload 2014-10-28 11:05:32 +01:00
350cee3d41 Added Event allocation pool, updated SPL with Class::onClassLoaded() 2014-10-28 10:47:40 +01:00
144a871c07 Improved Vector3 and Block handling, less allocation on Positions 2014-10-28 10:03:10 +01:00
69492474e4 Improve #2238, do not crash when an invalid/corrupt RCON stop event happens 2014-10-28 02:09:36 +01:00
4299ebebcc Bump API version to 1.6.1 2014-10-28 00:55:07 +01:00
119b429ab8 RakLib update 2014-10-28 00:43:47 +01:00
8f1eb41ca5 RakLib update 2014-10-28 00:23:55 +01:00
ca92d2a0d3 Bumped API version to 1.7.0 2014-10-27 20:30:58 +01:00
db82f76c11 Improved network packets allocation 2014-10-27 20:30:33 +01:00
3f5b129cf5 Updated RakLib 2014-10-27 19:39:24 +01:00
f6aac8728b Mark chunk to be saved when removing invalid entities/tiles 2014-10-27 18:43:58 +01:00
809fc44813 Bump API version to 1.6.1 2014-10-27 16:07:00 +01:00
64f1ff066d Fixed /setworldspawn changing sender data 2014-10-27 15:57:26 +01:00
a5a3f4801a Fixed entities not getting ticks on movement 2014-10-27 15:53:14 +01:00
23d1532ff9 Merge branch 'master' of github.com:PocketMine/PocketMine-MP 2014-10-27 15:44:44 +01:00
ecbbcc2e8e Drop invalid entities / tile entities on chunk loading 2014-10-27 15:44:36 +01:00
7abf52e615 Implemented Vector3 List and AxisAlignedBB Pool to decrease object allocation 2014-10-27 15:39:20 +01:00
9e01e2ef49 Merge pull request #2235 from nno88551/patch-2
Update BaseInventory.php
2014-10-26 15:52:08 +01:00
df81b365e5 Update BaseInventory.php 2014-10-26 22:21:21 +09:00
db8ac0b9cb Merge pull request #2225 from PEMapModder/falling-sand
Update FallingBlock to new Anvil formats, possible fix for #2189
2014-10-25 17:58:47 +02:00
ee4f416d93 Fix FallingBlock.php 2014-10-25 18:15:47 +08:00
8feea721e3 Merge pull request #2223 from Falkirks/set-armour-fix
Fix various get and set armour in PlayerInventory
2014-10-25 12:13:28 +02:00
8e7077ff4b Update FallingBlock to new Anvil formats, possible fix for #2189
I don't have time to test yet, so I am not sure if it does fix it.
2014-10-25 12:26:57 +08:00
4f4a6e7446 Fixes get and set armour 2014-10-24 17:11:59 -07:00
1fc066fc37 Updated time steps from x2.5 to x1.25 2014-10-24 12:12:01 +02:00
b565844062 Merge branch 'master' into 0.10 2014-10-24 12:07:35 +02:00
be948f99cc Fixed #2207 Server crashing if players are closed before logging in 2014-10-24 12:06:55 +02:00
5cb428e5cc Updated build number 2014-10-23 17:23:59 +02:00
d2f4a14d66 Merge branch 'master' into 0.10 2014-10-23 17:21:24 +02:00
516bb37a50 Removed some direct type checks on Entity/Tile->closed 2014-10-21 19:28:29 +02:00
580ade9092 Possible fix for entities not closing correctly 2014-10-21 19:26:16 +02:00
8f7dfe0b71 Removed extra ; from if, fixes #2205 2014-10-21 18:37:29 +02:00
5310ba3ae6 Fixed crash when doing var_dump() of anything that contains the Server object 2014-10-20 13:06:53 +02:00
ef97efcd96 Added explosion death message 2014-10-20 13:00:03 +02:00
30c3718ea8 Improved Explosion item drop position 2014-10-20 12:58:05 +02:00
5437567e95 Merge branch 'master' into 0.10 2014-10-20 12:53:14 +02:00
e3e97a4205 Improved Player->onGround checking 2014-10-20 12:52:00 +02:00
fec387d2ec Fixed entities not being pushed out of blocks 2014-10-20 12:37:17 +02:00
481e2b08ee Removed debug call 2014-10-20 12:05:40 +02:00
15de0eece7 Improved inventory and window allocation, fixes #2200 2014-10-20 09:48:11 +02:00
2f8267aa1e Improved Level object deallocation 2014-10-19 20:45:03 +02:00
f2b573c32f Fixed Level->getMetadata() and similar, removed extra references 2014-10-19 19:51:36 +02:00
34946faf94 Remove errors from Utils::getRandomBytes() 2014-10-19 13:44:38 +02:00
3b47513439 Return result directly on Server->getOfflinePlayer() 2014-10-19 02:49:58 +02:00
7d9a98ec6b Updated UseItemPacket 2014-10-18 23:42:41 +02:00
92facc94b9 Added new fences and fence gates to fuel types 2014-10-18 18:02:39 +02:00
d3327f450c Added different Fence Gates, new Fence Gate crafting recipes 2014-10-18 17:56:18 +02:00
570cab9c66 Added different Fences, new Fence crafting recipes 2014-10-18 17:44:24 +02:00
582ba100b0 Bumped protocol version to 19 2014-10-18 17:01:36 +02:00
4c0daa462d Merge branch 'master' into 0.10 2014-10-18 16:54:03 +02:00
2e6366868d Merge branch 'master' of github.com:PocketMine/PocketMine-MP 2014-10-18 16:53:42 +02:00
245e9b4f18 Fixes inventory changes getting the wrong window, closes #2187 2014-10-18 16:53:06 +02:00
68e73d4e3a Merge pull request #2188 from aodzip/patch-1
Update Skeleton.php
2014-10-18 15:36:02 +02:00
684617d370 Update Skeleton.php
fixed a little wrong
2014-10-18 21:13:35 +08:00
a879104a6f Minecraft: PE version bump 2014-10-17 14:43:10 +02:00
05f71691fc Fixed AxisAlignedBB->setBB() 2014-10-17 09:57:42 +02:00
1c03c3afcf Decreased chunk ordering times 2014-10-17 09:57:18 +02:00
94e9485be9 Improved broadcast packet encoding 2014-10-17 09:36:47 +02:00
9cb27e26ef Fixed #2183 2014-10-16 22:01:32 +02:00
7760559be1 Improved chunk loading and order refresh times 2014-10-16 20:21:06 +02:00
163a37ee23 Optimized Player->orderChunks() and chunk sending ordering algorithm 2014-10-16 14:54:55 +02:00
c73a3e53be Added extra Entity metadata 2014-10-16 12:49:45 +02:00
8637b7f5a3 Fixed Tasks deleting their Timings reports 2014-10-16 12:49:26 +02:00
747fdab389 Fixed Inventory->removeItem() 2014-10-16 12:16:23 +02:00
204915450f Do not wrap text if unknown characters are found. 2014-10-15 18:38:14 +02:00
500a690cd0 Throw CRITICAL error message on unhandled Exception on commands instead of crashing 2014-10-15 18:35:42 +02:00
d473ce13ee Throw CRITICAL error message on unhandled Exception on plugin events instead of crashing 2014-10-15 18:35:30 +02:00
1adf53a81e Fixed error_handler trace generation on higher debug levels 2014-10-15 17:58:03 +02:00
ed942100ec Do not block when killing workers 2014-10-15 17:49:08 +02:00
8abe95309c Fixed RegionLoader not creating default index on first load 2014-10-15 16:59:31 +02:00
5dc5aba42c Match Player pickup area with Minecraft 2014-10-15 14:57:12 +02:00
bda6f03e15 Added BlockUpdateEvent 2014-10-15 13:07:10 +02:00
69d132401e Fixes entities not being saved and tile entities having an incorrect field, closes #1661 2014-10-15 12:15:17 +02:00
e3a9db5d8f Implemented saving modified chunks 2014-10-15 11:42:58 +02:00
b71a4701d9 Fixed player using an invalid spawn chunk 2014-10-15 11:40:41 +02:00
9b85abd75e Micro-optimizations 2014-10-15 10:44:01 +02:00
7b7b91ea0d Fixed Entity updates not firing 2014-10-15 10:13:49 +02:00
18f6bad48d Implemented scheduled and partial entity updates 2014-10-14 22:49:35 +02:00
fbe548c611 RakLib update, PING/PONG handling 2014-10-14 16:13:32 +02:00
4e793199fa Deprecated EntityMoveEvent 2014-10-14 16:11:10 +02:00
43a97c407d New PlayerMoveEvent, improved player movement event firing 2014-10-14 16:10:50 +02:00
07dcbdb9b0 Fixed Level->getNearbyEntities(), fixes item drops not being picked up 2014-10-14 16:03:14 +02:00
60ca24fe0e Updated PluginManager event deprecation message 2014-10-14 14:11:58 +02:00
6e8144d5d9 Improved player movement event firing & corrections 2014-10-14 00:11:17 +02:00
464afb949e Increased Player->forceMovement check radius 2014-10-13 23:44:28 +02:00
823dc933b8 Improved Entity extinguish operations and packet spam 2014-10-13 23:44:11 +02:00
883f93cc8c Improved item drop spawning 2014-10-13 22:45:04 +02:00
b26ee09f76 Removed a bunch of TODO and fixed item drops on block update 2014-10-13 18:54:34 +02:00
1eec333501 Save block bounding boxes, improves block cache 2014-10-13 18:38:00 +02:00
5448a48f67 Fixed Level->getCollidingEntities() 2014-10-13 18:36:13 +02:00
a10ad42a13 Removed Generic block class 2014-10-13 18:12:34 +02:00
da23cf685d Added PlayerBucketEvent and children, improved Bucket usage and Liquid placing 2014-10-13 18:04:40 +02:00
79e4b3e3a9 Removed old Player->timeout property 2014-10-12 17:12:59 +02:00
8472349caf Improved global block cache 2014-10-12 17:02:27 +02:00
96b61fbb92 Made Wheat crops extend Crop class 2014-10-12 16:20:30 +02:00
6246ad19c4 Added global block cache 2014-10-12 16:16:19 +02:00
9b69cc4288 Removed debug code 2014-10-12 15:40:14 +02:00
114153ae97 Added EntityBlockChangeEvent 2014-10-12 13:37:45 +02:00
ebb844fa52 Removed unused code, fixed undefined variables 2014-10-11 22:22:51 +02:00
bf89ea1cf6 Added BlockGrowEvent 2014-10-11 20:19:46 +02:00
4076fb4657 Added BlockSpreadEvent 2014-10-11 19:27:43 +02:00
312f377483 Added LeavesDecayEvent 2014-10-11 19:01:27 +02:00
0af3dfedd5 Improved Living entity ticking 2014-10-11 17:35:13 +02:00
6f1f201c41 Workaround for entities glitching through the floor on the client-side 2014-10-11 17:02:41 +02:00
48f591e5ce Removed workaround on flying check due to physics calculation fix, closes #2169 2014-10-11 16:43:14 +02:00
7f85e37540 Worked on scheduler 2014-10-11 16:36:38 +02:00
341717c89d Increased Player->stepHeight to 0.6, closes #2156 2014-10-11 16:36:17 +02:00
afdf7bc2b9 Added proper TextWrap width 2014-10-11 00:17:31 +02:00
24c76acf30 Submodule update 2014-10-11 00:04:17 +02:00
baf06dc363 Revert "Use Collectable class on AsyncTask, removed task collection workaround on ServerScheduler"
This reverts commit 0dba14074a.
2014-10-11 00:03:46 +02:00
645c00b2f7 Added TextWrapper 2014-10-11 00:01:53 +02:00
0dd46c835c Made ExplosionPrimeEvent accept setting block breaking settings 2014-10-10 22:39:06 +02:00
0dba14074a Use Collectable class on AsyncTask, removed task collection workaround on ServerScheduler 2014-10-10 20:53:28 +02:00
8b585fd9f7 Deprecated Level->getSpawn() in favor of Level->getSpawnLocation() 2014-10-10 11:43:54 +02:00
9ede8177df Fixed Entity->getLineOfSight() 2014-10-10 09:53:58 +02:00
13ec046f0d Removed old OS detection code 2014-10-09 19:37:23 +02:00
5c4e7b6ee0 Added Living->getTargetBlock(), Living->getLineOfSight(), Vector3 side constants, Vector3::getOppositeSide() 2014-10-09 17:57:25 +02:00
6424934df6 Fixed EntityCombustEvent children using a different handlerList 2014-10-09 14:40:52 +02:00
b2ac959083 Added FurnaceSmeltEvent 2014-10-09 12:47:42 +02:00
c67d4dae7b Added FurnaceBurnEvent 2014-10-09 12:36:57 +02:00
22ad75c5a0 Update fuel duration to ticks 2014-10-09 12:21:14 +02:00
b45ef8928c Added Tile->getBlock() method 2014-10-09 12:14:39 +02:00
eccf7b08d2 Added PlayerDeathEvent methods for inventory keeping 2014-10-09 11:06:05 +02:00
94eb9e35e2 Improved liquid performance, update RakLib 2014-10-08 23:24:39 +02:00
79bf1f12f2 API 1.6.0 2014-10-08 17:39:43 +02:00
10b33546ef Added PlayerBedEnterEvent and PlayerBedLeaveEvent 2014-10-08 17:37:11 +02:00
c52dc58d6f Added ProjectileHitEvent 2014-10-08 17:04:35 +02:00
62af784d37 Removed unused imports 2014-10-08 17:00:23 +02:00
aa010b7dea Added ProjectileLaunchEvent 2014-10-08 16:58:17 +02:00
4a3163b4c8 Added ItemSpawnEvent 2014-10-08 16:53:13 +02:00
c750a204e6 Added ItemDespawnEvent 2014-10-08 16:51:10 +02:00
3313981d54 Fixed issues with Entity::heal() method 2014-10-08 16:46:21 +02:00
57f7d57c76 Added ExplosionPrimeEvent 2014-10-08 16:45:55 +02:00
64bf293c69 Improved EntityShootBowEvent 2014-10-08 16:36:43 +02:00
7b09edf048 Improved EntityRegainHealthEvent 2014-10-08 16:28:40 +02:00
4346773e25 Added EntityDamageByBlockEvent (child of EntityDamageEvent) 2014-10-08 16:13:18 +02:00
b0c314526d Added EntityCombustEvent and childs 2014-10-08 15:51:27 +02:00
dd140ce018 Fixed arrow damage not getting overridden by the event result 2014-10-08 15:38:58 +02:00
08aa7808cf Updated RakLib, better player join 2014-10-08 10:45:37 +02:00
582c165479 Implemented Explosion and PrimedTNT, closes #2139 2014-10-07 17:46:01 +02:00
5fb205493a Spawnable->spawnToAll() now uses the actual chunk instead of the entire level to spawn 2014-10-07 12:50:53 +02:00
e346d245e2 Merge pull request #2166 from PocketMine/query-event-implementation
Query event implementation
2014-10-07 11:46:55 +02:00
4fece32ca8 API 1.5.0 2014-10-07 11:02:22 +02:00
0b79d74a2f Implemented QueryRegenerateEvent 2014-10-07 11:02:05 +02:00
b83c6fbfa3 Added Vine blocks, closes #2162 2014-10-07 10:18:02 +02:00
dda9c598f1 Added new Tool type selection constants 2014-10-07 10:16:05 +02:00
8769d2bcd1 Unload entities from chunks, possible fix for #2157, fixes #2165 2014-10-07 09:27:18 +02:00
3b7ece3363 Do not spawn dead entities to players, fixes #2157, possible fix for #2165 2014-10-07 09:24:19 +02:00
b6025e3f2b Removed selectors on Player->sendMessage() 2014-10-06 16:45:11 +02:00
35de331b74 Fixed Level->getCollidingEntities() when called with a null Entity 2014-10-06 13:18:05 +02:00
de11cce154 Improved entity ticking 2014-10-06 13:10:59 +02:00
d53ba52d32 Removed parse errors from AutoReporting 2014-10-06 12:12:54 +02:00
9db2fe40eb Fixed player datta not getting saved, use fall distance on fly calculation 2014-10-06 12:02:36 +02:00
57bb8f14fa Fixed Player movement collision checks 2014-10-06 11:47:28 +02:00
761cd59514 Implemented flying protection 2014-10-06 11:22:59 +02:00
4c2a1c8684 Implement crop growth levels properly, fixes #2002, closes #2160 2014-10-06 09:34:40 +02:00
31bb6d1a68 Changed base block classes to abstract, closes #2159 2014-10-06 09:27:44 +02:00
cd65179aef Fixes #2155 2014-10-06 12:07:48 +10:30
9abd2c63f4 Improved initial chunk loading, do not skip near chunks, fixes world loading getting stuck 2014-10-06 00:45:02 +02:00
376e359577 Moved connected flag up in the Player disconnect process 2014-10-05 22:51:20 +02:00
571e2f8895 Revert "Option to disable hitbox calculation"
This reverts commit fae330d499.
2014-10-05 16:32:49 +02:00
7106ea87e6 Merge branch 'master' of github.com:PocketMine/PocketMine-MP 2014-10-05 16:32:27 +02:00
6b65b68ebc Possible fix for #1661 2014-10-05 16:32:15 +02:00
d4c75ce68a Trim system timezone output 2014-10-05 17:40:17 +10:30
fae330d499 Option to disable hitbox calculation 2014-10-04 20:07:37 -05:00
5e03e157ad Fixed #2153 2014-10-04 23:16:35 +02:00
b0c40dc1ab Fixed Server->unloadLevel() not removing objects from memory 2014-10-04 20:56:27 +02:00
6840589f4e Fix trailing newline 2014-10-04 18:28:42 +02:00
19e4aaa16a Merge pull request #2151 from sekjun9878/master
Timezone for Windows and IP Geolocation TZdata
2014-10-05 01:51:44 +09:30
e0a7944faa Re-use timezone offset parsing 2014-10-05 01:43:33 +09:30
eeda22d0ba Add portable linux timezone detection for incompatible linux distributions. 2014-10-05 01:29:07 +09:30
769f1effb0 Cleaner timezone parsing for Linux and add support for Macs 2014-10-05 01:05:00 +09:30
42c7322273 Reliable timezone detection using systeminfo for Windows and additional IP Geolocation-based detection. Added a warning message for when auto-detection fails. Fixes #2015. 2014-10-05 00:32:01 +09:30
c8cf6b715e Merge pull request #2150 from PEMapModder/patch-2
Fixed PlayerChatEvent::setRecipients() being ignored
2014-10-04 14:49:14 +02:00
41f94f7385 Fixed PlayerChatEvent::setRecipients() being useless 2014-10-04 20:10:12 +08:00
602bdf27a5 Compatibility with pthreads > 2.0.8 2014-10-02 16:58:37 +02:00
539fa232f8 Added individual object timings to Entities / Tile Entities 2014-09-30 16:09:21 +02:00
f8378c09ba Fixed entities getting OnGround default to true 2014-09-30 13:13:31 +02:00
69fb7ae525 Update RakLib, fixes server locking when shutting down 2014-09-30 09:52:50 +02:00
ee8ad6f92a Implement Armor changes as Transactions 2014-09-30 09:37:58 +02:00
f888acbd7c Send PlayerArmorEquipmentPacket instead of ContainerSetContentPacket with id 0x78 2014-09-29 23:43:52 +02:00
215691f1c4 Update RakLib 2014-09-29 23:23:11 +02:00
1252dd65a9 Improved PlayerInventory->setItemInHand() $source call, fixed Tool durability 2014-09-29 17:53:53 +02:00
762c27affe Added armor change $source parameter 2014-09-29 17:50:48 +02:00
706e1099a1 Update raklib 2014-09-29 16:46:19 +02:00
9cd66dc969 Some changes 2014-09-29 16:37:56 +02:00
5b6b789ab3 Improved exponentiation 2014-09-29 13:24:25 +02:00
85ff696ae5 Improved Chunk entity loading 2014-09-29 13:14:14 +02:00
25f8e8318b Fixed Anvil levels duplicating saved entities 2014-09-29 13:09:13 +02:00
61d84c73d0 Implemented Arrow pick up 2014-09-29 13:05:18 +02:00
f5822c6de8 Improved entity movement updates 2014-09-29 12:59:01 +02:00
b0bd927545 Improved entity base ticks 2014-09-29 12:55:10 +02:00
fde61b7d21 Improved single-threaded chunk generation efficiency 2014-09-29 12:48:11 +02:00
886ad8442c Fixed #2055 Extra packet data sent on armor change 2014-09-28 17:31:44 +02:00
7b5869bea8 RakLib submodule update 2014-09-28 16:35:24 +02:00
3063863c65 RakLib update 2014-09-28 16:06:27 +02:00
0dfaa19380 Fixed invalid spawn position setting for plugins 2014-09-28 15:19:09 +02:00
7fea29e874 Updated pthreads version on Travis-CI 2014-09-28 12:50:03 +02:00
2ded2013bf Fixed auto-save configuration, made it global 2014-09-28 10:50:43 +02:00
aa27c28e65 Force new player position on spawn 2014-09-28 01:14:03 +02:00
05a81bebf4 Fixed server crash when Tile Entities / Entities were loaded and requested the same chunk 2014-09-28 00:39:49 +02:00
ce91f2943a Fixed Double Chests 2014-09-28 00:39:11 +02:00
1d8562fb8c Allow setting the player spawnpoint via events before PlayerJoinEvent 2014-09-28 00:14:08 +02:00
1dfb17b932 Fixed #2126 Items drop twice from tile entities 2014-09-27 14:31:41 +02:00
16384c2b20 Improved Player generation queue 2014-09-27 10:31:02 +02:00
48041b2f19 Basic entity motion on water 2014-09-27 00:09:38 +02:00
529bf743db Added torch drop 2014-09-26 23:07:43 +02:00
48bc919a33 Added Liquid flow 2014-09-26 16:56:10 +02:00
474091c013 Improved Level block update scheduling for repeated updates 2014-09-26 16:55:34 +02:00
666e5553c2 Fixed Level->scheduleUpdate() tick calculation 2014-09-26 16:04:51 +02:00
ae6f532b1d Partial Liquid flow 2014-09-26 13:25:52 +02:00
b231eba803 Fixed E_NOTICE error on player movement 2014-09-26 13:23:47 +02:00
82d903733d Fixed #2121 2014-09-26 11:34:06 +02:00
8e2903da86 API version 1.4.1 2014-09-26 11:19:30 +02:00
d720113ac9 Added non-threaded chunk generation, toggleable on pocketmine.yml 2014-09-26 11:18:46 +02:00
5db45222c6 Deprecated Level->getChunkAt() in favor of Level->getChunk() 2014-09-26 10:31:32 +02:00
2975509d0f Improved chunk unload queue, possible fix for #1661 2014-09-25 23:03:56 +02:00
7e49d073fa Improved player movement, check once per tick 2014-09-24 16:58:22 +02:00
ef3674a296 Possible fix for #1661 2014-09-24 16:47:53 +02:00
6cb7e36f8a Improved knockback motion 2014-09-24 16:17:04 +02:00
b88f19bb74 Improved Level::getSafeSpawn() 2014-09-23 20:16:16 +02:00
8c3fcf0798 Send player metadata on respawn 2014-09-23 20:14:01 +02:00
6b312a7826 Fixed players getting Suffocation damage inside transparent blocks 2014-09-23 19:50:44 +02:00
9907e84eee Torches can now be crafted using charcoal 2014-09-23 19:36:30 +02:00
01f299a7f1 Merge branch 'master' of github.com:PocketMine/PocketMine-MP 2014-09-23 15:54:59 +02:00
91f20f6789 Add valid position difference back to Player entities 2014-09-23 15:54:48 +02:00
4c1edc3f7e Re-order RFC section 2014-09-23 20:32:39 +09:30
5fd1e271c5 Merge pull request #2112 from PocketMine/rfc-rfc-and-voting
RFC and Voting
2014-09-22 15:46:03 +02:00
593b0497b0 Fixed #1750 cannot place slabs against blocks 2014-09-22 11:58:15 +02:00
0907aedcef Fixed Entity/Block issues on negative coordinates, closes #2100 2014-09-22 11:48:39 +02:00
0a29e66b62 Fixed #2114 Removed Player collisions with other entities 2014-09-22 11:26:12 +02:00
3cc4afbcd6 Possible fix for #1920 2014-09-22 11:21:54 +02:00
b3ae6eae04 Added RFC ready status, added new label to label list 2014-09-22 09:30:14 +02:00
3b56b536b6 Changed RFC label 2014-09-22 08:46:03 +02:00
9258281546 Fixed missing whitespace 2014-09-21 21:18:37 +02:00
e7897be7cd Merge pull request #2113 from tnpxxsheepdog/rfc-rfc-and-voting
Update CONTRIBUTING.md
2014-09-21 21:08:18 +02:00
5ff01de413 Update CONTRIBUTING.md
Smoothed out wording, fix grammar.
2014-09-21 15:05:08 -04:00
f191ada405 Fixed text typo 2014-09-21 18:33:34 +02:00
addd74d09e Fix typo, added PR: Request for Comments label 2014-09-21 17:51:35 +02:00
4e9d2d0a7f Added 'RFC and Voting' to CONTRIBUTING.md 2014-09-21 17:45:58 +02:00
d04e994d1b Added TPS load to /status 2014-09-21 12:18:51 +02:00
3d870629f2 Fixed ifconfig command typo 2014-09-21 12:18:26 +02:00
8dbe834dc3 Submodule update 2014-09-21 12:18:10 +02:00
36d8100e17 Protect against \0 attacks on name checking 2014-09-20 18:26:17 +02:00
b880bf13f8 Documented tool usage in Level::useBreakOn() 2014-09-20 18:25:53 +02:00
1ac08ce404 Fixed Utils::getUniqueID() on Linux due to /proc/cpuinfo 2014-09-20 12:39:57 +02:00
689b2ea877 Fixed #2104 Can't place blocks where non-solid entities exist 2014-09-20 11:10:46 +02:00
d1f22ee395 Block more player actions when dead, closes #2102 2014-09-19 20:19:27 +02:00
056ed4802f Send project name on usage 2014-09-19 15:08:40 +02:00
bcb65e9a48 Send build number on usage 2014-09-19 15:07:48 +02:00
5404ba77d0 Throw exception when Server::dispatchCommand() is called with an invalid CommandSender 2014-09-19 10:30:35 +02:00
ae54426836 Fixed date_default_timezone_set E_NOTICE 2014-09-19 10:26:44 +02:00
ee7d84dfbd Fixed T_DOUBLE_COLON 2014-09-19 09:48:02 +02:00
3e1ea23036 Fixed CallbackTask name 2014-09-19 09:46:38 +02:00
d312d2a143 Possible fix for #2046, removed embedded class names 2014-09-19 09:44:58 +02:00
8c627bd0af Remove level locks, possible fix for #2046 2014-09-18 11:44:16 +02:00
6fb7170556 Handle force parameter properly on Level::unload() 2014-09-18 11:38:03 +02:00
50f5c6d8ed RakLib patches 2014-09-18 09:22:52 +02:00
f9d5c5bd37 Improved event checking on PlayerInteractEvent 2014-09-16 17:49:44 +02:00
379 changed files with 8943 additions and 4076 deletions

View File

@ -9,8 +9,8 @@ branches:
before_script:
- mkdir plugins
- wget -O plugins/DevTools.phar https://github.com/PocketMine/DevTools/releases/download/v1.9.0/DevTools_v1.9.0.phar
- pecl install channel://pecl.php.net/pthreads-2.0.8
- pecl install channel://pecl.php.net/weakref-0.2.4
- pecl install channel://pecl.php.net/pthreads-2.0.10
- pecl install channel://pecl.php.net/weakref-0.2.6
- echo | pecl install channel://pecl.php.net/yaml-1.1.1
script:
@ -18,4 +18,4 @@ script:
notifications:
email: false
#webhooks: http://n.tkte.ch/h/214/wsNvmG43-ncxUVRrFPwSM-r0
#webhooks: http://n.tkte.ch/h/214/wsNvmG43-ncxUVRrFPwSM-r0

View File

@ -72,6 +72,19 @@ class ExampleClass{
}
```
### RFC and Voting
* These are big Pull Requests or contributions that change important behavior.
* RFCs will be tagged with the *PR: RFC* label
* A vote will be held once the RFC is ready. All users can vote commenting on the Pull Request
* Comments MUST use "Yes" or "No" on the FIRST sentence to signify the vote, except when they don't want it to be counted.
* If your comment is a voting comment, specify the reason of your vote or it won't be counted.
* After voting has been closed, no further votes will be counted.
* An RFC will be rejected if less than 50% + 1 (simple majority) has voted Yes.
* If the RFC is approved, Team Members have the final word on its implementation or rejection.
* RFCs with complex voting options will specify the vote percentage or other details.
## Bug Tracking for Collaborators
### Labels
@ -91,6 +104,7 @@ Category labels are prefixed by `C:`. Multiple category labels may be applied to
Pull Requests are prefixed by `PR:`. Only one label may be applied for a Pull Request.
- PR: Bug Fix - This label is applied when the Pull Request fixes a bug.
- PR: Contribution - This label is applied when the Pull Request contributes code to PocketMine-MP such as a new feature or an improvement.
- PR: RFC - Request for Comments
#### Status
Status labels show the status of the issue. Multiple status labels may be applied.

View File

@ -22,6 +22,7 @@
namespace pocketmine;
use pocketmine\network\protocol\Info;
use pocketmine\plugin\PluginBase;
use pocketmine\plugin\PluginLoadOrder;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
@ -136,7 +137,7 @@ class CrashDump{
$error = $lastExceptionError;
}else{
$error = (array) error_get_last();
$error["trace"] = getTrace(4);
$error["trace"] = @getTrace(4);
$errorConversion = [
E_ERROR => "E_ERROR",
E_WARNING => "E_WARNING",
@ -179,7 +180,7 @@ class CrashDump{
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
$this->data["plugin"] = true;
$reflection = new \ReflectionClass("pocketmine\\plugin\\PluginBase");
$reflection = new \ReflectionClass(PluginBase::class);
$file = $reflection->getProperty("file");
$file->setAccessible(true);
foreach($this->server->getPluginManager()->getPlugins() as $plugin){

File diff suppressed because it is too large Load Diff

View File

@ -65,17 +65,22 @@ namespace {
}
namespace pocketmine {
use LogLevel;
use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Utils;
use pocketmine\wizard\Installer;
use raklib\RakLib;
const VERSION = "Alpha_1.4dev";
const API_VERSION = "1.4.0";
const API_VERSION = "1.8.0";
const CODENAME = "絶好(Zekkou)ケーキ(Cake)";
const MINECRAFT_VERSION = "v0.9.5 alpha";
const MINECRAFT_VERSION = "v0.10.4 alpha";
/*
* Startup code. Do not look at it, it may harm you.
* Most of them are hacks to fix date-related bugs, or basic functions used after this
* This is the only non-class based file on this project.
* Enjoy it as much as I did writing it. I don't want to do it again.
*/
if(\Phar::running(true) !== ""){
@define("pocketmine\\PATH", \Phar::running(true) . "/");
@ -101,40 +106,9 @@ namespace pocketmine {
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "raklib");
$autoloader->register(true);
//Startup code. Do not look at it, it can harm you. Most of them are hacks to fix date-related bugs, or basic functions used after this
set_time_limit(0); //Who set it to 30 seconds?!?!
if(ini_get("date.timezone") == ""){ //No Timezone set
date_default_timezone_set("GMT");
if(strpos(" " . strtoupper(php_uname("s")), " WIN") !== false){
$time = time();
$time -= $time % 60;
//TODO: Parse different time & date formats by region. ¬¬ world
//Example: USA
@exec("time.exe /T", $hour);
$i = array_map("intval", explode(":", trim($hour[0])));
@exec("date.exe /T", $date);
$j = array_map("intval", explode(substr($date[0], 2, 1), 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");
$d = timezone_name_from_abbr("", $offset, $daylight);
@ini_set("date.timezone", $d);
date_default_timezone_set($d);
}else{
$d = @date_default_timezone_get();
if(strpos($d, "/") === false){
$d = timezone_name_from_abbr($d);
@ini_set("date.timezone", $d);
date_default_timezone_set($d);
}
}
gc_enable();
error_reporting(-1);
ini_set("allow_url_fopen", 1);
@ -147,13 +121,174 @@ namespace pocketmine {
$opts = getopt("", ["enable-ansi", "disable-ansi", "data:", "plugins:", "no-wizard", "enable-profiler"]);
define("pocketmine\\DATA", isset($opts["data"]) ? realpath($opts["data"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? realpath($opts["plugins"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
define("pocketmine\\DATA", isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
define("pocketmine\\ANSI", ((strpos(strtoupper(php_uname("s")), "WIN") === false or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"])));
define("pocketmine\\ANSI", (Utils::getOS() !== "win" or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"]));
@mkdir(\pocketmine\DATA, 0777, true);
//Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone.
date_default_timezone_set("UTC");
$logger = new MainLogger(\pocketmine\DATA . "server.log", \pocketmine\ANSI);
if(!ini_get("date.timezone")){
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
//Success! Timezone has already been set and validated in the if statement.
//This here is just for redundancy just in case some program wants to read timezone data from the ini.
ini_set("date.timezone", $timezone);
}else{
//If system timezone detection fails or timezone is an invalid value.
if($response = Utils::getURL("http://ip-api.com/json")
and $ip_geolocation_data = json_decode($response, true)
and $ip_geolocation_data['status'] != 'fail'
and date_default_timezone_set($ip_geolocation_data['timezone']))
{
//Again, for redundancy.
ini_set("date.timezone", $ip_geolocation_data['timezone']);
}else{
ini_set("date.timezone", "UTC");
date_default_timezone_set("UTC");
$logger->warning("Timezone could not be automatically determined. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
}
}
}else{
/*
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
* an incorrect timezone abbreviation in php.ini apparently.
*/
$default_timezone = date_default_timezone_get();
if(strpos($default_timezone, "/") === false){
$default_timezone = timezone_name_from_abbr($default_timezone);
ini_set("date.timezone", $default_timezone);
date_default_timezone_set($default_timezone);
}
}
function detect_system_timezone(){
switch(Utils::getOS()){
case 'win':
$regex = '/(UTC)(\+*\-*\d*\d*\:*\d*\d*)/';
/*
* wmic timezone get Caption
* Get the timezone offset
*
* Sample Output var_dump
* array(3) {
* [0] =>
* string(7) "Caption"
* [1] =>
* string(20) "(UTC+09:30) Adelaide"
* [2] =>
* string(0) ""
* }
*/
exec("wmic timezone get Caption", $output);
$string = trim(implode("\n", $output));
//Detect the Time Zone string
preg_match($regex, $string, $matches);
if(!isset($matches[2]))
{
return false;
}
$offset = $matches[2];
if($offset == ""){
return "UTC";
}
return parse_offset($offset);
break;
case 'linux':
// Ubuntu / Debian.
if(file_exists('/etc/timezone')){
$data = file_get_contents('/etc/timezone');
if($data){
return trim($data);
}
}
// RHEL / CentOS
if(file_exists('/etc/sysconfig/clock')){
$data = parse_ini_file('/etc/sysconfig/clock');
if(!empty($data['ZONE'])){
return trim($data['ZONE']);
}
}
//Portable method for incompatible linux distributions.
$offset = trim(exec('date +%:z'));
if($offset == "+00:00"){
return "UTC";
}
return parse_offset($offset);
break;
case 'mac':
if(is_link('/etc/localtime')){
$filename = readlink('/etc/localtime');
if(strpos($filename, '/usr/share/zoneinfo/') === 0){
$timezone = substr($filename, 20);
return trim($timezone);
}
}
return false;
break;
default:
return false;
break;
}
}
/**
* @param string $offset In the format of +09:00, +02:00, -04:00 etc.
* @return string
*/
function parse_offset($offset){
//Make signed offsets unsigned for date_parse
if(strpos($offset, '-') !== false){
$negative_offset = true;
$offset = str_replace('-', '', $offset);
}else{
if(strpos($offset, '+') !== false){
$negative_offset = false;
$offset = str_replace('+', '', $offset);
}else{
return false;
}
}
$parsed = date_parse($offset);
$offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];
//After date_parse is done, put the sign back
if($negative_offset == true){
$offset = -abs($offset);
}
//And then, look the offset up.
//timezone_name_from_abbr is not used because it returns false on some(most) offsets because it's mapping function is weird.
//That's been a bug in PHP since 2008!
foreach(timezone_abbreviations_list() as $zones){
foreach($zones as $timezone){
if($timezone['offset'] == $offset){
return $timezone['timezone_id'];
}
}
}
return false;
}
if(isset($opts["enable-profiler"])){
if(function_exists("profiler_enable")){
\profiler_enable();
@ -209,54 +344,7 @@ namespace pocketmine {
return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH), "/")], ["/", "", "", "", ""], $path), "/");
}
function error_handler($errno, $errstr, $errfile, $errline, $trace = null){
global $lastError;
if(error_reporting() === 0){ //@ error-control
return false;
}
$errorConversion = [
E_ERROR => "E_ERROR",
E_WARNING => "E_WARNING",
E_PARSE => "E_PARSE",
E_NOTICE => "E_NOTICE",
E_CORE_ERROR => "E_CORE_ERROR",
E_CORE_WARNING => "E_CORE_WARNING",
E_COMPILE_ERROR => "E_COMPILE_ERROR",
E_COMPILE_WARNING => "E_COMPILE_WARNING",
E_USER_ERROR => "E_USER_ERROR",
E_USER_WARNING => "E_USER_WARNING",
E_USER_NOTICE => "E_USER_NOTICE",
E_STRICT => "E_STRICT",
E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
E_DEPRECATED => "E_DEPRECATED",
E_USER_DEPRECATED => "E_USER_DEPRECATED",
];
$type = ($errno === E_ERROR or $errno === E_WARNING or $errno === E_USER_ERROR or $errno === E_USER_WARNING) ? LogLevel::ERROR : LogLevel::NOTICE;
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno] : $errno;
if(($pos = strpos($errstr, "\n")) !== false){
$errstr = substr($errstr, 0, $pos);
}
$logger = MainLogger::getLogger();
$oldFile = $errfile;
$errfile = cleanPath($errfile);
$logger->log($type, "An $errno error happened: \"$errstr\" in \"$errfile\" at line $errline");
foreach(($trace = getTrace($trace === null ? 3 : 0, $trace)) as $i => $line){
$logger->debug($line);
}
$lastError = [
"type" => $type,
"message" => $errstr,
"fullFile" => $oldFile,
"file" => $errfile,
"line" => $errline,
"trace" => $trace
];
return true;
}
set_error_handler("\\pocketmine\\error_handler", E_ALL);
set_error_handler([\ExceptionHandler::class, "handler"], -1);
$errors = 0;
@ -279,8 +367,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "2.0.8") < 0){
$logger->critical("pthreads >= 2.0.8 is required, while you have $pthreads_version.");
if(version_compare($pthreads_version, "2.0.9") < 0){
$logger->critical("pthreads >= 2.0.9 is required, while you have $pthreads_version.");
++$errors;
}
@ -358,14 +446,14 @@ namespace pocketmine {
$logger->debug("Stopping " . (new \ReflectionClass($thread))->getShortName() . " thread");
if($thread instanceof Thread){
$thread->kill();
if($thread->isRunning() or !$thread->join()){
sleep(1);
if($thread->isRunning()){
$thread->detach();
}
}elseif($thread instanceof Worker){
$thread->kill();
sleep(1);
if($thread->isRunning() or !$thread->join()){
if($thread->isRunning()){
$thread->detach();
}
}

View File

@ -31,7 +31,15 @@ use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Arrow;
use pocketmine\entity\Entity;
use pocketmine\entity\FallingSand;
use pocketmine\entity\Human;
use pocketmine\entity\Item as DroppedItem;
use pocketmine\entity\PrimedTNT;
use pocketmine\entity\Snowball;
use pocketmine\entity\Villager;
use pocketmine\entity\Zombie;
use pocketmine\event\HandlerList;
use pocketmine\event\level\LevelInitEvent;
use pocketmine\event\level\LevelLoadEvent;
@ -42,9 +50,14 @@ use pocketmine\inventory\CraftingManager;
use pocketmine\inventory\InventoryType;
use pocketmine\inventory\Recipe;
use pocketmine\item\Item;
use pocketmine\level\format\anvil\Anvil;
use pocketmine\level\format\LevelProviderManager;
use pocketmine\level\format\mcregion\McRegion;
use pocketmine\level\generator\Flat;
use pocketmine\level\generator\GenerationInstanceManager;
use pocketmine\level\generator\GenerationRequestManager;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\Normal;
use pocketmine\level\Level;
use pocketmine\metadata\EntityMetadataStore;
use pocketmine\metadata\LevelMetadataStore;
@ -74,12 +87,19 @@ use pocketmine\plugin\PluginManager;
use pocketmine\scheduler\CallbackTask;
use pocketmine\scheduler\SendUsageTask;
use pocketmine\scheduler\ServerScheduler;
use pocketmine\tile\Chest;
use pocketmine\tile\Furnace;
use pocketmine\tile\Sign;
use pocketmine\tile\Tile;
use pocketmine\updater\AutoUpdater;
use pocketmine\utils\Binary;
use pocketmine\utils\Cache;
use pocketmine\utils\Config;
use pocketmine\utils\LevelException;
use pocketmine\utils\MainLogger;
use pocketmine\utils\ServerException;
use pocketmine\utils\TextFormat;
use pocketmine\utils\TextWrapper;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
@ -108,6 +128,8 @@ class Server{
/** @var bool */
private $isRunning = true;
private $hasStopped = false;
/** @var PluginManager */
private $pluginManager = null;
@ -135,6 +157,7 @@ class Server{
/** @var CommandReader */
private $console = null;
private $consoleThreaded;
/** @var SimpleCommandMap */
private $commandMap = null;
@ -148,6 +171,9 @@ class Server{
/** @var int */
private $maxPlayers;
/** @var bool */
private $autoSave;
/** @var RCON */
private $rcon;
@ -273,21 +299,38 @@ class Server{
* @return int
*/
public function getViewDistance(){
return max(56, $this->getProperty("chunk-sending.max-chunks"));
return max(56, $this->getProperty("chunk-sending.max-chunks", 96));
}
/**
* @return string
*/
public function getIp(){
return $this->getConfigString("server-ip", "");
return $this->getConfigString("server-ip", "0.0.0.0");
}
/**
* @return string
*/
public function getServerName(){
return $this->getConfigString("server-name", "Unknown server");
return $this->getConfigString("motd", "Minecraft: PE Server");
}
/**
* @return bool
*/
public function getAutoSave(){
return $this->autoSave;
}
/**
* @param bool $value
*/
public function setAutoSave($value){
$this->autoSave = (bool) $value;
foreach($this->getLevels() as $level){
$level->setAutoSave($this->autoSave);
}
}
/**
@ -584,9 +627,16 @@ class Server{
* @param string $payload
*/
public function handlePacket($address, $port, $payload){
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
$this->queryHandler->handle($address, $port, $payload);
} //TODO: add raw packet events
try{
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
$this->queryHandler->handle($address, $port, $payload);
}
}catch(\Exception $e){
if($this->logger instanceof MainLogger){
$this->logger->logException($e);
}
}
//TODO: add raw packet events
}
/**
@ -617,7 +667,7 @@ class Server{
$result = $this->getPlayerExact($name);
if($result === null){
$result = new OfflinePlayer($this, $name);
return new OfflinePlayer($this, $name);
}
return $result;
@ -631,107 +681,112 @@ class Server{
public function getOfflinePlayerData($name){
$name = strtolower($name);
$path = $this->getDataPath() . "players/";
if(!file_exists($path . "$name.dat")){
$spawn = $this->getDefaultLevel()->getSafeSpawn();
$nbt = new Compound(false, [
new Long("firstPlayed", floor(microtime(true) * 1000)),
new Long("lastPlayed", floor(microtime(true) * 1000)),
new Enum("Pos", [
new Double(0, $spawn->x),
new Double(1, $spawn->y),
new Double(2, $spawn->z)
]),
new String("Level", $this->getDefaultLevel()->getName()),
//new String("SpawnLevel", $this->getDefaultLevel()->getName()),
//new Int("SpawnX", (int) $spawn->x),
//new Int("SpawnY", (int) $spawn->y),
//new Int("SpawnZ", (int) $spawn->z),
//new Byte("SpawnForced", 1), //TODO
new Enum("Inventory", []),
new Compound("Achievements", []),
new Int("playerGameType", $this->getGamemode()),
new Enum("Motion", [
new Double(0, 0.0),
new Double(1, 0.0),
new Double(2, 0.0)
]),
new Enum("Rotation", [
new Float(0, 0.0),
new Float(1, 0.0)
]),
new Float("FallDistance", 0.0),
new Short("Fire", 0),
new Short("Air", 0),
new Byte("OnGround", 1),
new Byte("Invulnerable", 0),
new String("NameTag", $name),
]);
$nbt->Pos->setTagType(NBT::TAG_Double);
$nbt->Inventory->setTagType(NBT::TAG_Compound);
$nbt->Motion->setTagType(NBT::TAG_Double);
$nbt->Rotation->setTagType(NBT::TAG_Float);
if(file_exists($path . "$name.dat")){
try{
$nbt = new NBT(NBT::BIG_ENDIAN);
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
if(file_exists($path . "$name.yml")){ //Importing old PocketMine-MP files
$data = new Config($path . "$name.yml", Config::YAML, []);
$nbt["playerGameType"] = (int) $data->get("gamemode");
$nbt["Level"] = $data->get("position")["level"];
$nbt["Pos"][0] = $data->get("position")["x"];
$nbt["Pos"][1] = $data->get("position")["y"];
$nbt["Pos"][2] = $data->get("position")["z"];
$nbt["SpawnLevel"] = $data->get("spawn")["level"];
$nbt["SpawnX"] = (int) $data->get("spawn")["x"];
$nbt["SpawnY"] = (int) $data->get("spawn")["y"];
$nbt["SpawnZ"] = (int) $data->get("spawn")["z"];
$this->logger->notice("Old Player data found for \"" . $name . "\", upgrading profile");
foreach($data->get("inventory") as $slot => $item){
if(count($item) === 3){
$nbt->Inventory[$slot + 9] = new Compound(false, [
new Short("id", $item[0]),
new Short("Damage", $item[1]),
new Byte("Count", $item[2]),
new Byte("Slot", $slot + 9),
new Byte("TrueSlot", $slot + 9)
]);
}
}
foreach($data->get("hotbar") as $slot => $itemSlot){
if(isset($nbt->Inventory[$itemSlot + 9])){
$item = $nbt->Inventory[$itemSlot + 9];
$nbt->Inventory[$slot] = new Compound(false, [
new Short("id", $item["id"]),
new Short("Damage", $item["Damage"]),
new Byte("Count", $item["Count"]),
new Byte("Slot", $slot),
new Byte("TrueSlot", $item["TrueSlot"])
]);
}
}
foreach($data->get("armor") as $slot => $item){
if(count($item) === 2){
$nbt->Inventory[$slot + 100] = new Compound(false, [
new Short("id", $item[0]),
new Short("Damage", $item[1]),
new Byte("Count", 1),
new Byte("Slot", $slot + 100)
]);
}
}
foreach($data->get("achievements") as $achievement => $status){
$nbt->Achievements[$achievement] = new Byte($achievement, $status == true ? 1 : 0);
}
unlink($path . "$name.yml");
}else{
$this->logger->notice("Player data not found for \"" . $name . "\", creating new profile");
return $nbt->getData();
}catch(\Exception $e){ //zlib decode error / corrupt data
rename($path . "$name.dat", $path . "$name.dat.bak");
$this->logger->warning("Corrupted data found for \"" . $name . "\", creating new profile");
}
$this->saveOfflinePlayerData($name, $nbt);
return $nbt;
}else{
$nbt = new NBT(NBT::BIG_ENDIAN);
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
return $nbt->getData();
$this->logger->notice("Player data not found for \"" . $name . "\", creating new profile");
}
$spawn = $this->getDefaultLevel()->getSafeSpawn();
$nbt = new Compound(false, [
new Long("firstPlayed", floor(microtime(true) * 1000)),
new Long("lastPlayed", floor(microtime(true) * 1000)),
new Enum("Pos", [
new Double(0, $spawn->x),
new Double(1, $spawn->y),
new Double(2, $spawn->z)
]),
new String("Level", $this->getDefaultLevel()->getName()),
//new String("SpawnLevel", $this->getDefaultLevel()->getName()),
//new Int("SpawnX", (int) $spawn->x),
//new Int("SpawnY", (int) $spawn->y),
//new Int("SpawnZ", (int) $spawn->z),
//new Byte("SpawnForced", 1), //TODO
new Enum("Inventory", []),
new Compound("Achievements", []),
new Int("playerGameType", $this->getGamemode()),
new Enum("Motion", [
new Double(0, 0.0),
new Double(1, 0.0),
new Double(2, 0.0)
]),
new Enum("Rotation", [
new Float(0, 0.0),
new Float(1, 0.0)
]),
new Float("FallDistance", 0.0),
new Short("Fire", 0),
new Short("Air", 0),
new Byte("OnGround", 1),
new Byte("Invulnerable", 0),
new String("NameTag", $name),
]);
$nbt->Pos->setTagType(NBT::TAG_Double);
$nbt->Inventory->setTagType(NBT::TAG_Compound);
$nbt->Motion->setTagType(NBT::TAG_Double);
$nbt->Rotation->setTagType(NBT::TAG_Float);
if(file_exists($path . "$name.yml")){ //Importing old PocketMine-MP files
$data = new Config($path . "$name.yml", Config::YAML, []);
$nbt["playerGameType"] = (int) $data->get("gamemode");
$nbt["Level"] = $data->get("position")["level"];
$nbt["Pos"][0] = $data->get("position")["x"];
$nbt["Pos"][1] = $data->get("position")["y"];
$nbt["Pos"][2] = $data->get("position")["z"];
$nbt["SpawnLevel"] = $data->get("spawn")["level"];
$nbt["SpawnX"] = (int) $data->get("spawn")["x"];
$nbt["SpawnY"] = (int) $data->get("spawn")["y"];
$nbt["SpawnZ"] = (int) $data->get("spawn")["z"];
$this->logger->notice("Old Player data found for \"" . $name . "\", upgrading profile");
foreach($data->get("inventory") as $slot => $item){
if(count($item) === 3){
$nbt->Inventory[$slot + 9] = new Compound(false, [
new Short("id", $item[0]),
new Short("Damage", $item[1]),
new Byte("Count", $item[2]),
new Byte("Slot", $slot + 9),
new Byte("TrueSlot", $slot + 9)
]);
}
}
foreach($data->get("hotbar") as $slot => $itemSlot){
if(isset($nbt->Inventory[$itemSlot + 9])){
$item = $nbt->Inventory[$itemSlot + 9];
$nbt->Inventory[$slot] = new Compound(false, [
new Short("id", $item["id"]),
new Short("Damage", $item["Damage"]),
new Byte("Count", $item["Count"]),
new Byte("Slot", $slot),
new Byte("TrueSlot", $item["TrueSlot"])
]);
}
}
foreach($data->get("armor") as $slot => $item){
if(count($item) === 2){
$nbt->Inventory[$slot + 100] = new Compound(false, [
new Short("id", $item[0]),
new Short("Damage", $item[1]),
new Byte("Count", 1),
new Byte("Slot", $slot + 100)
]);
}
}
foreach($data->get("achievements") as $achievement => $status){
$nbt->Achievements[$achievement] = new Byte($achievement, $status == true ? 1 : 0);
}
unlink($path . "$name.yml");
}
$this->saveOfflinePlayerData($name, $nbt);
return $nbt;
}
/**
@ -888,7 +943,7 @@ class Server{
* @return bool
*/
public function unloadLevel(Level $level, $forceUnload = false){
if($level->unload($forceUnload) === true and $this->isLevelLoaded($level->getFolderName())){
if($level->unload($forceUnload) === true){
unset($this->levels[$level->getID()]);
return true;
@ -904,11 +959,11 @@ class Server{
*
* @return bool
*
* @throws \Exception
* @throws LevelException
*/
public function loadLevel($name){
if(trim($name) === ""){
throw new \Exception("Invalid empty level name");
throw new LevelException("Invalid empty level name");
}
if($this->isLevelLoaded($name)){
return true;
@ -942,6 +997,8 @@ class Server{
$this->levels[$level->getID()] = $level;
$level->initLevel();
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
/*foreach($entities->getAll() as $entity){
@ -1055,9 +1112,9 @@ class Server{
return false;
}
$seed = $seed === null ? Binary::readInt(Utils::getRandomBytes(4, false)) : (int) $seed;
$seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed;
if($generator !== null and class_exists($generator) and is_subclass_of($generator, "pocketmine\\level\\generator\\Generator")){
if($generator !== null and class_exists($generator) and is_subclass_of($generator, Generator::class)){
$generator = new $generator($options);
}else{
$options["preset"] = $this->getConfigString("generator-settings", "");
@ -1075,6 +1132,8 @@ class Server{
$level = new Level($this, $name, $path, $provider);
$this->levels[$level->getID()] = $level;
$level->initLevel();
$this->getPluginManager()->callEvent(new LevelInitEvent($level));
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
@ -1085,14 +1144,14 @@ class Server{
$radiusSquared = ($this->getViewDistance() + 1) / M_PI;
$radius = ceil(sqrt($radiusSquared));
$centerX = $level->getSpawn()->getX() >> 4;
$centerZ = $level->getSpawn()->getZ() >> 4;
$centerX = $level->getSpawnLocation()->getX() >> 4;
$centerZ = $level->getSpawnLocation()->getZ() >> 4;
$order = [];
for($X = -$radius; $X <= $radius; ++$X){
for($Z = -$radius; $Z <= $radius; ++$Z){
$distance = ($X * $X) + ($Z * $Z);
$distance = $X ** 2 + $Z ** 2;
if($distance > $radiusSquared){
continue;
}
@ -1347,7 +1406,7 @@ class Server{
/**
* @return Config
*/
public function getOPs(){
public function getOps(){
return $this->operators;
}
@ -1397,11 +1456,12 @@ class Server{
$this->autoloader = $autoloader;
$this->logger = $logger;
$this->filePath = $filePath;
$this->dataPath = $dataPath;
$this->pluginPath = $pluginPath;
@mkdir($this->dataPath . "worlds/", 0777, true);
@mkdir($this->dataPath . "players/", 0777);
@mkdir($this->pluginPath, 0777);
@mkdir($dataPath . "worlds/", 0777);
@mkdir($dataPath . "players/", 0777);
@mkdir($pluginPath, 0777);
$this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
$this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
$this->entityMetadata = new EntityMetadataStore();
$this->playerMetadata = new PlayerMetadataStore();
@ -1419,7 +1479,8 @@ class Server{
$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
$this->banByIP->load();
$this->console = new CommandReader();
$this->consoleThreaded = new \Threaded();
$this->console = new CommandReader($this->consoleThreaded);
$version = new VersionString($this->getPocketMineVersion());
$this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
@ -1457,7 +1518,7 @@ class Server{
"level-type" => "DEFAULT",
"enable-query" => true,
"enable-rcon" => false,
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
"rcon.password" => substr(base64_encode(@Utils::getRandomBytes(20, false)), 3, 10),
"auto-save" => true,
]);
@ -1470,6 +1531,7 @@ class Server{
}
$this->maxPlayers = $this->getConfigInt("max-players", 20);
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
if(($memory = str_replace("B", "", strtoupper($this->getConfigString("memory-limit", "256M")))) !== false){
$value = ["M" => 1, "G" => 1024];
@ -1495,19 +1557,19 @@ class Server{
$this->logger->info("Advanced cache enabled");
}
Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 7);
Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 8);
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0){
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
}
$this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort());
define("BOOTUP_RANDOM", Utils::getRandomBytes(16));
define("BOOTUP_RANDOM", @Utils::getRandomBytes(16));
$this->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8));
$this->addInterface($this->mainInterface = new RakLibInterface($this));
$this->logger->info("This server is running " . $this->getName() . " version " . ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(false) . TextFormat::RESET . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0);
$this->logger->info("This server is running " . $this->getName() . " version " . ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0);
$this->logger->info($this->getName() . " is distributed under the LGPL License", true, true, 0);
PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins");
@ -1516,19 +1578,22 @@ class Server{
$this->consoleSender = new ConsoleCommandSender();
$this->commandMap = new SimpleCommandMap($this);
$this->registerEntities();
$this->registerTiles();
InventoryType::init();
Block::init();
Item::init();
TextWrapper::init();
$this->craftingManager = new CraftingManager();
$this->pluginManager = new PluginManager($this, $this->commandMap);
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
$this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false));
$this->pluginManager->registerInterface("pocketmine\\plugin\\PharPluginLoader");
$this->pluginManager->registerInterface(PharPluginLoader::class);
set_exception_handler([$this, "exceptionHandler"]);
register_shutdown_function([$this, "crashDump"]);
register_shutdown_function([$this, "forceShutdown"]);
$this->pluginManager->loadPlugins($this->pluginPath);
@ -1536,24 +1601,21 @@ class Server{
$this->enablePlugins(PluginLoadOrder::STARTUP);
$this->generationManager = new GenerationRequestManager($this);
LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\anvil\\Anvil");
LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\mcregion\\McRegion");
Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat");
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal");
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "default");
//Temporal workaround, pthreads static property nullification test
if(PluginManager::$pluginParentTimer === null){
$this->getLogger()->emergency("You are using an invalid pthreads version. Please update your binaries.");
kill(getmypid());
return;
if($this->getProperty("chunk-generation.use-async", true)){
$this->generationManager = new GenerationRequestManager($this);
}else{
$this->generationManager = new GenerationInstanceManager($this);
}
foreach($this->getProperty("worlds", []) as $name => $worldSetting){
LevelProviderManager::addProvider($this, Anvil::class);
LevelProviderManager::addProvider($this, McRegion::class);
Generator::addGenerator(Flat::class, "flat");
Generator::addGenerator(Normal::class, "normal");
Generator::addGenerator(Normal::class, "default");
foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){
if($this->loadLevel($name) === false){
$seed = $this->getProperty("worlds.$name.seed", time());
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
@ -1595,8 +1657,8 @@ class Server{
return;
}
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask("pocketmine\\utils\\Cache::cleanup"), $this->getProperty("ticks-per.cache-cleanup", 900), $this->getProperty("ticks-per.cache-cleanup", 900));
if($this->getConfigBoolean("auto-save", true) === true and $this->getProperty("ticks-per.autosave", 6000) > 0){
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([Cache::class, "cleanup"]), $this->getProperty("ticks-per.cache-cleanup", 900), $this->getProperty("ticks-per.cache-cleanup", 900));
if($this->getAutoSave() and $this->getProperty("ticks-per.autosave", 6000) > 0){
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "doAutoSave"]), $this->getProperty("ticks-per.autosave", 6000), $this->getProperty("ticks-per.autosave", 6000));
}
@ -1611,11 +1673,17 @@ class Server{
/**
* @param $message
* @param Player[]|null $recipients
*
* @return int
*/
public function broadcastMessage($message){
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
public function broadcastMessage($message, $recipients = null){
if(!is_array($recipients)){
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
}
foreach($recipients as $recipient){
$recipient->sendMessage($message);
}
}
/**
@ -1649,8 +1717,13 @@ class Server{
* @param DataPacket $packet
*/
public static function broadcastPacket(array $players, DataPacket $packet){
$packet->encode();
$packet->isEncoded = true;
foreach($players as $player){
$player->dataPacket(clone $packet);
$player->dataPacket($packet);
}
if(isset($packet->__encapsulatedPacket)){
unset($packet->__encapsulatedPacket);
}
}
@ -1709,8 +1782,14 @@ class Server{
* @param string $commandLine
*
* @return bool
*
* @throws \Exception
*/
public function dispatchCommand(CommandSender $sender, $commandLine){
if(!($sender instanceof CommandSender)){
throw new ServerException("CommandSender is not valid");
}
if($this->commandMap->dispatch($sender, $commandLine)){
return true;
}
@ -1760,7 +1839,7 @@ class Server{
$this->operators->reload();
$this->pluginManager->registerInterface("pocketmine\\plugin\\PharPluginLoader");
$this->pluginManager->registerInterface(PharPluginLoader::class);
$this->pluginManager->loadPlugins($this->pluginPath);
$this->enablePlugins(PluginLoadOrder::STARTUP);
$this->enablePlugins(PluginLoadOrder::POSTWORLD);
@ -1776,40 +1855,54 @@ class Server{
}
public function forceShutdown(){
$this->shutdown();
if($this->rcon instanceof RCON){
$this->rcon->stop();
if($this->hasStopped){
return;
}
if($this->getProperty("settings.upnp-forwarding", false) === true){
$this->logger->info("[UPnP] Removing port forward...");
UPnP::RemovePortForward($this->getPort());
try{
$this->hasStopped = true;
$this->shutdown();
if($this->rcon instanceof RCON){
$this->rcon->stop();
}
if($this->getProperty("settings.upnp-forwarding", false) === true){
$this->logger->info("[UPnP] Removing port forward...");
UPnP::RemovePortForward($this->getPort());
}
$this->pluginManager->disablePlugins();
foreach($this->players as $player){
$player->close(TextFormat::YELLOW . $player->getName() . " has left the game", $this->getProperty("settings.shutdown-message", "Server closed"));
}
foreach($this->getLevels() as $level){
$this->unloadLevel($level, true);
}
if($this->generationManager instanceof GenerationRequestManager){
$this->generationManager->shutdown();
}
HandlerList::unregisterAll();
$this->scheduler->cancelAllTasks();
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
$this->properties->save();
$this->console->kill();
foreach($this->interfaces as $interface){
$interface->shutdown();
}
}catch (\Exception $e){
$this->logger->emergency("Crashed while crashing, killing process");
@kill(getmypid());
}
$this->pluginManager->disablePlugins();
foreach($this->players as $player){
$player->close(TextFormat::YELLOW . $player->getName() . " has left the game", $this->getProperty("settings.shutdown-message", "Server closed"));
}
foreach($this->getLevels() as $level){
$this->unloadLevel($level, true);
}
if($this->generationManager instanceof GenerationRequestManager){
$this->generationManager->shutdown();
}
HandlerList::unregisterAll();
$this->scheduler->cancelAllTasks();
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
$this->properties->save();
$this->console->kill();
foreach($this->interfaces as $interface){
$interface->shutdown();
}
}
/**
@ -1878,25 +1971,52 @@ class Server{
}
}
public function exceptionHandler(\Exception $e){
public function exceptionHandler(\Exception $e, $trace = null){
if($e === null){
return;
}
error_handler(E_ERROR, $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace());
global $lastError;
$errstr = $e->getMessage();
$errfile = $e->getFile();
$errno = $e->getCode();
$errline = $e->getLine();
$type = ($errno === E_ERROR or $errno === E_USER_ERROR) ? \LogLevel::ERROR : (($errno === E_USER_WARNING or $errno === E_WARNING) ? \LogLevel::WARNING : \LogLevel::NOTICE);
if(($pos = strpos($errstr, "\n")) !== false){
$errstr = substr($errstr, 0, $pos);
}
$errfile = cleanPath($errfile);
if($this->logger instanceof MainLogger){
$this->logger->logException($e, $trace);
}
$lastError = [
"type" => $type,
"message" => $errstr,
"fullFile" => $e->getFile(),
"file" => $errfile,
"line" => $errline,
"trace" => @getTrace($trace === null ? 3 : 0, $trace)
];
global $lastExceptionError, $lastError;
$lastExceptionError = $lastError;
$this->crashDump();
$this->forceShutdown();
kill(getmypid());
exit(1);
}
public function crashDump(){
if($this->isRunning === false){
return;
}
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
$this->isRunning = false;
$this->hasStopped = false;
ini_set("error_reporting", 0);
ini_set("memory_limit", -1); //Fix error dump not dumped on memory problems
$this->logger->emergency("An unrecoverable error has occurred and the server has crashed. Creating a crash dump");
$dump = new CrashDump($this);
@ -1904,44 +2024,49 @@ class Server{
if($this->getProperty("auto-report.enabled", true) !== false){
$report = true;
$plugin = $dump->getData()["plugin"];
if(is_string($plugin)){
$p = $this->pluginManager->getPlugin($plugin);
if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
return;
$report = false;
}
}elseif(\Phar::running(true) == ""){
return;
$report = false;
}
if($dump->getData()["type"] === "E_PARSE" or $dump->getData()["type"] === "E_COMPILE_ERROR"){
return;
if($dump->getData()["error"]["type"] === "E_PARSE" or $dump->getData()["error"]["type"] === "E_COMPILE_ERROR"){
$report = false;
}
$reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [
"report" => "yes",
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
"email" => "crash@pocketmine.net",
"reportPaste" => base64_encode($dump->getEncodedData())
]);
if($report){
$reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [
"report" => "yes",
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
"email" => "crash@pocketmine.net",
"reportPaste" => base64_encode($dump->getEncodedData())
]);
if(($data = json_decode($reply)) !== false and isset($data->crashId)){
$reportId = $data->crashId;
$reportUrl = $data->crashUrl;
$this->logger->emergency("The crash dump has been automatically submitted to the Crash Archive. You can view it on $reportUrl or use the ID #$reportId.");
if(($data = json_decode($reply)) !== false and isset($data->crashId)){
$reportId = $data->crashId;
$reportUrl = $data->crashUrl;
$this->logger->emergency("The crash dump has been automatically submitted to the Crash Archive. You can view it on $reportUrl or use the ID #$reportId.");
}
}
}
//$this->checkMemory();
//$dump .= "Memory Usage Tracking: \r\n" . chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9))) . "\r\n";
$this->forceShutdown();
@kill(getmypid());
exit(1);
}
public function __debugInfo(){
return get_class($this);
return [];
}
private function tickProcessor(){
$lastLoop = 0;
while($this->isRunning){
$this->tick();
usleep((int) max(1, ($this->nextTick - microtime(true)) * 1000000));
@ -1956,24 +2081,33 @@ class Server{
//Do level ticks
foreach($this->getLevels() as $level){
$level->doTick($currentTick);
try{
$level->doTick($currentTick);
}catch (\Exception $e){
$this->logger->critical("Could not tick level ".$level->getName().": ".$e->getMessage());
if($this->logger instanceof MainLogger){
$this->logger->logException($e);
}
}
}
}
public function doAutoSave(){
Timings::$worldSaveTimer->startTiming();
foreach($this->getOnlinePlayers() as $index => $player){
if($player->isOnline()){
$player->save();
}elseif(!$player->isConnected()){
unset($this->players[$index]);
if($this->getAutoSave()){
Timings::$worldSaveTimer->startTiming();
foreach($this->getOnlinePlayers() as $index => $player){
if($player->isOnline()){
$player->save();
}elseif(!$player->isConnected()){
unset($this->players[$index]);
}
}
}
foreach($this->getLevels() as $level){
$level->save(false);
foreach($this->getLevels() as $level){
$level->save(false);
}
Timings::$worldSaveTimer->stopTiming();
}
Timings::$worldSaveTimer->stopTiming();
}
public function doLevelGC(){
@ -1997,13 +2131,14 @@ class Server{
$version = new VersionString();
$this->lastSendUsage = new SendUsageTask("http://stats.pocketmine.net/usage.php", [
"serverid" => Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . ":" . $this->getPort()), 0, 8)),
"serverid" => $this->serverID,
"port" => $this->getPort(),
"os" => Utils::getOS(),
"name" => $this->getName(),
"memory_total" => $this->getConfigString("memory-limit"),
"memory_usage" => memory_get_usage(),
"php_version" => PHP_VERSION,
"version" => $version->get(false),
"version" => $version->get(true),
"build" => $version->getBuild(),
"mc_version" => \pocketmine\MINECRAFT_VERSION,
"protocol" => network\protocol\Info::CURRENT_PROTOCOL,
@ -2052,11 +2187,30 @@ class Server{
if(($this->tickCounter & 0b1111) === 0){
$this->titleTick();
if(isset($this->queryHandler) and ($this->tickCounter & 0b111111111) === 0){
$this->queryHandler->regenerateInfo();
try{
$this->queryHandler->regenerateInfo();
}catch(\Exception $e){
if($this->logger instanceof MainLogger){
$this->logger->logException($e);
}
}
}
}
try{
$this->generationManager->process();
}catch (\Exception $e){
if($this->logger instanceof MainLogger){
$this->logger->logException($e);
}
}
if(($this->tickCounter % 100) === 0){
foreach($this->levels as $level){
$level->clearCache();
}
}
$this->generationManager->handlePackets();
Timings::$serverTickTimer->stopTiming();
@ -2072,9 +2226,26 @@ class Server{
$this->nextTick = $tickTime;
}
$this->nextTick += 0.05;
$this->inTick = false;
return true;
}
private function registerEntities(){
Entity::registerEntity(Arrow::class);
Entity::registerEntity(DroppedItem::class);
Entity::registerEntity(FallingSand::class);
Entity::registerEntity(PrimedTNT::class);
Entity::registerEntity(Snowball::class);
Entity::registerEntity(Villager::class);
Entity::registerEntity(Zombie::class);
Entity::registerEntity(Human::class, true);
}
private function registerTiles(){
Tile::registerTile(Chest::class);
Tile::registerTile(Furnace::class);
Tile::registerTile(Sign::class);
}
}

View File

@ -35,7 +35,7 @@ class Bed extends Transparent{
$this->hardness = 1;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x,
$this->y,
@ -53,7 +53,7 @@ class Bed extends Transparent{
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
if($player instanceof Player and !$isNight){
$pk = new ChatPacket;
$pk = new ChatPacket();
$pk->message = "You can only sleep at night";
$player->dataPacket($pk);
@ -77,7 +77,7 @@ class Bed extends Transparent{
$b = $blockWest;
}else{
if($player instanceof Player){
$pk = new ChatPacket;
$pk = new ChatPacket();
$pk->message = "This bed is incomplete";
$player->dataPacket($pk);
}
@ -87,7 +87,7 @@ class Bed extends Transparent{
}
if($player instanceof Player and $player->sleepOn($b) === false){
$pk = new ChatPacket;
$pk = new ChatPacket();
$pk->message = "This bed is occupied";
$player->dataPacket($pk);
}

View File

@ -22,65 +22,10 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
class Beetroot extends Flowable{
class Beetroot extends Crops{
public function __construct($meta = 0){
parent::__construct(self::BEETROOT_BLOCK, $meta, "Beetroot Block");
$this->isActivable = true;
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$this->meta = 0x07;
$this->getLevel()->setBlock($this, $this, true, true);
$item->count--;
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
$this->getLevel()->dropItem($this, Item::get(Item::BEETROOT_SEEDS, 0, 1));
$this->getLevel()->setBlock($this, new Air(), false);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
++$this->meta;
$this->getLevel()->setBlock($this, $this, true);
return Level::BLOCK_UPDATE_RANDOM;
}
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
}
return false;
}
public function getDrops(Item $item){

View File

@ -39,7 +39,7 @@ use pocketmine\Player;
use pocketmine\plugin\Plugin;
abstract class Block extends Position implements Metadatable{
class Block extends Position implements Metadatable{
const AIR = 0;
const STONE = 1;
const GRASS = 2;
@ -144,6 +144,7 @@ abstract class Block extends Position implements Metadatable{
const SUGARCANE_BLOCK = 83;
const FENCE = 85;
const FENCE_OAK = 85;
const PUMPKIN = 86;
const NETHERRACK = 87;
const SOUL_SAND = 88;
@ -167,7 +168,8 @@ abstract class Block extends Position implements Metadatable{
const MELON_BLOCK = 103;
const PUMPKIN_STEM = 104;
const MELON_STEM = 105;
const VINE = 106;
const VINES = 106;
const FENCE_GATE = 107;
const BRICK_STAIRS = 108;
const STONE_BRICK_STAIRS = 109;
@ -227,6 +229,17 @@ abstract class Block extends Position implements Metadatable{
const HARDENED_CLAY = 172;
const COAL_BLOCK = 173;
const FENCE_GATE_SPRUCE = 183;
const FENCE_GATE_BIRCH = 184;
const FENCE_GATE_JUNGLE = 185;
const FENCE_GATE_DARK_OAK = 186;
const FENCE_GATE_ACACIA = 187;
const FENCE_SPRUCE = 188;
const FENCE_BIRCH = 189;
const FENCE_JUNGLE = 190;
const FENCE_DARK_OAK = 191;
const FENCE_ACACIA = 192;
const PODZOL = 243;
const BEETROOT_BLOCK = 244;
const STONECUTTER = 245;
@ -345,7 +358,7 @@ abstract class Block extends Position implements Metadatable{
[Item::SNOW_LAYER, 0],
[Item::GLASS, 0],
[Item::GLOWSTONE_BLOCK, 0],
//TODO: Vines
[Item::VINES, 0],
[Item::NETHER_REACTOR, 0],
[Item::LADDER, 0],
[Item::SPONGE, 0],
@ -353,7 +366,16 @@ abstract class Block extends Position implements Metadatable{
[Item::WOODEN_DOOR, 0],
[Item::TRAPDOOR, 0],
[Item::FENCE, 0],
[Item::FENCE_SPRUCE, 0],
[Item::FENCE_BIRCH, 0],
[Item::FENCE_DARK_OAK, 0],
[Item::FENCE_JUNGLE, 0],
[Item::FENCE_GATE, 0],
[Item::FENCE_GATE_BIRCH, 0],
[Item::FENCE_GATE_SPRUCE, 0],
[Item::FENCE_GATE_DARK_OAK, 0],
[Item::FENCE_GATE_JUNGLE, 0],
[Item::FENCE_GATE_ACACIA, 0],
[Item::IRON_BARS, 0],
[Item::BED, 0],
[Item::BOOKSHELF, 0],
@ -362,7 +384,6 @@ abstract class Block extends Position implements Metadatable{
[Item::STONECUTTER, 0],
[Item::CHEST, 0],
[Item::FURNACE, 0],
//TODO: End Portal
[Item::END_PORTAL, 0],
[Item::DANDELION, 0],
[Item::POPPY, 0],
@ -505,13 +526,22 @@ abstract class Block extends Position implements Metadatable{
];
/** @var Block[] */
public static $list = [];
/** @var \SplFixedArray */
public static $list = null;
/** @var \SplFixedArray */
public static $light = null;
/** @var \SplFixedArray */
public static $lightFilter = null;
/** @var \SplFixedArray */
public static $solid = null;
/** @var \SplFixedArray */
public static $transparent = null;
protected $id;
protected $meta;
protected $name = "Unknown";
protected $breakTime = 0.20;
protected $hardness = 10;
public $hasEntityCollision = false;
public $isActivable = false;
public $breakable = true;
public $isFlowable = false;
@ -520,153 +550,196 @@ abstract class Block extends Position implements Metadatable{
public $isReplaceable = false;
public $isPlaceable = true;
public $hasPhysics = false;
public $isLiquid = false;
public $isFullBlock = true;
public $lightLevel = 0;
public $x = 0;
public $y = 0;
public $z = 0;
public $frictionFactor = 0.6;
/** @var AxisAlignedBB */
protected $boundingBox = null;
public static function init(){
if(count(self::$list) === 0){
self::$list = [
self::AIR => Air::class,
self::STONE => Stone::class,
self::GRASS => Grass::class,
self::DIRT => Dirt::class,
self::COBBLESTONE => Cobblestone::class,
self::PLANKS => Planks::class,
self::SAPLING => Sapling::class,
self::BEDROCK => Bedrock::class,
self::WATER => Water::class,
self::STILL_WATER => StillWater::class,
self::LAVA => Lava::class,
self::STILL_LAVA => StillLava::class,
self::SAND => Sand::class,
self::GRAVEL => Gravel::class,
self::GOLD_ORE => GoldOre::class,
self::IRON_ORE => IronOre::class,
self::COAL_ORE => CoalOre::class,
self::WOOD => Wood::class,
self::LEAVES => Leaves::class,
self::SPONGE => Sponge::class,
self::GLASS => Glass::class,
self::LAPIS_ORE => LapisOre::class,
self::LAPIS_BLOCK => Lapis::class,
self::SANDSTONE => Sandstone::class,
self::BED_BLOCK => Bed::class,
self::COBWEB => Cobweb::class,
self::TALL_GRASS => TallGrass::class,
self::DEAD_BUSH => DeadBush::class,
self::WOOL => Wool::class,
self::DANDELION => Dandelion::class,
self::POPPY => CyanFlower::class,
self::BROWN_MUSHROOM => BrownMushroom::class,
self::RED_MUSHROOM => RedMushroom::class,
self::GOLD_BLOCK => Gold::class,
self::IRON_BLOCK => Iron::class,
self::DOUBLE_SLAB => DoubleSlab::class,
self::SLAB => Slab::class,
self::BRICKS_BLOCK => Bricks::class,
self::TNT => TNT::class,
self::BOOKSHELF => Bookshelf::class,
self::MOSS_STONE => MossStone::class,
self::OBSIDIAN => Obsidian::class,
self::TORCH => Torch::class,
self::FIRE => Fire::class,
self::MONSTER_SPAWNER => MonsterSpawner::class,
self::WOOD_STAIRS => WoodStairs::class,
self::CHEST => Chest::class,
if(self::$list === null){
self::$list = new \SplFixedArray(256);
self::$light = new \SplFixedArray(256);
self::$lightFilter = new \SplFixedArray(256);
self::$solid = new \SplFixedArray(256);
self::$transparent = new \SplFixedArray(256);
self::$list[self::AIR] = Air::class;;
self::$list[self::STONE] = Stone::class;;
self::$list[self::GRASS] = Grass::class;;
self::$list[self::DIRT] = Dirt::class;;
self::$list[self::COBBLESTONE] = Cobblestone::class;;
self::$list[self::PLANKS] = Planks::class;;
self::$list[self::SAPLING] = Sapling::class;;
self::$list[self::BEDROCK] = Bedrock::class;;
self::$list[self::WATER] = Water::class;;
self::$list[self::STILL_WATER] = StillWater::class;;
self::$list[self::LAVA] = Lava::class;;
self::$list[self::STILL_LAVA] = StillLava::class;;
self::$list[self::SAND] = Sand::class;;
self::$list[self::GRAVEL] = Gravel::class;;
self::$list[self::GOLD_ORE] = GoldOre::class;;
self::$list[self::IRON_ORE] = IronOre::class;;
self::$list[self::COAL_ORE] = CoalOre::class;;
self::$list[self::WOOD] = Wood::class;;
self::$list[self::LEAVES] = Leaves::class;;
self::$list[self::SPONGE] = Sponge::class;;
self::$list[self::GLASS] = Glass::class;;
self::$list[self::LAPIS_ORE] = LapisOre::class;;
self::$list[self::LAPIS_BLOCK] = Lapis::class;;
self::$list[self::SANDSTONE] = Sandstone::class;;
self::$list[self::BED_BLOCK] = Bed::class;;
self::$list[self::COBWEB] = Cobweb::class;;
self::$list[self::TALL_GRASS] = TallGrass::class;;
self::$list[self::DEAD_BUSH] = DeadBush::class;;
self::$list[self::WOOL] = Wool::class;;
self::$list[self::DANDELION] = Dandelion::class;;
self::$list[self::POPPY] = CyanFlower::class;;
self::$list[self::BROWN_MUSHROOM] = BrownMushroom::class;;
self::$list[self::RED_MUSHROOM] = RedMushroom::class;;
self::$list[self::GOLD_BLOCK] = Gold::class;;
self::$list[self::IRON_BLOCK] = Iron::class;;
self::$list[self::DOUBLE_SLAB] = DoubleSlab::class;;
self::$list[self::SLAB] = Slab::class;;
self::$list[self::BRICKS_BLOCK] = Bricks::class;;
self::$list[self::TNT] = TNT::class;;
self::$list[self::BOOKSHELF] = Bookshelf::class;;
self::$list[self::MOSS_STONE] = MossStone::class;;
self::$list[self::OBSIDIAN] = Obsidian::class;;
self::$list[self::TORCH] = Torch::class;;
self::$list[self::FIRE] = Fire::class;;
self::$list[self::MONSTER_SPAWNER] = MonsterSpawner::class;;
self::$list[self::WOOD_STAIRS] = WoodStairs::class;;
self::$list[self::CHEST] = Chest::class;;
self::DIAMOND_ORE => DiamondOre::class,
self::DIAMOND_BLOCK => Diamond::class,
self::WORKBENCH => Workbench::class,
self::WHEAT_BLOCK => Wheat::class,
self::FARMLAND => Farmland::class,
self::FURNACE => Furnace::class,
self::BURNING_FURNACE => BurningFurnace::class,
self::SIGN_POST => SignPost::class,
self::WOOD_DOOR_BLOCK => WoodDoor::class,
self::LADDER => Ladder::class,
self::$list[self::DIAMOND_ORE] = DiamondOre::class;;
self::$list[self::DIAMOND_BLOCK] = Diamond::class;;
self::$list[self::WORKBENCH] = Workbench::class;;
self::$list[self::WHEAT_BLOCK] = Wheat::class;;
self::$list[self::FARMLAND] = Farmland::class;;
self::$list[self::FURNACE] = Furnace::class;;
self::$list[self::BURNING_FURNACE] = BurningFurnace::class;;
self::$list[self::SIGN_POST] = SignPost::class;;
self::$list[self::WOOD_DOOR_BLOCK] = WoodDoor::class;;
self::$list[self::LADDER] = Ladder::class;;
self::COBBLESTONE_STAIRS => CobblestoneStairs::class,
self::WALL_SIGN => WallSign::class,
self::$list[self::COBBLESTONE_STAIRS] = CobblestoneStairs::class;;
self::$list[self::WALL_SIGN] = WallSign::class;;
self::IRON_DOOR_BLOCK => IronDoor::class,
self::REDSTONE_ORE => RedstoneOre::class,
self::GLOWING_REDSTONE_ORE => GlowingRedstoneOre::class,
self::$list[self::IRON_DOOR_BLOCK] = IronDoor::class;;
self::$list[self::REDSTONE_ORE] = RedstoneOre::class;;
self::$list[self::GLOWING_REDSTONE_ORE] = GlowingRedstoneOre::class;;
self::SNOW_LAYER => SnowLayer::class,
self::ICE => Ice::class,
self::SNOW_BLOCK => Snow::class,
self::CACTUS => Cactus::class,
self::CLAY_BLOCK => Clay::class,
self::SUGARCANE_BLOCK => Sugarcane::class,
self::$list[self::SNOW_LAYER] = SnowLayer::class;;
self::$list[self::ICE] = Ice::class;;
self::$list[self::SNOW_BLOCK] = Snow::class;;
self::$list[self::CACTUS] = Cactus::class;;
self::$list[self::CLAY_BLOCK] = Clay::class;;
self::$list[self::SUGARCANE_BLOCK] = Sugarcane::class;;
self::FENCE => Fence::class,
self::PUMPKIN => Pumpkin::class,
self::NETHERRACK => Netherrack::class,
self::SOUL_SAND => SoulSand::class,
self::GLOWSTONE_BLOCK => Glowstone::class,
self::$list[self::FENCE] = Fence::class;;
self::$list[self::PUMPKIN] = Pumpkin::class;;
self::$list[self::NETHERRACK] = Netherrack::class;;
self::$list[self::SOUL_SAND] = SoulSand::class;;
self::$list[self::GLOWSTONE_BLOCK] = Glowstone::class;;
self::LIT_PUMPKIN => LitPumpkin::class,
self::CAKE_BLOCK => Cake::class,
self::$list[self::LIT_PUMPKIN] = LitPumpkin::class;;
self::$list[self::CAKE_BLOCK] = Cake::class;;
self::TRAPDOOR => Trapdoor::class,
self::$list[self::TRAPDOOR] = Trapdoor::class;;
self::STONE_BRICKS => StoneBricks::class,
self::$list[self::STONE_BRICKS] = StoneBricks::class;;
self::IRON_BARS => IronBars::class,
self::GLASS_PANE => GlassPane::class,
self::MELON_BLOCK => Melon::class,
self::PUMPKIN_STEM => PumpkinStem::class,
self::MELON_STEM => MelonStem::class,
self::$list[self::IRON_BARS] = IronBars::class;;
self::$list[self::GLASS_PANE] = GlassPane::class;;
self::$list[self::MELON_BLOCK] = Melon::class;;
self::$list[self::PUMPKIN_STEM] = PumpkinStem::class;;
self::$list[self::MELON_STEM] = MelonStem::class;;
self::$list[self::VINE] = Vine::class;;
self::$list[self::FENCE_GATE] = FenceGate::class;;
self::$list[self::BRICK_STAIRS] = BrickStairs::class;;
self::$list[self::STONE_BRICK_STAIRS] = StoneBrickStairs::class;;
self::FENCE_GATE => FenceGate::class,
self::BRICK_STAIRS => BrickStairs::class,
self::STONE_BRICK_STAIRS => StoneBrickStairs::class,
self::$list[self::MYCELIUM] = Mycelium::class;;
self::$list[self::NETHER_BRICKS] = NetherBrick::class;;
self::MYCELIUM => Mycelium::class,
self::NETHER_BRICKS => NetherBrick::class,
self::$list[self::NETHER_BRICKS_STAIRS] = NetherBrickStairs::class;;
self::NETHER_BRICKS_STAIRS => NetherBrickStairs::class,
self::$list[self::END_PORTAL] = EndPortal::class;;
self::$list[self::END_STONE] = EndStone::class;;
self::$list[self::SANDSTONE_STAIRS] = SandstoneStairs::class;;
self::$list[self::EMERALD_ORE] = EmeraldOre::class;;
self::END_PORTAL => EndPortal::class,
self::END_STONE => EndStone::class,
self::SANDSTONE_STAIRS => SandstoneStairs::class,
self::EMERALD_ORE => EmeraldOre::class,
self::$list[self::EMERALD_BLOCK] = Emerald::class;;
self::$list[self::SPRUCE_WOOD_STAIRS] = SpruceWoodStairs::class;;
self::$list[self::BIRCH_WOOD_STAIRS] = BirchWoodStairs::class;;
self::$list[self::JUNGLE_WOOD_STAIRS] = JungleWoodStairs::class;;
self::$list[self::STONE_WALL] = StoneWall::class;;
self::EMERALD_BLOCK => Emerald::class,
self::SPRUCE_WOOD_STAIRS => SpruceWoodStairs::class,
self::BIRCH_WOOD_STAIRS => BirchWoodStairs::class,
self::JUNGLE_WOOD_STAIRS => JungleWoodStairs::class,
self::STONE_WALL => StoneWall::class,
self::$list[self::CARROT_BLOCK] = Carrot::class;;
self::$list[self::POTATO_BLOCK] = Potato::class;;
self::CARROT_BLOCK => Carrot::class,
self::POTATO_BLOCK => Potato::class,
self::$list[self::QUARTZ_BLOCK] = Quartz::class;;
self::$list[self::QUARTZ_STAIRS] = QuartzStairs::class;;
self::$list[self::DOUBLE_WOOD_SLAB] = DoubleWoodSlab::class;;
self::$list[self::WOOD_SLAB] = WoodSlab::class;;
self::$list[self::STAINED_CLAY] = StainedClay::class;;
self::QUARTZ_BLOCK => Quartz::class,
self::QUARTZ_STAIRS => QuartzStairs::class,
self::DOUBLE_WOOD_SLAB => DoubleWoodSlab::class,
self::WOOD_SLAB => WoodSlab::class,
self::STAINED_CLAY => StainedClay::class,
self::$list[self::LEAVES2] = Leaves2::class;;
self::$list[self::WOOD2] = Wood2::class;;
self::$list[self::ACACIA_WOOD_STAIRS] = AcaciaWoodStairs::class;;
self::$list[self::DARK_OAK_WOOD_STAIRS] = DarkOakWoodStairs::class;;
self::LEAVES2 => Leaves2::class,
self::WOOD2 => Wood2::class,
self::ACACIA_WOOD_STAIRS => AcaciaWoodStairs::class,
self::DARK_OAK_WOOD_STAIRS => DarkOakWoodStairs::class,
self::$list[self::HAY_BALE] = HayBale::class;;
self::$list[self::CARPET] = Carpet::class;;
self::$list[self::HARDENED_CLAY] = HardenedClay::class;;
self::$list[self::COAL_BLOCK] = Coal::class;;
self::HAY_BALE => HayBale::class,
self::CARPET => Carpet::class,
self::HARDENED_CLAY => HardenedClay::class,
self::COAL_BLOCK => Coal::class,
self::$list[self::FENCE_GATE_SPRUCE] = FenceGateSpruce::class;
self::$list[self::FENCE_GATE_BIRCH] = FenceGateBirch::class;
self::$list[self::FENCE_GATE_JUNGLE] = FenceGateJungle::class;
self::$list[self::FENCE_GATE_DARK_OAK] = FenceGateDarkOak::class;
self::$list[self::FENCE_GATE_ACACIA] = FenceGateAcacia::class;
self::$list[self::FENCE_SPRUCE] = FenceSpruce::class;
self::$list[self::FENCE_BIRCH] = FenceBirch::class;
self::$list[self::FENCE_DARK_OAK] = FenceDarkOak::class;
self::$list[self::FENCE_JUNGLE] = FenceJungle::class;
self::$list[self::FENCE_ACACIA] = FenceAcacia::class;
self::PODZOL => Podzol::class,
self::BEETROOT_BLOCK => Beetroot::class,
self::STONECUTTER => Stonecutter::class,
self::GLOWING_OBSIDIAN => GlowingObsidian::class,
self::NETHER_REACTOR => NetherReactor::class,
];
self::$list[self::PODZOL] = Podzol::class;
self::$list[self::BEETROOT_BLOCK] = Beetroot::class;
self::$list[self::STONECUTTER] = Stonecutter::class;
self::$list[self::GLOWING_OBSIDIAN] = GlowingObsidian::class;
self::$list[self::NETHER_REACTOR] = NetherReactor::class;
foreach(self::$list as $id => $class){
if($class !== null){
/** @var Block $block */
$block = new $class();
self::$solid[$id] = (bool) $block->isSolid;
self::$transparent[$id] = (bool) $block->isTransparent;
self::$light[$id] = (int) $block->lightLevel;
if($block->isSolid){
if($block->isTransparent){
if($block instanceof Liquid or $block instanceof Ice){
self::$lightFilter[$id] = 2;
}else{
self::$lightFilter[$id] = 1;
}
}else{
self::$lightFilter[$id] = 15;
}
}else{
self::$lightFilter[$id] = 1;
}
}else{
self::$lightFilter[$id] = 1;
}
}
}
}
@ -678,15 +751,22 @@ abstract class Block extends Position implements Metadatable{
* @return Block
*/
public static function get($id, $meta = 0, Position $pos = null){
if(isset(self::$list[$id])){
try{
$block = self::$list[$id];
$block = new $block($meta);
}else{
$block = new Generic($id, $meta);
if($block !== null){
$block = new $block($meta);
}else{
$block = new Block($id, $meta);
}
}catch(\RuntimeException $e){
$block = new Block($id, $meta);
}
if($pos instanceof Position){
$block->position($pos);
if($pos !== null){
$block->x = $pos->x;
$block->y = $pos->y;
$block->z = $pos->z;
$block->level = $pos->level;
}
return $block;
@ -703,6 +783,69 @@ abstract class Block extends Position implements Metadatable{
$this->name = $name;
}
/**
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
*
* @param Item $item
* @param Block $block
* @param Block $target
* @param int $face
* @param float $fx
* @param float $fy
* @param float $fz
* @param Player $player = null
*
* @return bool
*/
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
return $this->getLevel()->setBlock($this, $this, true, true);
}
/**
* Returns if the item can be broken with an specific Item
*
* @param Item $item
*
* @return bool
*/
public function isBreakable(Item $item){
return $this->breakable;
}
/**
* Do the actions needed so the block is broken with the Item
*
* @param Item $item
*
* @return mixed
*/
public function onBreak(Item $item){
return $this->getLevel()->setBlock($this, new Air(), true, true);
}
/**
* Fires a block update on the Block
*
* @param int $type
*
* @return void
*/
public function onUpdate($type){
}
/**
* Do actions when activated by Item. Returns if it has done anything
*
* @param Item $item
* @param Player $player
*
* @return bool
*/
public function onActivate(Item $item, Player $player = null){
return $this->isActivable;
}
/**
* @return int
*/
@ -720,10 +863,14 @@ abstract class Block extends Position implements Metadatable{
/**
* @return int
*/
final public function getID(){
final public function getId(){
return $this->id;
}
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
}
/**
* @return int
*/
@ -802,24 +949,6 @@ abstract class Block extends Position implements Metadatable{
return "Block " . $this->name . " (" . $this->id . ":" . $this->meta . ")";
}
/**
* Returns if the item can be broken with an specific Item
*
* @param Item $item
*
* @return bool
*/
abstract function isBreakable(Item $item);
/**
* Do the actions needed so the block is broken with the Item
*
* @param Item $item
*
* @return mixed
*/
abstract function onBreak(Item $item);
/**
* Checks for collision against an AxisAlignedBB
*
@ -844,6 +973,17 @@ abstract class Block extends Position implements Metadatable{
* @return AxisAlignedBB
*/
public function getBoundingBox(){
if($this->boundingBox !== null){
return $this->boundingBox;
}else{
return $this->boundingBox = $this->recalculateBoundingBox();
}
}
/**
* @return AxisAlignedBB
*/
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x,
$this->y,
@ -936,41 +1076,6 @@ abstract class Block extends Position implements Metadatable{
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
}
/**
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
*
* @param Item $item
* @param Block $block
* @param Block $target
* @param int $face
* @param float $fx
* @param float $fy
* @param float $fz
* @param Player $player = null
*
* @return bool
*/
abstract function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null);
/**
* Do actions when activated by Item. Returns if it has done anything
*
* @param Item $item
* @param Player $player
*
* @return bool
*/
abstract function onActivate(Item $item, Player $player = null);
/**
* Fires a block update on the Block
*
* @param int $type
*
* @return void
*/
abstract function onUpdate($type);
public function setMetadata($metadataKey, MetadataValue $metadataValue){
if($this->getLevel() instanceof Level){
$this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $metadataValue);

View File

@ -26,6 +26,9 @@ use pocketmine\level\Level;
use pocketmine\Player;
class BrownMushroom extends Flowable{
public $lightLevel = 1;
public function __construct(){
parent::__construct(self::BROWN_MUSHROOM, 0, "Brown Mushroom");
$this->hardness = 0;
@ -33,9 +36,8 @@ class BrownMushroom extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
$this->getLevel()->dropItem($this, Item::get($this->id));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -32,6 +32,9 @@ use pocketmine\tile\Furnace;
use pocketmine\tile\Tile;
class BurningFurnace extends Solid{
public $lightLevel = 13;
public function __construct($meta = 0){
parent::__construct(self::BURNING_FURNACE, $meta, "Burning Furnace");
$this->isActivable = true;
@ -55,13 +58,13 @@ class BurningFurnace extends Solid{
new Int("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
new Furnace($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
return true;
}
public function onBreak(Item $item){
$this->getLevel()->setBlock($this, new Air(), true, true, true);
$this->getLevel()->setBlock($this, new Air(), true, true);
return true;
}
@ -81,7 +84,7 @@ class BurningFurnace extends Solid{
new Int("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
$furnace = new Furnace($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
$furnace = Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
}
if(($player->getGamemode() & 0x01) === 0x01){
@ -116,15 +119,6 @@ class BurningFurnace extends Solid{
if($item->isPickaxe() >= 1){
$drops[] = [Item::FURNACE, 0, 1];
}
$t = $this->getLevel()->getTile($this);
if($t instanceof Furnace){
for($s = 0; $s < $t->getInventory()->getSize(); ++$s){
$slot = $t->getInventory()->getItem($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$drops[] = [$slot->getID(), $slot->getDamage(), $slot->getCount()];
}
}
}
return $drops;
}

View File

@ -21,23 +21,29 @@
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\entity\Entity;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\Server;
class Cactus extends Transparent{
public $hasEntityCollision = true;
public function __construct($meta = 0){
parent::__construct(self::CACTUS, $meta, "Cactus");
$this->isFullBlock = false;
$this->hardness = 2;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x + 0.0625,
$this->y,
@ -49,29 +55,20 @@ class Cactus extends Transparent{
}
public function onEntityCollide(Entity $entity){
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_CONTACT, 1);
Server::getInstance()->getPluginManager()->callEvent($ev);
if(!$ev->isCancelled()){
$entity->attack($ev->getFinalDamage(), $ev);
}
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
$entity->attack($ev->getFinalDamage(), $ev);
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(0);
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){ //Replace with common break method
$this->getLevel()->setBlock($this, new Air(), false);
$this->getLevel()->dropItem($this, Item::get($this->id));
return;
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){
$this->getLevel()->useBreakOn($this);
}else{
for($side = 2; $side <= 5; ++$side){
$b = $this->getSide($side);
if(!$b->isFlowable){
$this->getLevel()->setBlock($this, new Air(), false);
$this->getLevel()->dropItem($this, Item::get($this->id));
return;
$this->getLevel()->useBreakOn($this);
}
}
}
@ -81,8 +78,10 @@ class Cactus extends Transparent{
for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
if($b->getID() === self::AIR){
$this->getLevel()->setBlock($b, new Cactus(), true);
break;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Cactus()));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
}
}
}
$this->meta = 0;
@ -91,8 +90,6 @@ class Cactus extends Transparent{
++$this->meta;
$this->getLevel()->setBlock($this, $this);
}
return;
}
}

View File

@ -21,10 +21,12 @@
namespace pocketmine\block;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\Player;
use pocketmine\Server;
class Cake extends Transparent{
public function __construct($meta = 0){
@ -35,7 +37,8 @@ class Cake extends Transparent{
$this->hardness = 2.5;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$f = (1 + $this->getDamage() * 2) / 16;
return new AxisAlignedBB(
@ -78,7 +81,10 @@ class Cake extends Transparent{
public function onActivate(Item $item, Player $player = null){
if($player instanceof Player and $player->getHealth() < 20){
++$this->meta;
$player->heal(3, "cake");
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($player, 3, EntityRegainHealthEvent::CAUSE_EATING));
if(!$ev->isCancelled()){
$player->heal($ev->getAmount(), $ev);
}
if($this->meta >= 0x06){
$this->getLevel()->setBlock($this, new Air(), true);
}else{

View File

@ -53,7 +53,8 @@ class Carpet extends Flowable{
$this->isSolid = true;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x,
$this->y,
@ -77,9 +78,8 @@ class Carpet extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->getID() === self::AIR){ //TODO: Replace with common break method
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta, 1));
$this->getLevel()->setBlock($this, new Air(), true);
if($this->getSide(0)->getID() === self::AIR){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -22,67 +22,10 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
class Carrot extends Flowable{
class Carrot extends Crops{
public function __construct($meta = 0){
parent::__construct(self::CARROT_BLOCK, $meta, "Carrot Block");
$this->isActivable = true;
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$this->meta = 0x07;
$this->getLevel()->setBlock($this, $this, true);
$item->count--;
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get(CARROT, 0, 1));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
++$this->meta;
$this->getLevel()->setBlock($this, $this, true);
return Level::BLOCK_UPDATE_RANDOM;
}
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
}
return false;
}
public function getDrops(Item $item){

View File

@ -42,13 +42,14 @@ class Chest extends Transparent{
$this->hardness = 15;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x + 0.0625,
$this->y,
$this->z + 0.0625,
$this->x + 0.9375,
$this->y + 0.875,
$this->y + 0.9475,
$this->z + 0.9375
);
}
@ -61,7 +62,7 @@ class Chest extends Transparent{
3 => 3,
];
$chest = false;
$chest = null;
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
for($side = 2; $side <= 5; ++$side){
@ -89,9 +90,9 @@ class Chest extends Transparent{
new Int("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
$tile = new TileChest($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
$tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
if($chest instanceof TileChest){
if($chest instanceof TileChest and $tile instanceof TileChest){
$chest->pairWith($tile);
$tile->pairWith($chest);
}
@ -104,7 +105,7 @@ class Chest extends Transparent{
if($t instanceof TileChest){
$t->unpair();
}
$this->getLevel()->setBlock($this, new Air(), true, true, true);
$this->getLevel()->setBlock($this, new Air(), true, true);
return true;
}
@ -129,11 +130,11 @@ class Chest extends Transparent{
new Int("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
$chest = new TileChest($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
$chest = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
}
if(($player->gamemode & 0x01) === 0x01){
if($player->isCreative()){
return true;
}
$player->addWindow($chest->getInventory());
@ -143,19 +144,8 @@ class Chest extends Transparent{
}
public function getDrops(Item $item){
$drops = [
return [
[$this->id, 0, 1],
];
$t = $this->getLevel()->getTile($this);
if($t instanceof TileChest){
for($s = 0; $s < $t->getRealInventory()->getSize(); ++$s){
$slot = $t->getRealInventory()->getItem($s);
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
$drops[] = [$slot->getID(), $slot->getDamage(), $slot->getCount()];
}
}
}
return $drops;
}
}

View File

@ -21,10 +21,13 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
class Cobweb extends Flowable{
public $hasEntityCollision = true;
public function __construct(){
parent::__construct(self::COBWEB, 0, "Cobweb");
$this->isSolid = true;

View File

@ -0,0 +1,100 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
use pocketmine\Server;
abstract class Crops extends Flowable{
public $isActivable = true;
public $hardness = 0;
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$block = clone $this;
$block->meta += mt_rand(2, 5);
if($block->meta > 7){
$block->meta = 7;
}
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
}
$item->count--;
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
$block = clone $this;
++$block->meta;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
}
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
}
return false;
}
}

View File

@ -49,9 +49,8 @@ class CyanFlower extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
$this->getLevel()->dropItem($this, Item::get($this->id, 0, 1));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -49,10 +49,8 @@ class Dandelion extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -52,7 +52,8 @@ abstract class Door extends Transparent{
return $first & 0x07 | ($flag ? 8 : 0) | ($flag1 ? 0x10 : 0);
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$f = 0.1875;
$damage = $this->getFullDamage();
@ -72,7 +73,7 @@ abstract class Door extends Transparent{
if($j === 0){
if($flag){
if(!$flag1){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -81,7 +82,7 @@ abstract class Door extends Transparent{
$this->z + $f
);
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z + 1 - $f,
@ -91,7 +92,7 @@ abstract class Door extends Transparent{
);
}
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -103,7 +104,7 @@ abstract class Door extends Transparent{
}elseif($j === 1){
if($flag){
if(!$flag1){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x + 1 - $f,
$this->y,
$this->z,
@ -112,7 +113,7 @@ abstract class Door extends Transparent{
$this->z + 1
);
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -122,7 +123,7 @@ abstract class Door extends Transparent{
);
}
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -134,7 +135,7 @@ abstract class Door extends Transparent{
}elseif($j === 2){
if($flag){
if(!$flag1){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z + 1 - $f,
@ -143,7 +144,7 @@ abstract class Door extends Transparent{
$this->z + 1
);
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -153,7 +154,7 @@ abstract class Door extends Transparent{
);
}
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x + 1 - $f,
$this->y,
$this->z,
@ -165,7 +166,7 @@ abstract class Door extends Transparent{
}elseif($j === 3){
if($flag){
if(!$flag1){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -174,7 +175,7 @@ abstract class Door extends Transparent{
$this->z + 1
);
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x + 1 - $f,
$this->y,
$this->z,
@ -184,7 +185,7 @@ abstract class Door extends Transparent{
);
}
}else{
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z + 1 - $f,
@ -270,7 +271,7 @@ abstract class Door extends Transparent{
if($player instanceof Player){
unset($players[$player->getID()]);
}
$pk = new LevelEventPacket;
$pk = new LevelEventPacket();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
@ -289,7 +290,7 @@ abstract class Door extends Transparent{
if($player instanceof Player){
unset($players[$player->getID()]);
}
$pk = new LevelEventPacket;
$pk = new LevelEventPacket();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;

View File

@ -24,12 +24,16 @@ namespace pocketmine\block;
use pocketmine\math\AxisAlignedBB;
class EndPortal extends Solid{
public $lightLevel = 1;
public function __construct($meta = 0){
parent::__construct(self::END_PORTAL, $meta, "End Portal");
$this->hardness = 18000000;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x,
$this->y,

View File

@ -21,17 +21,18 @@
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\Player;
use pocketmine\level\Level;
use pocketmine\entity\FallingBlock;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Double;
use pocketmine\nbt\tag\Float;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Double;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Float;
use pocketmine\nbt\tag\Int;
use pocketmine\Player;
class Fallable extends Solid{
abstract class Fallable extends Solid{
public $hasPhysics = true;
@ -45,13 +46,12 @@ class Fallable extends Solid{
if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(0);
if($down->getID() === self::AIR or ($down instanceof Liquid)){
$fall = new FallingBlock($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), new Compound("", [
$fall = Entity::createEntity("FallingSand", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [
new Double("", $this->x + 0.5),
new Double("", $this->y + 0.5),
new Double("", $this->y),
new Double("", $this->z + 0.5)
]),
//TODO: add random motion with physics
"Motion" => new Enum("Motion", [
new Double("", 0),
new Double("", 0),
@ -61,13 +61,12 @@ class Fallable extends Solid{
new Float("", 0),
new Float("", 0)
]),
"Tile" => new Byte("Tile", $this->getID())
"TileID" => new Int("TileID", $this->getID()),
"Data" => new Byte("Data", $this->getDamage()),
]));
$fall->spawnToAll();
}
return false;
}
}
}

View File

@ -30,7 +30,8 @@ class Farmland extends Solid{
$this->hardness = 3;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x,
$this->y,

View File

@ -21,18 +21,17 @@
namespace pocketmine\block;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
class Fence extends Transparent{
public function __construct(){
parent::__construct(self::FENCE, 0, "Fence");
parent::__construct(self::FENCE, 0, "Oak Fence");
$this->isFullBlock = false;
$this->hardness = 15;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$flag = $this->canConnect($this->getSide(2));
$flag1 = $this->canConnect($this->getSide(3));
$flag2 = $this->canConnect($this->getSide(4));
@ -48,13 +47,13 @@ class Fence extends Transparent{
$this->y,
$this->z + $f2,
$this->x + $f1,
$this->y + 1, //TODO: check this, add extra bounding box
$this->y + 1.5,
$this->z + $f3
);
}
public function canConnect(Block $block){
return ($block->getID() !== self::FENCE and $block->getID() !== self::FENCE_GATE) ? $block->isSolid : true;
return (!($block instanceof Fence) and !($block instanceof FenceGate)) ? $block->isSolid : true;
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceAcacia extends Fence{
public function __construct(){
Transparent::__construct(self::FENCE_ACACIA, 0, "Acacia Fence");
$this->isFullBlock = false;
$this->hardness = 15;
}
}

View File

@ -21,29 +21,10 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
class Generic extends Block{
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
return $this->getLevel()->setBlock($this, $this, true, true);
}
public function isBreakable(Item $item){
return $this->breakable;
}
public function onBreak(Item $item){
return $this->getLevel()->setBlock($this, new Air(), true, true);
}
public function onUpdate($type){
return false;
}
public function onActivate(Item $item, Player $player = null){
return $this->isActivable;
class FenceBirch extends Fence{
public function __construct(){
Transparent::__construct(self::FENCE_BIRCH, 0, "Birch Fence");
$this->isFullBlock = false;
$this->hardness = 15;
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceDarkOak extends Fence{
public function __construct(){
Transparent::__construct(self::FENCE_DARK_OAK, 0, "Dark Oak Fence");
$this->isFullBlock = false;
$this->hardness = 15;
}
}

View File

@ -27,7 +27,7 @@ use pocketmine\Player;
class FenceGate extends Transparent{
public function __construct($meta = 0){
parent::__construct(self::FENCE_GATE, $meta, "Fence Gate");
parent::__construct(self::FENCE_GATE, $meta, "Oak Fence Gate");
$this->isActivable = true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
@ -38,7 +38,8 @@ class FenceGate extends Transparent{
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
if(($this->getDamage() & 0x04) > 0){
return null;
}
@ -50,7 +51,7 @@ class FenceGate extends Transparent{
$this->y,
$this->z + 0.375,
$this->x + 1,
$this->y + 1,
$this->y + 1.5,
$this->z + 0.625
);
}else{
@ -59,7 +60,7 @@ class FenceGate extends Transparent{
$this->y,
$this->z,
$this->x + 0.625,
$this->y + 1,
$this->y + 1.5,
$this->z + 1
);
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceGateAcacia extends FenceGate{
public function __construct($meta = 0){
Transparent::__construct(self::FENCE_GATE_ACACIA, $meta, "Acacia Fence Gate");
$this->isActivable = true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
}else{
$this->isFullBlock = false;
}
$this->hardness = 15;
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceGateBirch extends FenceGate{
public function __construct($meta = 0){
Transparent::__construct(self::FENCE_GATE_BIRCH, $meta, "Birch Fence Gate");
$this->isActivable = true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
}else{
$this->isFullBlock = false;
}
$this->hardness = 15;
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceGateDarkOak extends FenceGate{
public function __construct($meta = 0){
Transparent::__construct(self::FENCE_GATE_DARK_OAK, $meta, "Dark Oak Fence Gate");
$this->isActivable = true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
}else{
$this->isFullBlock = false;
}
$this->hardness = 15;
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceGateJungle extends FenceGate{
public function __construct($meta = 0){
Transparent::__construct(self::FENCE_GATE_JUNGLE, $meta, "Jungle Fence Gate");
$this->isActivable = true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
}else{
$this->isFullBlock = false;
}
$this->hardness = 15;
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceGateSpruce extends FenceGate{
public function __construct($meta = 0){
Transparent::__construct(self::FENCE_GATE_SPRUCE, $meta, "Spruce Fence Gate");
$this->isActivable = true;
if(($this->meta & 0x04) === 0x04){
$this->isFullBlock = true;
}else{
$this->isFullBlock = false;
}
$this->hardness = 15;
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceJungle extends Fence{
public function __construct(){
Transparent::__construct(self::FENCE_JUNGLE, 0, "Jungle Fence");
$this->isFullBlock = false;
$this->hardness = 15;
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
class FenceSpruce extends Fence{
public function __construct(){
Transparent::__construct(self::FENCE_SPRUCE, 0, "Spruce Fence");
$this->isFullBlock = false;
$this->hardness = 15;
}
}

View File

@ -21,13 +21,19 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Server;
class Fire extends Flowable{
public $hasEntityCollision = true;
public $lightLevel = 15;
public function __construct($meta = 0){
parent::__construct(self::FIRE, $meta, "Fire");
$this->isReplaceable = true;
@ -41,11 +47,13 @@ class Fire extends Flowable{
}
public function onEntityCollide(Entity $entity){
$entity->setOnFire(8);
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_FIRE, 1);
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
$entity->attack($ev->getFinalDamage(), $ev);
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
Server::getInstance()->getPluginManager()->callEvent($ev);
if(!$ev->isCancelled()){
$entity->attack($ev->getFinalDamage(), $ev);
$entity->setOnFire($ev->getDuration());
}
}

View File

@ -22,7 +22,7 @@
namespace pocketmine\block;
class Flowable extends Transparent{
abstract class Flowable extends Transparent{
public $isFlowable = true;
public $isFullBlock = false;

View File

@ -23,6 +23,9 @@ namespace pocketmine\block;
class GlowingObsidian extends Solid{
public $lightLevel = 12;
public function __construct($meta = 0){
parent::__construct(self::GLOWING_OBSIDIAN, $meta, "Glowing Obsidian");
}

View File

@ -25,6 +25,9 @@ use pocketmine\item\Item;
use pocketmine\level\Level;
class GlowingRedstoneOre extends Solid{
public $lightLevel = 9;
public function __construct(){
parent::__construct(self::GLOWING_REDSTONE_ORE, 0, "Glowing Redstone Ore");
$this->hardness = 15;

View File

@ -24,6 +24,9 @@ namespace pocketmine\block;
use pocketmine\item\Item;
class Glowstone extends Transparent{
public $lightLevel = 15;
public function __construct(){
parent::__construct(self::GLOWSTONE_BLOCK, 0, "Glowstone");
$this->hardness = 1.5;

View File

@ -21,11 +21,13 @@
namespace pocketmine\block;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\Random;
class Grass extends Solid{
@ -52,11 +54,13 @@ class Grass extends Solid{
$x = mt_rand($this->x - 1, $this->x + 1);
$y = mt_rand($this->y - 2, $this->y + 2);
$z = mt_rand($this->z - 1, $this->z + 1);
$block = $this->getLevel()->getBlockIdAt($x, $y, $z);
if($block === Block::DIRT){
$block = Block::get($block, $this->getLevel()->getBlockDataAt($x, $y, $z), new Position($x, $y, $z, $this->getLevel()));
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
if($block->getID() === Block::DIRT){
if($block->getSide(1) instanceof Transparent){
$this->getLevel()->setBlock($block, new Grass());
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, new Grass()));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($block, $ev->getNewState());
}
}
}
}

View File

@ -21,13 +21,16 @@
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\Player;
use pocketmine\entity\Entity;
class Ladder extends Transparent{
public $hasEntityCollision = true;
public function __construct($meta = 0){
parent::__construct(self::LADDER, $meta, "Ladder");
$this->isSolid = false;
@ -37,9 +40,11 @@ class Ladder extends Transparent{
public function onEntityCollide(Entity $entity){
$entity->fallDistance = 0;
$entity->onGround = true;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$f = 0.125;
if($this->meta === 2){

View File

@ -21,150 +21,44 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\event\entity\EntityDamageEvent;
class Lava extends Liquid{
public $lightLevel = 15;
public function __construct($meta = 0){
parent::__construct(self::LAVA, $meta, "Lava");
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function onEntityCollide(Entity $entity){
$entity->setOnFire(15);
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_LAVA, 4);
$entity->fallDistance *= 0.5;
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
$entity->attack($ev->getFinalDamage(), $ev);
$ev = new EntityCombustByBlockEvent($this, $entity, 15);
Server::getInstance()->getPluginManager()->callEvent($ev);
if(!$ev->isCancelled()){
$entity->attack($ev->getFinalDamage(), $ev);
$entity->setOnFire($ev->getDuration());
}
if($entity instanceof Player){
$entity->onGround = true;
}
$entity->attack(4, EntityDamageEvent::CAUSE_LAVA);
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$ret = $this->getLevel()->setBlock($this, $this, true);
$this->getLevel()->scheduleUpdate(clone $this, 40);
$ret = $this->getLevel()->setBlock($this, $this, true, false);
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
return $ret;
}
public function getSourceCount(){
$count = 0;
for($side = 2; $side <= 5; ++$side){
if($this->getSide($side) instanceof Lava){
$b = $this->getSide($side);
$level = $b->meta & 0x07;
if($level == 0x00){
$count++;
}
}
}
return $count;
}
public function checkWater(){
for($side = 1; $side <= 5; ++$side){
$b = $this->getSide($side);
if($b instanceof Water){
$level = $this->meta & 0x07;
if($level == 0x00){
$this->getLevel()->setBlock($this, new Obsidian(), false, false, true);
}else{
$this->getLevel()->setBlock($this, new Cobblestone(), false, false, true);
}
}
}
}
public function getFrom(){
for($side = 0; $side <= 5; ++$side){
$b = $this->getSide($side);
if($b instanceof Lava){
$tlevel = $b->meta & 0x07;
$level = $this->meta & 0x07;
if(($tlevel + 2) == $level || ($side == 0x01 && $level == 0x01) || ($tlevel == 6 && $level == 7)){
return $b;
}
}
}
return null;
}
public function onUpdate($type){
return false;
$newId = $this->id;
$level = $this->meta & 0x07;
if($type !== Level::BLOCK_UPDATE_NORMAL){
return false;
}
if($this->checkWater()){
return;
}
$falling = $this->meta >> 3;
$down = $this->getSide(0);
$from = $this->getFrom();
if($from !== null || $level == 0x00){
if($level !== 0x07){
if($down instanceof Air || $down instanceof Lava){
$this->getLevel()->setBlock($down, new Lava(0x01), false, false, true);
Server::getInstance()->api->block->scheduleBlockUpdate(new Position($down, 0, 0, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
}else{
for($side = 2; $side <= 5; ++$side){
$b = $this->getSide($side);
if($b instanceof Lava){
}elseif($b->isFlowable === true){
$this->getLevel()->setBlock($b, new Lava(min($level + 2, 7)), false, false, true);
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
}
}
}
}
}else{
//Extend Remove for Left Lavas
for($side = 2; $side <= 5; ++$side){
$sb = $this->getSide($side);
if($sb instanceof Lava){
$tlevel = $sb->meta & 0x07;
if($tlevel != 0x00){
for($s = 0; $s <= 5; $s++){
$ssb = $sb->getSide($s);
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
}
$this->getLevel()->setBlock($sb, new Air(), false, false, true);
}
}
$b = $this->getSide(0)->getSide($side);
if($b instanceof Lava){
$tlevel = $b->meta & 0x07;
if($tlevel != 0x00){
for($s = 0; $s <= 5; $s++){
$ssb = $sb->getSide($s);
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
}
$this->getLevel()->setBlock($b, new Air(), false, false, true);
}
}
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
}
$this->getLevel()->setBlock($this, new Air(), false, false, true);
}
return false;
}
}

View File

@ -21,9 +21,11 @@
namespace pocketmine\block;
use pocketmine\event\block\LeavesDecayEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
use pocketmine\Server;
class Leaves extends Transparent{
const OAK = 0;
@ -121,16 +123,13 @@ class Leaves extends Transparent{
$this->meta &= 0x03;
$visited = [];
$check = 0;
if($this->findLog($this, $visited, 0, $check) === true){
$this->getLevel()->setBlock($this, $this, false, false, true);
Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){
$this->getLevel()->setBlock($this, $this, false, false);
}else{
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if(mt_rand(1, 20) === 1){ //Saplings
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
}
if(($this->meta & 0x03) === self::OAK and mt_rand(1, 200) === 1){ //Apples
$this->getLevel()->dropItem($this, Item::get(Item::APPLE, 0, 1));
}
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -21,9 +21,11 @@
namespace pocketmine\block;
use pocketmine\event\block\LeavesDecayEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
use pocketmine\Server;
class Leaves2 extends Leaves{
@ -113,13 +115,13 @@ class Leaves2 extends Leaves{
$this->meta &= 0x03;
$visited = [];
$check = 0;
if($this->findLog($this, $visited, 0, $check) === true){
$this->getLevel()->setBlock($this, $this, false, false, true);
Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){
$this->getLevel()->setBlock($this, $this, false, false);
}else{
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if(mt_rand(1, 20) === 1){ //Saplings
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
}
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -22,13 +22,23 @@
namespace pocketmine\block;
class Liquid extends Transparent{
public $isLiquid = true;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
abstract class Liquid extends Transparent{
public $hasEntityCollision = true;
public $breakable = false;
public $isReplaceable = true;
public $isSolid = false;
public $isFullBlock = true;
public $adjacentSources = 0;
public $isOptimalFlowDirection = [0, 0, 0, 0];
public $flowCost = [0, 0, 0, 0];
public function getFluidHeightPercent(){
$d = $this->meta;
if($d >= 8){
@ -37,4 +47,374 @@ class Liquid extends Transparent{
return ($d + 1) / 9;
}
protected function getFlowDecay(Vector3 $pos){
if(!($pos instanceof Block)){
$pos = $this->getLevel()->getBlock($pos);
}
if($pos->getID() !== $this->getID()){
return -1;
}else{
return $pos->getDamage();
}
}
protected function getEffectiveFlowDecay(Vector3 $pos){
if(!($pos instanceof Block)){
$pos = $this->getLevel()->getBlock($pos);
}
if($pos->getID() !== $this->getID()){
return -1;
}
$decay = $pos->getDamage();
if($decay >= 8){
$decay = 0;
}
return $decay;
}
public function getFlowVector(){
$vector = new Vector3(0, 0, 0);
$decay = $this->getEffectiveFlowDecay($this);
for($j = 0; $j < 4; ++$j){
$x = $this->x;
$y = $this->y;
$z = $this->z;
if($j === 0){
--$x;
}elseif($j === 1){
++$x;
}elseif($j === 2){
--$z;
}elseif($j === 3){
++$z;
}
$sideBlock = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
if($blockDecay < 0){
if(!$sideBlock->isFlowable){
continue;
}
$blockDecay = $this->getEffectiveFlowDecay($sideBlock->getSide(0));
if($blockDecay >= 0){
$realDecay = $blockDecay - ($decay - 8);
$vector = $vector->add(($sideBlock->x - $this->x) * $realDecay, ($sideBlock->y - $this->y) * $realDecay, ($sideBlock->z - $this->z) * $realDecay);
}
continue;
}else{
$realDecay = $blockDecay - $decay;
$vector = $vector->add(($sideBlock->x - $this->x) * $realDecay, ($sideBlock->y - $this->y) * $realDecay, ($sideBlock->z - $this->z) * $realDecay);
}
}
if($this->getDamage() >= 8){
$falling = false;
if(!$this->getLevel()->getBlock($this->add(0, 0, -1))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(0, 0, 1))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(-1, 0, 0))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(1, 0, 0))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(0, 1, -1))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(0, 1, 1))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(-1, 1, 0))->isFlowable){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->add(1, 1, 0))->isFlowable){
$falling = true;
}
if($falling){
$vector = $vector->normalize()->add(0, -6, 0);
}
}
return $vector->normalize();
}
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
$flow = $this->getFlowVector();
$vector->x += $flow->x;
$vector->y += $flow->y;
$vector->z += $flow->z;
}
public function tickRate(){
if($this instanceof Water){
return 5;
}elseif($this instanceof Lava){
return 30;
}
return 0;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$this->checkForHarden();
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
}elseif($type === Level::BLOCK_UPDATE_SCHEDULED){
$decay = $this->getFlowDecay($this);
$multiplier = $this instanceof Lava ? 2 : 1;
$flag = true;
if($decay > 0){
$smallestFlowDecay = -100;
$this->adjacentSources = 0;
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(4), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(5), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(2), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(3), $smallestFlowDecay);
$k = $smallestFlowDecay + $multiplier;
if($k >= 8 or $smallestFlowDecay < 0){
$k = -1;
}
if(($topFlowDecay = $this->getFlowDecay($this->getSide(1))) >= 0){
if($topFlowDecay >= 8){
$k = $topFlowDecay;
}else{
$k = $topFlowDecay | 0x08;
}
}
if($this->adjacentSources >= 2 and $this instanceof Water){
$bottomBlock = $this->getSide(0);
if($bottomBlock->isSolid){
$k = 0;
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
$k = 0;
}
}
if($this instanceof Lava and $decay < 8 and $k < 8 and $k > 1 and mt_rand(0, 4) !== 0){
$k = $decay;
$flag = false;
}
if($k !== $decay){
$decay = $k;
if($decay < 0){
$this->getLevel()->setBlock($this, Block::get(Item::AIR), true);
}else{
$this->getLevel()->setBlock($this, Block::get($this->id, $decay), true);
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
}
}elseif($flag){
//$this->getLevel()->scheduleUpdate($this, $this->tickRate());
//$this->updateFlow();
}
}else{
//$this->updateFlow();
}
$bottomBlock = $this->getSide(0);
if($bottomBlock->isFlowable or $bottomBlock instanceof Liquid){
if($this instanceof Lava and $bottomBlock instanceof Water){
$this->getLevel()->setBlock($bottomBlock, Block::get(Item::STONE), true);
return;
}
if($decay >= 8){
$this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay), true);
$this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate());
}else{
$this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay + 8), true);
$this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate());
}
}elseif($decay >= 0 and ($decay === 0 or !$bottomBlock->isFlowable)){
$flags = $this->getOptimalFlowDirections();
$l = $decay + $multiplier;
if($decay >= 8){
$l = 1;
}
if($l >= 8){
$this->checkForHarden();
return;
}
if($flags[0]){
$this->flowIntoBlock($this->getSide(4), $l);
}
if($flags[1]){
$this->flowIntoBlock($this->getSide(5), $l);
}
if($flags[2]){
$this->flowIntoBlock($this->getSide(2), $l);
}
if($flags[3]){
$this->flowIntoBlock($this->getSide(3), $l);
}
}
$this->checkForHarden();
}
}
private function flowIntoBlock(Block $block, $newFlowDecay){
if($block->isFlowable){
if($block->getID() > 0){
$this->getLevel()->useBreakOn($block);
}
$this->getLevel()->setBlock($block, Block::get($this->id, $newFlowDecay), true);
$this->getLevel()->scheduleUpdate($block, $this->tickRate());
}
}
private function calculateFlowCost(Block $block, $accumulatedCost, $previousDirection){
$cost = 1000;
for($j = 0; $j < 4; ++$j){
if(
($j === 0 and $previousDirection === 1) or
($j === 1 and $previousDirection === 0) or
($j === 2 and $previousDirection === 3) or
($j === 3 and $previousDirection === 2)
){
$x = $block->x;
$y = $block->y;
$z = $block->z;
if($j === 0){
--$x;
}elseif($j === 1){
++$x;
}elseif($j === 2){
--$z;
}elseif($j === 3){
++$z;
}
$blockSide = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
if(!$blockSide->isFlowable and !($blockSide instanceof Liquid)){
continue;
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
continue;
}elseif($blockSide->getSide(0)->isFlowable){
return $accumulatedCost;
}
if($accumulatedCost >= 4){
continue;
}
$realCost = $this->calculateFlowCost($blockSide, $accumulatedCost + 1, $j);
if($realCost < $cost){
$cost = $realCost;
}
}
}
return $cost;
}
private function getOptimalFlowDirections(){
for($j = 0; $j < 4; ++$j){
$this->flowCost[$j] = 1000;
$x = $this->x;
$y = $this->y;
$z = $this->z;
if($j === 0){
--$x;
}elseif($j === 1){
++$x;
}elseif($j === 2){
--$z;
}elseif($j === 3){
++$z;
}
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
if(!$block->isFlowable and !($block instanceof Liquid)){
continue;
}elseif($block instanceof Liquid and $block->getDamage() === 0){
continue;
}elseif($block->getSide(0)->isFlowable){
$this->flowCost[$j] = 0;
}else{
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
}
}
$minCost = $this->flowCost[0];
for($i = 1; $i < 4; ++$i){
if($this->flowCost[$i] < $minCost){
$minCost = $this->flowCost[$i];
}
}
for($i = 0; $i < 4; ++$i){
$this->isOptimalFlowDirection[$i] = ($this->flowCost[$i] === $minCost);
}
return $this->isOptimalFlowDirection;
}
private function getSmallestFlowDecay(Vector3 $pos, $decay){
$blockDecay = $this->getFlowDecay($pos);
if($blockDecay < 0){
return $decay;
}elseif($blockDecay === 0){
++$this->adjacentSources;
}elseif($blockDecay >= 8){
$blockDecay = 0;
}
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
}
private function checkForHarden(){
if($this instanceof Lava){
$colliding = false;
for($side = 0; $side <= 5 and !$colliding; ++$side){
$colliding = $this->getSide($side) instanceof Water;
}
if($colliding){
if($this->getDamage() === 0){
$this->getLevel()->setBlock($this, Block::get(Item::OBSIDIAN), true);
}elseif($this->getDamage() <= 4){
$this->getLevel()->setBlock($this, Block::get(Item::COBBLESTONE), true);
}
}
}
}
public function getBoundingBox(){
return null;
}
}

View File

@ -25,6 +25,9 @@ use pocketmine\item\Item;
use pocketmine\Player;
class LitPumpkin extends Solid{
public $lightLevel = 15;
public function __construct(){
parent::__construct(self::LIT_PUMPKIN, "Jack o'Lantern");
$this->hardness = 5;

View File

@ -21,46 +21,31 @@
namespace pocketmine\block;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
use pocketmine\Server;
class MelonStem extends Flowable{
class MelonStem extends Crops{
public function __construct($meta = 0){
parent::__construct(self::MELON_STEM, $meta, "Melon Stem");
$this->isActivable = true;
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
$this->getLevel()->dropItem($this, Item::get(Item::MELON_SEEDS, 0, mt_rand(0, 2)));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
++$this->meta;
$this->getLevel()->setBlock($this, $this, true);
$block = clone $this;
++$block->meta;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
}
return Level::BLOCK_UPDATE_RANDOM;
}else{
@ -73,7 +58,10 @@ class MelonStem extends Flowable{
$side = $this->getSide(mt_rand(2, 5));
$d = $side->getSide(0);
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
$this->getLevel()->setBlock($side, new Melon(), true);
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($side, new Melon()));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
}
}
}
}
@ -84,20 +72,6 @@ class MelonStem extends Flowable{
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$this->meta = 0x07;
$this->getLevel()->setBlock($this, $this, true);
if(($player->gamemode & 0x01) === 0){
$item->count--;
}
return true;
}
return false;
}
public function getDrops(Item $item){
return [
[Item::MELON_SEEDS, 0, mt_rand(0, 2)],

View File

@ -21,9 +21,11 @@
namespace pocketmine\block;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\math\Vector3;
use pocketmine\Server;
class Mycelium extends Solid{
public function __construct(){
@ -43,11 +45,13 @@ class Mycelium extends Solid{
$x = mt_rand($this->x - 1, $this->x + 1);
$y = mt_rand($this->y - 2, $this->y + 2);
$z = mt_rand($this->z - 1, $this->z + 1);
$block = $this->getLevel()->getBlockIdAt($x, $y, $z);
if($block === Block::DIRT){
$block = Block::get($block, $this->getLevel()->getBlockDataAt($x, $y, $z), new Position($x, $y, $z, $this->getLevel()));
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
if($block->getID() === Block::DIRT){
if($block->getSide(1) instanceof Transparent){
$this->getLevel()->setBlock($block, new Mycelium());
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, new Mycelium()));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($block, $ev->getNewState());
}
}
}
}

View File

@ -22,68 +22,10 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
class Potato extends Flowable{
class Potato extends Crops{
public function __construct($meta = 0){
parent::__construct(self::POTATO_BLOCK, $meta, "Potato Block");
$this->isActivable = true;
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$this->meta = 0x07;
$this->getLevel()->setBlock($this, $this, true);
if(($player->gamemode & 0x01) === 0){
$item->count--;
}
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
$this->getLevel()->dropItem($this, Item::get(Item::POTATO, 0, 1));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
++$this->meta;
$this->getLevel()->setBlock($this, $this, true);
return Level::BLOCK_UPDATE_RANDOM;
}
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
}
return false;
}
public function getDrops(Item $item){

View File

@ -21,47 +21,31 @@
namespace pocketmine\block;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
use pocketmine\Server;
class PumpkinStem extends Flowable{
class PumpkinStem extends Crops{
public function __construct($meta = 0){
parent::__construct(self::PUMPKIN_STEM, $meta, "Pumpkin Stem");
$this->isActivable = true;
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get(PUMPKIN_SEEDS, 0, mt_rand(0, 2)));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
++$this->meta;
$this->getLevel()->setBlock($this, $this, true);
$block = clone $this;
++$block->meta;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
}
return Level::BLOCK_UPDATE_RANDOM;
}else{
@ -74,7 +58,10 @@ class PumpkinStem extends Flowable{
$side = $this->getSide(mt_rand(2, 5));
$d = $side->getSide(0);
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
$this->getLevel()->setBlock($side, new Pumpkin(), true);
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($side, new Pumpkin()));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
}
}
}
}
@ -85,20 +72,6 @@ class PumpkinStem extends Flowable{
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$this->meta = 0x07;
$this->getLevel()->setBlock($this, $this, true);
if(($player->gamemode & 0x01) === 0){
$item->count--;
}
return true;
}
return false;
}
public function getDrops(Item $item){
return [
[Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2)],

View File

@ -38,10 +38,8 @@ class RedMushroom extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
$this->getLevel()->setBlock($this, new Air(), false);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -81,10 +81,8 @@ class Sapling extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($this->getSide(0)->isTransparent === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -64,10 +64,8 @@ class SignPost extends Transparent{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get(SIGN, 0, 1));
$this->getLevel()->setBlock($this, new Air(), true, true, true);
if($this->getSide(0)->getID() === self::AIR){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -47,7 +47,8 @@ class Slab extends Transparent{
$this->hardness = 30;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
if(($this->meta & 0x08) > 0){
return new AxisAlignedBB(
$this->x,
@ -94,7 +95,7 @@ class Slab extends Transparent{
return true;
}
//TODO: check for collision
}elseif(!($player instanceof Player)){
}else{
if($block->getID() === self::SLAB){
if(($block->getDamage() & 0x07) === ($this->meta & 0x07)){
$this->getLevel()->setBlock($block, Block::get(Item::DOUBLE_SLAB, $this->meta), true);
@ -108,9 +109,8 @@ class Slab extends Transparent{
$this->meta |= 0x08;
}
}
}else{
return false;
}
if($block->getID() === self::SLAB and ($target->getDamage() & 0x07) !== ($this->meta & 0x07)){
return false;
}

View File

@ -21,12 +21,7 @@
namespace pocketmine\block;
class Solid extends Generic{
public function __construct($id, $meta = 0, $name = "Unknown"){
parent::__construct($id, $meta, $name);
$this->isSolid = true;
$this->isFullBlock = true;
}
abstract class Solid extends Block{
public $isSolid = true;
public $isFullBlock = true;
}

View File

@ -30,7 +30,8 @@ class SoulSand extends Solid{
$this->hardness = 2.5;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
return new AxisAlignedBB(
$this->x,
$this->y,

View File

@ -25,7 +25,7 @@ use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\Player;
class Stair extends Transparent{
abstract class Stair extends Transparent{
public function __construct($id, $meta = 0, $name = "Unknown"){
parent::__construct($id, $meta, $name);
@ -54,7 +54,7 @@ class Stair extends Transparent{
$f3 = 0.5;
}
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f,
$this->z,
@ -66,7 +66,7 @@ class Stair extends Transparent{
}
if($j === 0){
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x + 0.5,
$this->y + $f2,
$this->z,
@ -77,7 +77,7 @@ class Stair extends Transparent{
$list[] = $bb2;
}
}elseif($j === 1){
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z,
@ -88,7 +88,7 @@ class Stair extends Transparent{
$list[] = $bb2;
}
}elseif($j === 2){
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z + 0.5,
@ -99,7 +99,7 @@ class Stair extends Transparent{
$list[] = $bb2;
}
}elseif($j === 3){
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z,
@ -113,7 +113,8 @@ class Stair extends Transparent{
}
*/
public function getBoundingBox(){
protected function recalculateBoundingBox(){
if(($this->getDamage() & 0x04) > 0){
return new AxisAlignedBB(
$this->x,

View File

@ -21,28 +21,10 @@
namespace pocketmine\block;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\Server;
use pocketmine\entity\Entity;
class StillLava extends Liquid{
class StillLava extends Lava{
public function __construct($meta = 0){
parent::__construct(self::STILL_LAVA, $meta, "Still Lava");
$this->hardness = 500;
}
public function getBoundingBox(){
return null;
}
public function onEntityCollide(Entity $entity){
$entity->setOnFire(15);
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_LAVA, 4);
Server::getInstance()->getPluginManager()->callEvent($ev);
if(!$ev->isCancelled()){
$entity->attack($ev->getFinalDamage(), $ev);
}
$entity->attack(4, EntityDamageEvent::CAUSE_LAVA);
}
}

View File

@ -22,6 +22,7 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
class Stone extends Solid{
const NORMAL = 0;
@ -45,6 +46,7 @@ class Stone extends Solid{
self::POLISHED_DIORITE => "Polished Diorite",
self::ANDESITE => "Andesite",
self::POLISHED_ANDESITE => "Polished Andesite",
7 => "Unknown Stone",
];
$this->name = $names[$this->meta & 0x07];
}
@ -67,7 +69,7 @@ class Stone extends Solid{
}
public function getDrops(Item $item){
if($item->isPickaxe() >= 1){
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return [
[Item::COBBLESTONE, 0, 1],
];

View File

@ -36,7 +36,8 @@ class StoneWall extends Transparent{
$this->hardness = 30;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$flag = $this->canConnect($this->getSide(2));
$flag1 = $this->canConnect($this->getSide(3));
$flag2 = $this->canConnect($this->getSide(4));
@ -46,14 +47,11 @@ class StoneWall extends Transparent{
$f1 = $flag3 ? 1 : 0.75;
$f2 = $flag ? 0 : 0.25;
$f3 = $flag1 ? 1 : 0.75;
$f4 = 1;
if($flag and $flag1 and !$flag2 and !$flag3){
$f4 = 0.8125;
$f = 0.3125;
$f1 = 0.6875;
}elseif(!$flag and !$flag1 and $flag2 and $flag3){
$f4 = 0.8125;
$f2 = 0.3125;
$f3 = 0.6875;
}
@ -63,7 +61,7 @@ class StoneWall extends Transparent{
$this->y,
$this->z + $f2,
$this->x + $f1,
$this->y + $f4,
$this->y + 1.5,
$this->z + $f3
);
}

View File

@ -21,10 +21,12 @@
namespace pocketmine\block;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\Player;
use pocketmine\Server;
class Sugarcane extends Flowable{
public function __construct($meta = 0){
@ -49,7 +51,10 @@ class Sugarcane extends Flowable{
for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
if($b->getID() === self::AIR){
$this->getLevel()->setBlock($b, new Sugarcane(), true);
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Sugarcane()));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
}
break;
}
}
@ -69,10 +74,8 @@ class Sugarcane extends Flowable{
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(0);
if($down->isTransparent === true and $down->getID() !== self::SUGARCANE_BLOCK){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get(SUGARCANE));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
if($down->isTransparent === true and $down->getID() !== self::SUGARCANE_BLOCK){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -21,8 +21,15 @@
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Double;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Float;
use pocketmine\Player;
use pocketmine\utils\Random;
class TNT extends Solid{
public function __construct(){
@ -33,20 +40,29 @@ class TNT extends Solid{
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::FLINT_STEEL){
if(($player->gamemode & 0x01) === 0){
$item->useOn($this);
}
$data = [
"x" => $this->x + 0.5,
"y" => $this->y + 0.5,
"z" => $this->z + 0.5,
"power" => 4,
"fuse" => 20 * 4, //4 seconds
];
$this->getLevel()->setBlock($this, new Air(), false, false, true);
//TODO
//$e = Server::getInstance()->api->entity->add($this->level, ENTITY_OBJECT, OBJECT_PRIMEDTNT, $data);
//$e->spawnToAll();
$item->useOn($this);
$this->getLevel()->setBlock($this, new Air(), true);
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [
new Double("", $this->x + 0.5),
new Double("", $this->y),
new Double("", $this->z + 0.5)
]),
"Motion" => new Enum("Motion", [
new Double("", -sin($mot) * 0.02),
new Double("", 0.2),
new Double("", -cos($mot) * 0.02)
]),
"Rotation" => new Enum("Rotation", [
new Float("", 0),
new Float("", 0)
]),
"Fuse" => new Byte("Fuse", 80)
]));
$tnt->spawnToAll();
return true;
}

View File

@ -24,12 +24,13 @@ namespace pocketmine\block;
use pocketmine\math\AxisAlignedBB;
class Thin extends Transparent{
abstract class Thin extends Transparent{
public $isFullBlock = false;
public $isSolid = false;
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$f = 0.4375;
$f1 = 0.5625;
$f2 = 0.4375;

View File

@ -26,6 +26,9 @@ use pocketmine\level\Level;
use pocketmine\Player;
class Torch extends Flowable{
public $lightLevel = 15;
public function __construct($meta = 0){
parent::__construct(self::TORCH, $meta, "Torch");
$this->hardness = 0;
@ -49,10 +52,8 @@ class Torch extends Flowable{
0 => 0,
];
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === self::FENCE)){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get($this->id, 0, 1));
$this->getLevel()->setBlock($this, new Air(), true);
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === self::FENCE)){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -23,7 +23,7 @@ namespace pocketmine\block;
class Transparent extends Generic{
abstract class Transparent extends Block{
public $isActivable = false;
public $breakable = true;
public $isFlowable = false;

View File

@ -37,13 +37,12 @@ class Trapdoor extends Transparent{
$this->hardness = 15;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
$damage = $this->getDamage();
$f = 0.1875;
$bb = null;
if(($damage & 0x08) > 0){
$bb = new AxisAlignedBB(
$this->x,
@ -66,7 +65,7 @@ class Trapdoor extends Transparent{
if(($damage & 0x04) > 0){
if(($damage & 0x03) === 0){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z + 1 - $f,
@ -75,7 +74,7 @@ class Trapdoor extends Transparent{
$this->z + 1
);
}elseif(($damage & 0x03) === 1){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,
@ -84,7 +83,7 @@ class Trapdoor extends Transparent{
$this->z + $f
);
}if(($damage & 0x03) === 2){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x + 1 - $f,
$this->y,
$this->z,
@ -93,7 +92,7 @@ class Trapdoor extends Transparent{
$this->z + 1
);
}if(($damage & 0x03) === 3){
$bb = new AxisAlignedBB(
$bb->setBounds(
$this->x,
$this->y,
$this->z,

View File

@ -0,0 +1,172 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\Player;
class Vine extends Transparent{
public $hasEntityCollision = true;
public function __construct($meta = 0){
parent::__construct(self::VINE, $meta, "Vines");
$this->isSolid = false;
$this->isFullBlock = false;
$this->hardness = 1;
}
public function onEntityCollide(Entity $entity){
$entity->fallDistance = 0;
}
protected function recalculateBoundingBox(){
$f1 = 1;
$f2 = 1;
$f3 = 1;
$f4 = 0;
$f5 = 0;
$f6 = 0;
$flag = $this->meta > 0;
if(($this->meta & 0x02) > 0){
$f4 = max($f4, 0.0625);
$f1 = 0;
$f2 = 0;
$f5 = 1;
$f3 = 0;
$f6 = 1;
$flag = true;
}
if(($this->meta & 0x08) > 0){
$f1 = min($f1, 0.9375);
$f4 = 1;
$f2 = 0;
$f5 = 1;
$f3 = 0;
$f6 = 1;
$flag = true;
}
if(($this->meta & 0x01) > 0){
$f3 = min($f3, 0.9375);
$f6 = 1;
$f1 = 0;
$f4 = 1;
$f2 = 0;
$f5 = 1;
$flag = true;
}
if(!$flag and $this->getSide(1)->isSolid){
$f2 = min($f2, 0.9375);
$f5 = 1;
$f1 = 0;
$f4 = 1;
$f3 = 0;
$f6 = 1;
}
return new AxisAlignedBB(
$this->x + $f1,
$this->y + $f2,
$this->z + $f3,
$this->x + $f4,
$this->y + $f5,
$this->z + $f6
);
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
if($target->isSolid){
$faces = [
0 => 0,
1 => 0,
2 => 1,
3 => 4,
4 => 8,
5 => 2,
];
if(isset($faces[$face])){
$this->meta = $faces[$face];
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
}
return false;
}
public function getBreakTime(Item $item){
if($item->isShears()){
return 0.02;
}elseif($item->isSword()){
return 0.2;
}elseif($item->isAxe()){
switch($item->isAxe()){
case Tool::TIER_WOODEN:
return 0.15;
case Tool::TIER_STONE:
return 0.075;
case Tool::TIER_IRON:
return 0.05;
case Tool::TIER_DIAMOND:
return 0.0375;
case Tool::TIER_GOLD:
return 0.025;
}
}
return 0.3;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
/*if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
Server::getInstance()->api->entity->drop($this, Item::get(LADDER, 0, 1));
$this->getLevel()->setBlock($this, new Air(), true, true, true);
return Level::BLOCK_UPDATE_NORMAL;
}*/
}
return false;
}
public function getDrops(Item $item){
if($item->isShears()){
return [
[$this->id, 0, 1],
];
}else{
return [];
}
}
}

View File

@ -21,150 +21,31 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\Player;
class Water extends Liquid{
public function __construct($meta = 0){
parent::__construct(self::WATER, $meta, "Water");
$this->hardness = 500;
}
public function getBoundingBox(){
return null;
}
public function onEntityCollide(Entity $entity){
$entity->fallDistance = 0;
$entity->extinguish();
if($entity->fireTicks > 0){
$entity->extinguish();
}
if($entity instanceof Player){
$entity->onGround = true;
}
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$ret = $this->getLevel()->setBlock($this, $this, true);
$this->getLevel()->scheduleUpdate(clone $this, 10);
$ret = $this->getLevel()->setBlock($this, $this, true, false);
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
return $ret;
}
public function getSourceCount(){
$count = 0;
for($side = 2; $side <= 5; ++$side){
if($this->getSide($side) instanceof Water){
$b = $this->getSide($side);
$level = $b->meta & 0x07;
if($level == 0x00){
$count++;
}
}
}
return $count;
}
public function checkLava(){
for($side = 0; $side <= 5; ++$side){
if($side == 1){
continue;
}
$b = $this->getSide($side);
if($b instanceof Lava){
$level = $b->meta & 0x07;
if($level == 0x00){
$this->getLevel()->setBlock($b, new Obsidian(), false, false, true);
}else{
$this->getLevel()->setBlock($b, new Cobblestone(), false, false, true);
}
return true;
}
}
return false;
}
public function getFrom(){
for($side = 0; $side <= 5; ++$side){
$b = $this->getSide($side);
if($b instanceof Water){
$tlevel = $b->meta & 0x07;
$level = $this->meta & 0x07;
if(($tlevel + 1) == $level || ($side == 0x01 && $level == 0x01)){
return $b;
}
}
}
return null;
}
public function onUpdate($type){
return false;
$newId = $this->id;
$level = $this->meta & 0x07;
if($type !== Level::BLOCK_UPDATE_NORMAL){
return false;
}
$this->checkLava();
$falling = $this->meta >> 3;
$down = $this->getSide(0);
$from = $this->getFrom();
//Has Source or Its Source
if($from !== null || $level == 0x00){
if($level !== 0x07){
if($down instanceof Air || $down instanceof Water){
$this->getLevel()->setBlock($down, new Water(0x01), false, false, true);
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($down, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
}else{
for($side = 2; $side <= 5; ++$side){
$b = $this->getSide($side);
if($b instanceof Water){
if($this->getSourceCount() >= 2 && $level != 0x00){
$this->getLevel()->setBlock($this, new Water(0), false, false, true);
}
}elseif($b->isFlowable === true){
$this->getLevel()->setBlock($b, new Water($level + 1), false, false, true);
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
}
}
}
}
}else{
//Extend Remove for Left Waters
for($side = 2; $side <= 5; ++$side){
$sb = $this->getSide($side);
if($sb instanceof Water){
$tlevel = $sb->meta & 0x07;
if($tlevel != 0x00){
for($s = 0; $s <= 5; $s++){
$ssb = $sb->getSide($s);
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
}
$this->getLevel()->setBlock($sb, new Air(), false, false, true);
}
}
$b = $this->getSide(0)->getSide($side);
if($b instanceof Water){
$tlevel = $b->meta & 0x07;
if($tlevel != 0x00){
for($s = 0; $s <= 5; $s++){
$ssb = $sb->getSide($s);
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
}
$this->getLevel()->setBlock($b, new Air(), false, false, true);
}
}
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
}
$this->getLevel()->setBlock($this, new Air(), false, false, true);
}
return false;
}
}

View File

@ -22,65 +22,10 @@
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\Player;
class Wheat extends Flowable{
class Wheat extends Crops{
public function __construct($meta = 0){
parent::__construct(self::WHEAT_BLOCK, $meta, "Wheat Block");
$this->isActivable = true;
$this->hardness = 0;
}
public function getBoundingBox(){
return null;
}
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
$down = $this->getSide(0);
if($down->getID() === self::FARMLAND){
$this->getLevel()->setBlock($block, $this, true, true);
return true;
}
return false;
}
public function onActivate(Item $item, Player $player = null){
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
$this->meta = 0x07;
$this->getLevel()->setBlock($this, $this, true);
if(($player->gamemode & 0x01) === 0){
$item->count--;
}
return true;
}
return false;
}
public function onUpdate($type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
//TODO
//Server::getInstance()->api->entity->drop($this, Item::get(WHEAT_SEEDS, 0, 1));
$this->getLevel()->setBlock($this, new Air(), false, false, true);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) == 1){
if($this->meta < 0x07){
++$this->meta;
$this->getLevel()->setBlock($this, $this, true);
}
}
}
return false;
}
public function getDrops(Item $item){

View File

@ -23,14 +23,18 @@ namespace pocketmine\block;
class Wood2 extends Wood{
const ACACIA = 0;
const DARK_OAK = 1;
public function __construct($meta = 0){
Solid::__construct(self::WOOD2, $meta, "Wood");
$names = [
0 => "Acacia Wood",
1 => "Dark Oak Wood"
1 => "Dark Oak Wood",
2 => ""
];
$this->name = $names[$this->meta & 0x03];
$this->hardness = 10;
}
}
}

View File

@ -45,7 +45,8 @@ class WoodSlab extends Transparent{
$this->hardness = 15;
}
public function getBoundingBox(){
protected function recalculateBoundingBox(){
if(($this->meta & 0x08) > 0){
return new AxisAlignedBB(
$this->x,
@ -91,7 +92,7 @@ class WoodSlab extends Transparent{
return true;
}
}elseif(!($player instanceof Player)){ //TODO: collision
}else{ //TODO: collision
if($block->getID() === self::WOOD_SLAB){
if(($block->getDamage() & 0x07) === ($this->meta & 0x07)){
$this->getLevel()->setBlock($block, Block::get(Item::DOUBLE_WOOD_SLAB, $this->meta), true);
@ -105,9 +106,8 @@ class WoodSlab extends Transparent{
$this->meta |= 0x08;
}
}
}else{
return false;
}
if($block->getID() === self::WOOD_SLAB and ($target->getDamage() & 0x07) !== ($this->meta & 0x07)){
return false;
}

View File

@ -31,13 +31,15 @@ class CommandReader extends Thread{
private $readline;
/** @var \Threaded */
private $buffer;
protected $buffer;
/**
* @param \Threaded $threaded
* @param string $stream
*/
public function __construct($stream = "php://stdin"){
public function __construct(\Threaded $threaded, $stream = "php://stdin"){
$this->stream = $stream;
$this->buffer = $threaded;
$this->start();
}
@ -70,7 +72,6 @@ class CommandReader extends Thread{
}
public function run(){
$this->buffer = new \Threaded;
$opts = getopt("", ["disable-readline"]);
if(extension_loaded("readline") and $this->stream === "php://stdin" and !isset($opts["disable-readline"])){
$this->readline = true;

View File

@ -22,6 +22,7 @@
namespace pocketmine\command;
use pocketmine\Server;
use pocketmine\utils\MainLogger;
use pocketmine\utils\TextFormat;
class FormattedCommandAlias extends Command{
@ -49,6 +50,9 @@ class FormattedCommandAlias extends Command{
$sender->sendMessage(TextFormat::RED . $e->getMessage());
}else{
$sender->sendMessage(TextFormat::RED . "An internal error occurred while attempting to perform this command");
if(($logger = $sender->getServer()->getLogger()) instanceof MainLogger){
$logger->logException($e);
}
}
return false;

View File

@ -56,6 +56,7 @@ use pocketmine\command\defaults\VanillaCommand;
use pocketmine\command\defaults\VersionCommand;
use pocketmine\command\defaults\WhitelistCommand;
use pocketmine\Server;
use pocketmine\utils\MainLogger;
class SimpleCommandMap implements CommandMap{
@ -178,7 +179,14 @@ class SimpleCommandMap implements CommandMap{
}
$target->timings->startTiming();
$target->execute($sender, $sentCommandLabel, $args);
try{
$target->execute($sender, $sentCommandLabel, $args);
}catch(\Exception $e){
$this->server->getLogger()->critical("Unhandled exception executing command '". $commandLine ."' in ". $target.": ".$e->getMessage());
if(($logger = $sender->getServer()->getLogger()) instanceof MainLogger){
$logger->logException($e);
}
}
$target->timings->stopTiming();
return true;

View File

@ -22,6 +22,7 @@
namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\network\protocol\SetDifficultyPacket;
use pocketmine\Server;
use pocketmine\utils\TextFormat;
@ -55,6 +56,9 @@ class DifficultyCommand extends VanillaCommand{
if($difficulty !== -1){
$sender->getServer()->setConfigInt("difficulty", $difficulty);
$pk = new SetDifficultyPacket();
$pk->difficulty = $sender->getServer()->getDifficulty();
Server::broadcastPacket($sender->getServer()->getOnlinePlayers(), $pk);
$sender->sendMessage("Set difficulty to " . $difficulty);
}else{
$sender->sendMessage("Unknown difficulty");

View File

@ -24,7 +24,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\TextFormat;
class KillCommand extends VanillaCommand{
@ -45,9 +44,7 @@ class KillCommand extends VanillaCommand{
}
if($sender instanceof Player){
//TODO: EntityDamageEvent
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
$sender->getServer()->getPluginManager()->callEvent($ev = new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
if($ev->isCancelled()){
return true;

View File

@ -41,9 +41,7 @@ class SaveOffCommand extends VanillaCommand{
return true;
}
foreach($sender->getServer()->getLevels() as $level){
$level->setAutoSave(false);
}
$sender->getServer()->setAutoSave(false);
Command::broadcastCommandMessage($sender, "Disabled level saving");

View File

@ -41,9 +41,7 @@ class SaveOnCommand extends VanillaCommand{
return true;
}
foreach($sender->getServer()->getLevels() as $level){
$level->setAutoSave(true);
}
$sender->getServer()->setAutoSave(true);
Command::broadcastCommandMessage($sender, "Enabled level saving");

View File

@ -46,7 +46,7 @@ class SetWorldSpawnCommand extends VanillaCommand{
if(count($args) === 0){
if($sender instanceof Player){
$level = $sender->getLevel();
$pos = $sender->round();
$pos = (new Vector3($sender->x, $sender->y, $sender->z))->round();
}else{
$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");

View File

@ -66,7 +66,7 @@ class SpawnpointCommand extends VanillaCommand{
if(count($args) === 4){
if($level !== null){
$pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawn();
$pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawnLocation();
$x = (int) $this->getRelativeDouble($pos->x, $sender, $args[1]);
$y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, 128);
$z = $this->getRelativeDouble($pos->z, $sender, $args[3]);

View File

@ -43,6 +43,7 @@ class StatusCommand extends VanillaCommand{
$server = $sender->getServer();
$sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----");
$sender->sendMessage(TextFormat::GOLD . "TPS: " . TextFormat::WHITE . $server->getTicksPerSecond());
$sender->sendMessage(TextFormat::GOLD . "TPS Load: " . TextFormat::WHITE . $server->getTickUsage() . "%");
//TODO: implement network speed
//$sender->sendMessage(TextFormat::GOLD . "Upload: " . TextFormat::WHITE . round($server->getNetwork()->getUploadSpeed() / 1024, 2) . " kB/s");
//$sender->sendMessage(TextFormat::GOLD . "Download: " . TextFormat::WHITE . round($server->getNetwork()->getDownloadSpeed() / 1024, 2) . " kB/s");
@ -50,4 +51,4 @@ class StatusCommand extends VanillaCommand{
return true;
}
}
}

View File

@ -23,7 +23,6 @@ namespace pocketmine\command\defaults;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\level\Position;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
@ -88,8 +87,7 @@ class TeleportCommand extends VanillaCommand{
}
if(count($args) < 3){
$pos = new Position($target->x, $target->y, $target->z, $target->getLevel());
$origin->teleport($pos);
$origin->teleport($target);
Command::broadcastCommandMessage($sender, "Teleported " . $origin->getDisplayName() . " to " . $target->getDisplayName());
return true;

View File

@ -32,12 +32,47 @@ class TimeCommand extends VanillaCommand{
parent::__construct(
$name,
"Changes the time on each world",
"/time set <value>\n/time add <value>"
"/time set <value>\n/time add <value>\n/time start|stop"
);
$this->setPermission("pocketmine.command.time.add;pocketmine.command.time.set");
$this->setPermission("pocketmine.command.time.add;pocketmine.command.time.set;pocketmine.command.time.start;pocketmine.command.time.stop");
}
public function execute(CommandSender $sender, $currentAlias, array $args){
if(count($args) < 1){
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
return false;
}
if($args[0] === "start"){
if(!$sender->hasPermission("pocketmine.command.time.start")){
$sender->sendMessage(TextFormat::RED . "You don't have permission to restart the time");
return true;
}
foreach($sender->getServer()->getLevels() as $level){
$level->checkTime();
$level->startTime();
$level->checkTime();
}
Command::broadcastCommandMessage($sender, "Restarted the time");
return true;
}elseif($args[0] === "stop"){
if(!$sender->hasPermission("pocketmine.command.time.stop")){
$sender->sendMessage(TextFormat::RED . "You don't have permission to stop the time");
return true;
}
foreach($sender->getServer()->getLevels() as $level){
$level->checkTime();
$level->stopTime();
$level->checkTime();
}
Command::broadcastCommandMessage($sender, "Stopped the time");
return true;
}
if(count($args) < 2){
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
@ -78,6 +113,7 @@ class TimeCommand extends VanillaCommand{
$level->setTime($level->getTime() + $value);
$level->checkTime();
}
Command::broadcastCommandMessage($sender, "Added " . $value ." to time");
}else{
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
}

View File

@ -93,40 +93,39 @@ class TimingsCommand extends VanillaCommand{
if($paste){
fseek($fileTimings, 0);
$data = [
"public" => false,
"description" => $sender->getServer()->getName() . " Timings",
"files" => [
"timings.txt" => [
"content" => stream_get_contents($fileTimings)
]
]
"syntax" => "text",
"poster" => $sender->getServer()->getName(),
"content" => stream_get_contents($fileTimings)
];
$ch = curl_init("https://api.github.com/gists");
$ch = curl_init("http://paste.ubuntu.com/");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_SLASHES));
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json", "User-Agent: " . $this->getName() . " " . $sender->getServer()->getPocketMineVersion()]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_AUTOREFERER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: " . $this->getName() . " " . $sender->getServer()->getPocketMineVersion()]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$ret = curl_exec($ch);
$data = json_decode($ret);
$data = curl_exec($ch);
curl_close($ch);
if($data === false or $data === null or !isset($data->html_url)){
if(preg_match('#^Location: http://paste\\.ubuntu\\.com/([0-9]{1,})/#m', $data, $matches) == 0){
$sender->sendMessage("An error happened while pasting the report");
return true;
}
$timings = $data->html_url;
}
fclose($fileTimings);
$sender->sendMessage("Timings written to " . $timings);
$sender->sendMessage("Paste contents of file into form at http://aikar.co/timings.php to read results.");
$sender->sendMessage("Timings uploaded to http://paste.ubuntu.com/".$matches[1]."/");
$sender->sendMessage("You can read the results at http://timings.aikar.co/?url=".$matches[1]);
fclose($fileTimings);
}else{
fclose($fileTimings);
$sender->sendMessage("Timings written to " . $timings);
}
}
return true;

View File

@ -21,17 +21,9 @@
namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\level\format\FullChunk;
use pocketmine\level\MovingObjectPosition;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Short;
use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\AddEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player;
class Arrow extends Projectile{
@ -41,149 +33,33 @@ class Arrow extends Projectile{
public $length = 0.5;
public $height = 0.5;
/** @var Entity */
public $shootingEntity = null;
protected $gravity = 0.05;
protected $drag = 0.01;
private $damage = 6;
protected $damage = 6;
public function __construct(FullChunk $chunk, Compound $nbt, Entity $shootingEntity = null){
$this->shootingEntity = $shootingEntity;
parent::__construct($chunk, $nbt);
}
protected function initEntity(){
$this->namedtag->id = new String("id", "Arrow");
$this->setMaxHealth(1);
$this->setHealth(1);
if(isset($this->namedtag->Age)){
$this->age = $this->namedtag["Age"];
}
}
public function onUpdate(){
$this->entityBaseTick();
if($this->closed !== false){
public function onUpdate($currentTick){
if($this->closed){
return false;
}
$movingObjectPosition = null;
$this->timings->startTiming();
$this->motionY -= $this->gravity;
$this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
$moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
$list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this);
$nearDistance = PHP_INT_MAX;
$nearEntity = null;
foreach($list as $entity){
if(!$entity->canCollideWith($this) or ($entity === $this->shootingEntity and $this->ticksLived < 5)){
continue;
}
$axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3);
$ob = $axisalignedbb->calculateIntercept($this, $moveVector);
if($ob === null){
continue;
}
$distance = $this->distance($ob->hitVector);
if($distance < $nearDistance){
$nearDistance = $distance;
$nearEntity = $entity;
}
}
if($nearEntity !== null){
$movingObjectPosition = MovingObjectPosition::fromEntity($nearEntity);
}
if($movingObjectPosition !== null){
if($movingObjectPosition->entityHit !== null){
$motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2);
$damage = ceil($motion * $this->damage);
$ev = new EntityDamageByEntityEvent($this->shootingEntity === null ? $this : $this->shootingEntity, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
$this->server->getPluginManager()->callEvent($ev);
if(!$ev->isCancelled()){
$movingObjectPosition->entityHit->attack($damage, $ev);
if($this->fireTicks > 0){
$movingObjectPosition->entityHit->setOnFire(5);
}
$this->kill();
}
}
}
$this->move($this->motionX, $this->motionY, $this->motionZ);
$friction = 1 - $this->drag;
if($this->onGround){
$friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction;
}
$this->motionX *= $friction;
$this->motionY *= 1 - $this->drag;
$this->motionZ *= $friction;
if($this->onGround){
$this->motionX = 0;
$this->motionY = 0;
$this->motionZ = 0;
}
if($this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0){
$f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2));
$this->yaw = (atan2($this->motionX, $this->motionZ) * 180 / M_PI);
$this->pitch = (atan2($this->motionY, $f) * 180 / M_PI);
}
$hasUpdate = parent::onUpdate($currentTick);
if($this->age > 1200){
$this->kill();
$hasUpdate = true;
}
$this->updateMovement();
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
}
$this->timings->stopTiming();
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
$this->setLastDamageCause($source);
$this->setHealth($this->getHealth() - $damage);
}
public function heal($amount){
}
public function saveNBT(){
$this->namedtag->Age = new Short("Age", $this->age);
}
public function getData(){
$flags = 0;
$flags |= $this->fireTicks > 0 ? 1 : 0;
return [
0 => ["type" => 0, "value" => $flags]
];
}
public function canCollideWith(Entity $entity){
return $entity instanceof Living and !$this->onGround;
return $hasUpdate;
}
public function spawnTo(Player $player){
@ -196,11 +72,7 @@ class Arrow extends Projectile{
$pk->did = 0; //TODO: send motion here
$player->dataPacket($pk);
$pk = new SetEntityMotionPacket();
$pk->entities = [
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
];
$player->dataPacket($pk);
$player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ);
parent::spawnTo($player);
}

View File

@ -22,11 +22,6 @@
namespace pocketmine\entity;
use pocketmine\nbt\tag\String;
class Chicken extends Animal{
protected function initEntity(){
$this->namedtag->id = new String("id", "Chicken");
}
}

View File

@ -22,10 +22,6 @@
namespace pocketmine\entity;
use pocketmine\nbt\tag\String;
class Cow extends Animal{
protected function initEntity(){
$this->namedtag->id = new String("id", "Cow");
}
}

View File

@ -22,10 +22,6 @@
namespace pocketmine\entity;
use pocketmine\nbt\tag\String;
class Creeper extends Monster implements Explosive{
protected function initEntity(){
$this->namedtag->id = new String("id", "Creeper");
}
}

View File

@ -22,10 +22,6 @@
namespace pocketmine\entity;
use pocketmine\nbt\tag\String;
class Egg extends Projectile{
protected function initEntity(){
$this->namedtag->id = new String("id", "Egg");
}
}

View File

@ -23,10 +23,7 @@ namespace pocketmine\entity;
use pocketmine\inventory\InventoryHolder;
use pocketmine\nbt\tag\String;
class Enderman extends Monster implements InventoryHolder{
protected function initEntity(){
$this->namedtag->id = new String("id", "Enderman");
}
}

View File

@ -24,22 +24,23 @@
*/
namespace pocketmine\entity;
use pocketmine\block\Block;
use pocketmine\block\Water;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDespawnEvent;
use pocketmine\event\entity\EntityLevelChangeEvent;
use pocketmine\event\entity\EntityMotionEvent;
use pocketmine\event\entity\EntityMoveEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\entity\EntitySpawnEvent;
use pocketmine\event\entity\EntityTeleportEvent;
use pocketmine\event\Timings;
use pocketmine\level\format\Chunk;
use pocketmine\level\format\FullChunk;
use pocketmine\level\Level;
use pocketmine\level\Location;
use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\math\Math;
use pocketmine\math\Vector3;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\Byte;
@ -48,22 +49,26 @@ use pocketmine\nbt\tag\Double;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Float;
use pocketmine\nbt\tag\Short;
use pocketmine\network\protocol\MoveEntityPacket;
use pocketmine\nbt\tag\String;
use pocketmine\Network;
use pocketmine\network\protocol\MovePlayerPacket;
use pocketmine\network\protocol\RemoveEntityPacket;
use pocketmine\network\protocol\SetEntityDataPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\network\protocol\SetTimePacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\utils\ChunkException;
abstract class Entity extends Location implements Metadatable{
abstract class Entity extends Position implements Metadatable{
const NETWORK_ID = -1;
public static $entityCount = 1;
/** @var Entity[] */
private static $knownEntities = [];
private static $shortNames = [];
/**
* @var Player[]
@ -85,9 +90,9 @@ abstract class Entity extends Position implements Metadatable{
protected $lastDamageCause = null;
public $lastX;
public $lastY;
public $lastZ;
public $lastX = null;
public $lastY = null;
public $lastZ = null;
public $motionX;
public $motionY;
@ -96,8 +101,6 @@ abstract class Entity extends Position implements Metadatable{
public $lastMotionY;
public $lastMotionZ;
public $yaw;
public $pitch;
public $lastYaw;
public $lastPitch;
@ -123,7 +126,7 @@ abstract class Entity extends Position implements Metadatable{
protected $ySize = 0;
protected $stepHeight = 0;
public $keepMovement = true;
public $keepMovement = false;
public $fallDistance;
public $ticksLived;
@ -132,17 +135,19 @@ abstract class Entity extends Position implements Metadatable{
public $fireTicks;
public $airTicks;
public $namedtag;
protected $isStatic = false;
protected $isColliding = false;
public $canCollide = true;
protected $isStatic = false;
public $isCollided = false;
public $isCollidedHorizontally = false;
public $isCollidedVertically = false;
protected $inWater;
public $noDamageTicks;
private $justCreated;
protected $fireProof;
private $invulnerable;
protected $spawnTime;
protected $gravity;
protected $drag;
@ -151,19 +156,25 @@ abstract class Entity extends Position implements Metadatable{
public $closed = false;
/** @var \pocketmine\event\TimingsHandler */
protected $timings;
public function __construct(FullChunk $chunk, Compound $nbt){
if($chunk === null or $chunk->getProvider() === null){
throw new \Exception("Invalid garbage Chunk given to Entity");
throw new ChunkException("Invalid garbage Chunk given to Entity");
}
$this->timings = Timings::getEntityTimings($this);
if($this->eyeHeight === null){
$this->eyeHeight = $this->height;
$this->eyeHeight = $this->height / 2 + 0.1;
}
$this->id = Entity::$entityCount++;
$this->justCreated = true;
$this->namedtag = $nbt;
$this->chunk = $chunk;
$this->setLevel($chunk->getProvider()->getLevel());
$this->server = $chunk->getProvider()->getLevel()->getServer();
@ -197,7 +208,7 @@ abstract class Entity extends Position implements Metadatable{
$this->airTicks = $this->namedtag["Air"];
if(!isset($this->namedtag->OnGround)){
$this->namedtag->OnGround = new Byte("OnGround", 1);
$this->namedtag->OnGround = new Byte("OnGround", 0);
}
$this->onGround = $this->namedtag["OnGround"] > 0 ? true : false;
@ -207,16 +218,63 @@ abstract class Entity extends Position implements Metadatable{
$this->invulnerable = $this->namedtag["Invulnerable"] > 0 ? true : false;
$this->chunk->addEntity($this);
$this->getLevel()->addEntity($this);
$this->level->addEntity($this);
$this->initEntity();
$this->lastUpdate = $this->spawnTime = microtime(true);
$this->lastUpdate = $this->server->getTick();
$this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this));
$this->scheduleUpdate();
}
/**
* @param int|string $type
* @param FullChunk $chunk
* @param Compound $nbt
* @param $args
*
* @return Entity
*/
public static function createEntity($type, FullChunk $chunk, Compound $nbt, ...$args){
if(isset(self::$knownEntities[$type])){
$class = self::$knownEntities[$type];
return new $class($chunk, $nbt, ...$args);
}
return null;
}
public static function registerEntity($className, $force = false){
$class = new \ReflectionClass($className);
if(is_a($className, Entity::class, true) and !$class->isAbstract()){
if($className::NETWORK_ID !== -1){
self::$knownEntities[$className::NETWORK_ID] = $className;
}elseif(!$force){
return false;
}
self::$knownEntities[$class->getShortName()] = $className;
self::$shortNames[$className] = $class->getShortName();
return true;
}
return false;
}
/**
* Returns the short save name
*
* @return string
*/
public function getSaveId(){
return self::$shortNames[static::class];
}
public function saveNBT(){
if(!($this instanceof Player)){
$this->namedtag->id = new String("id", $this->getSaveId());
}
$this->namedtag->Pos = new Enum("Pos", [
new Double(0, $this->x),
new Double(1, $this->y),
@ -270,13 +328,15 @@ abstract class Entity extends Position implements Metadatable{
$pk = new SetEntityDataPacket();
$pk->eid = $this->id;
$pk->metadata = $this->getData();
$pk->encode();
$pk->isEncoded = true;
foreach($player as $p){
if($p === $this){
/** @var Player $p */
$pk = new SetEntityDataPacket();
$pk->eid = 0;
$pk->metadata = $this->getData();
$p->dataPacket($pk);
$pk2 = new SetEntityDataPacket();
$pk2->eid = 0;
$pk2->metadata = $this->getData();
$p->dataPacket($pk2);
}else{
$p->dataPacket($pk);
}
@ -288,7 +348,7 @@ abstract class Entity extends Position implements Metadatable{
*/
public function despawnFrom(Player $player){
if(isset($this->hasSpawned[$player->getID()])){
$pk = new RemoveEntityPacket;
$pk = new RemoveEntityPacket();
$pk->eid = $this->id;
$player->dataPacket($pk);
unset($this->hasSpawned[$player->getID()]);
@ -299,11 +359,15 @@ abstract class Entity extends Position implements Metadatable{
* @param float $damage
* @param int|EntityDamageEvent $source
*
* @return mixed
*/
abstract function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC);
abstract function heal($amount);
/**
* @param float $amount
* @param int|EntityRegainHealthEvent $source
*
*/
abstract function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC);
/**
* @return int
@ -338,7 +402,7 @@ abstract class Entity extends Position implements Metadatable{
* @param int|EntityDamageEvent $type
*/
public function setLastDamageCause($type){
$this->lastDamageCause = $type;
$this->lastDamageCause = $type instanceof EntityDamageEvent ? clone $type : $type;
}
/**
@ -376,17 +440,19 @@ abstract class Entity extends Position implements Metadatable{
$diffY = $y - $j;
$diffZ = $z - $k;
$list = $this->getLevel()->getCollisionBlocks($this->boundingBox);
$list = $this->level->getCollisionBlocks($this->boundingBox);
if(count($list) === 0 and !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k))){
$v = new Vector3($i, $j, $k);
if(count($list) === 0 and !$this->level->isFullBlock($v->setComponents($i, $j, $k))){
return false;
}else{
$flag = !$this->getLevel()->isFullBlock(new Vector3($i - 1, $j, $k));
$flag1 = !$this->getLevel()->isFullBlock(new Vector3($i + 1, $j, $k));
//$flag2 = !$this->getLevel()->isFullBlock(new Vector3($i, $j - 1, $k));
$flag3 = !$this->getLevel()->isFullBlock(new Vector3($i, $j + 1, $k));
$flag4 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k - 1));
$flag5 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k + 1));
$flag = !$this->level->isFullBlock($v->setComponents($i - 1, $j, $k));
$flag1 = !$this->level->isFullBlock($v->setComponents($i + 1, $j, $k));
//$flag2 = !$this->level->isFullBlock($v->setComponents($i, $j - 1, $k));
$flag3 = !$this->level->isFullBlock($v->setComponents($i, $j + 1, $k));
$flag4 = !$this->level->isFullBlock($v->setComponents($i, $j, $k - 1));
$flag5 = !$this->level->isFullBlock($v->setComponents($i, $j, $k + 1));
$direction = 3; //UP!
$limit = 9999;
@ -452,72 +518,60 @@ abstract class Entity extends Position implements Metadatable{
}
}
public function entityBaseTick(){
public function entityBaseTick($tickDiff = 1){
Timings::$tickEntityTimer->startTiming();
//TODO: check vehicles
$this->justCreated = false;
$isPlayer = $this instanceof Player;
if($this->dead === true and !($this instanceof Player)){
$this->close();
return false;
}elseif($this->dead === true){
if($this->dead === true){
$this->despawnFromAll();
if(!$isPlayer){
$this->close();
}
Timings::$tickEntityTimer->stopTiming();
return $isPlayer;
}
$hasUpdate = false;
$this->updateMovement();
$this->checkBlockCollision();
if($this->handleWaterMovement()){
$this->fallDistance = 0;
$this->inWater = true;
$this->extinguish();
}else{
$this->inWater = false;
}
if($this->y < 0 and $this->dead !== true){
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10));
if(!$ev->isCancelled()){
$this->attack($ev->getFinalDamage(), $ev);
}
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10);
$this->attack($ev->getFinalDamage(), $ev);
$hasUpdate = true;
}
if($this->fireTicks > 0){
if($this->fireProof){
$this->fireTicks -= 4;
$this->fireTicks -= 4 * $tickDiff;
if($this->fireTicks < 0){
$this->fireTicks = 0;
}
}else{
if(($this->fireTicks % 20) === 0){
if(($this->fireTicks % 20) === 0 or $tickDiff > 20){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
$this->server->getPluginManager()->callEvent($ev);
if(!$ev->isCancelled()){
$this->attack($ev->getFinalDamage(), $ev);
}
$this->attack($ev->getFinalDamage(), $ev);
}
--$this->fireTicks;
$this->fireTicks -= $tickDiff;
}
if($this->fireTicks <= 0){
$this->extinguish();
}else{
$hasUpdate = true;
}
$hasUpdate = true;
}
if($this->handleLavaMovement()){
//$this->attack(4, EntityDamageEvent::CAUSE_LAVA);
//$this->setOnFire(15);
$hasUpdate = true;
$this->fallDistance *= 0.5;
}
$this->age += $tickDiff;
$this->ticksLived += $tickDiff;
++$this->age;
++$this->ticksLived;
Timings::$tickEntityTimer->stopTiming();
return $hasUpdate;
}
public function updateMovement(){
@ -530,25 +584,21 @@ abstract class Entity extends Position implements Metadatable{
$this->lastPitch = $this->pitch;
if($this instanceof Human){
$pk = new MovePlayerPacket;
$pk = new MovePlayerPacket();
$pk->eid = $this->id;
$pk->x = $this->x;
$pk->y = $this->y; //teleport from head
$pk->y = $this->y;
$pk->z = $this->z;
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->bodyYaw = $this->yaw;
Server::broadcastPacket($this->hasSpawned, $pk);
}else{
//TODO: add to move list
$pk = new MoveEntityPacket();
$pk->entities = [
[$this->id, $this->x, $this->y, $this->z, $this->yaw, $this->pitch]
];
foreach($this->hasSpawned as $player){
$player->addEntityMovement($this->id, $this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch);
}
}
foreach($this->hasSpawned as $player){
$player->directDataPacket($pk);
}
}
if(($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){
@ -556,11 +606,9 @@ abstract class Entity extends Position implements Metadatable{
$this->lastMotionY = $this->motionY;
$this->lastMotionZ = $this->motionZ;
$pk = new SetEntityMotionPacket;
$pk->entities = [
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
];
Server::broadcastPacket($this->hasSpawned, $pk);
foreach($this->hasSpawned as $player){
$player->addEntityMotion($this->id, $this->motionX, $this->motionY, $this->motionZ);
}
if($this instanceof Player){
$this->motionX = 0;
@ -585,15 +633,24 @@ abstract class Entity extends Position implements Metadatable{
return new Vector3($x, $y, $z);
}
public function onUpdate(){
if($this->closed !== false){
public function onUpdate($currentTick){
if($this->closed){
return false;
}
$hasUpdate = $this->entityBaseTick();
$tickDiff = max(1, $currentTick - $this->lastUpdate);
$this->lastUpdate = $currentTick;
$this->timings->startTiming();
$hasUpdate = $this->entityBaseTick($tickDiff);
$this->updateMovement();
$this->timings->stopTiming();
//if($this->isStatic())
return true;
return $hasUpdate;
//return !($this instanceof Player);
}
@ -665,18 +722,11 @@ abstract class Entity extends Position implements Metadatable{
public function fall($fallDistance){
$damage = floor($fallDistance - 3);
if($damage > 0){
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage));
if($ev->isCancelled()){
return;
}
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage);
$this->attack($ev->getFinalDamage(), $ev);
}
}
public function handleWaterMovement(){ //TODO
}
public function handleLavaMovement(){ //TODO
}
@ -695,34 +745,32 @@ abstract class Entity extends Position implements Metadatable{
protected function switchLevel(Level $targetLevel){
if($this->isValid()){
$this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->getLevel(), $targetLevel));
$this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel));
if($ev->isCancelled()){
return false;
}
$this->getLevel()->removeEntity($this);
$this->chunk->removeEntity($this);
$this->level->removeEntity($this);
if($this->chunk !== null){
$this->chunk->removeEntity($this);
}
$this->despawnFromAll();
if($this instanceof Player){
foreach($this->usedChunks as $index => $d){
$X = null;
$Z = null;
Level::getXZ($index, $X, $Z);
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
$entity->despawnFrom($this);
}
$this->unloadChunk($X, $Z);
}
$this->getLevel()->freeAllChunks($this);
}
}
$this->setLevel($targetLevel, $this instanceof Player ? true : false); //Hard reference
$this->getLevel()->addEntity($this);
$this->setLevel($targetLevel);
$this->level->addEntity($this);
if($this instanceof Player){
$this->usedChunks = [];
$pk = new SetTimePacket();
$pk->time = $this->getLevel()->getTime();
$pk->started = $this->getLevel()->stopTime == false;
$pk->time = $this->level->getTime();
$pk->started = $this->level->stopTime == false;
$this->dataPacket($pk);
}
$this->chunk = null;
@ -731,14 +779,18 @@ abstract class Entity extends Position implements Metadatable{
}
public function getPosition(){
return new Position($this->x, $this->y, $this->z, $this->getLevel());
return new Position($this->x, $this->y, $this->z, $this->level);
}
public function getLocation(){
return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->level);
}
public function isInsideOfWater(){
$block = $this->getLevel()->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
$block = $this->level->getBlock(new Vector3(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z)));
if($block instanceof Water){
$f = ($pos->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
$f = ($block->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
return $y < $f;
}
@ -746,31 +798,14 @@ abstract class Entity extends Position implements Metadatable{
}
public function isInsideOfSolid(){
for($i = 0; $i < 8; ++$i){
$x = (($i % 2) - 0.5) * $this->width * 0.8;
$y = ((($i >> 1) % 2) - 0.5) * 0.1;
$z = ((($i >> 2) % 2) - 0.5) * $this->width * 0.8;
$block = $this->getLevel()->getBlock((new Vector3($this->x + $x, $this->y + $this->getEyeHeight() + $y, $this->z + $z))->floor());
$block = $this->level->getBlock(new Vector3(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z)));
if($block->isSolid){
return true;
}
$bb = $block->getBoundingBox();
if($bb !== null and $block->isSolid and !$block->isTransparent and $bb->intersectsWith($this->getBoundingBox())){
return true;
}
return false;
$block = $this->getLevel()->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
if($block instanceof Water){
$f = ($pos->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
return $y < $f;
}
return false;
}
public function collision(){
$this->isColliding = true;
$this->fallDistance = 0;
}
public function move($dx, $dy, $dz){
@ -779,12 +814,11 @@ abstract class Entity extends Position implements Metadatable{
return true;
}
//if($this->inBlock){ //TODO: noclip
// $this->boundingBox->offset($dx, $dy, $dz);
// $this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
// $this->y = $this->boundingBox->minY/* + $this->height*/;
// $this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;
//}else{
if($this->keepMovement){
$this->boundingBox->offset($dx, $dy, $dz);
$this->setPosition(new Vector3(($this->boundingBox->minX + $this->boundingBox->maxX) / 2, $this->boundingBox->minY - $this->ySize, ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2));
$this->onGround = $this instanceof Player ? true : false;
}else{
Timings::$entityMoveTimer->startTiming();
@ -811,7 +845,7 @@ abstract class Entity extends Position implements Metadatable{
/*$sneakFlag = $this->onGround and $this instanceof Player;
if($sneakFlag){
for($mov = 0.05; $dx != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
for($mov = 0.05; $dx != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
if($dx < $mov and $dx >= -$mov){
$dx = 0;
}elseif($dx > 0){
@ -821,7 +855,7 @@ abstract class Entity extends Position implements Metadatable{
}
}
for(; $dz != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
for(; $dz != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
if($dz < $mov and $dz >= -$mov){
$dz = 0;
}elseif($dz > 0){
@ -834,7 +868,7 @@ abstract class Entity extends Position implements Metadatable{
//TODO: big messy loop
}*/
$list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, $dy, $dz));
$list = $this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, $dy, $dz));
foreach($list as $bb){
@ -843,7 +877,7 @@ abstract class Entity extends Position implements Metadatable{
$this->boundingBox->offset(0, $dy, 0);
if(!$this->keepMovement and $movY != $dy){
if($movY != $dy){
$dx = 0;
$dy = 0;
$dz = 0;
@ -857,7 +891,7 @@ abstract class Entity extends Position implements Metadatable{
$this->boundingBox->offset($dx, 0, 0);
if(!$this->keepMovement and $movX != $dx){
if($movX != $dx){
$dx = 0;
$dy = 0;
$dz = 0;
@ -869,7 +903,7 @@ abstract class Entity extends Position implements Metadatable{
$this->boundingBox->offset(0, 0, $dz);
if(!$this->keepMovement and $movZ != $dz){
if($movZ != $dz){
$dx = 0;
$dy = 0;
$dz = 0;
@ -888,14 +922,14 @@ abstract class Entity extends Position implements Metadatable{
$this->boundingBox->setBB($axisalignedbb);
$list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ));
$list = $this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ), false);
foreach($list as $bb){
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
}
$this->boundingBox->offset(0, $dy, 0);
if(!$this->keepMovement and $movY != $dy){
if($movY != $dy){
$dx = 0;
$dy = 0;
$dz = 0;
@ -906,7 +940,7 @@ abstract class Entity extends Position implements Metadatable{
}
$this->boundingBox->offset($dx, 0, 0);
if(!$this->keepMovement and $movX != $dx){
if($movX != $dx){
$dx = 0;
$dy = 0;
$dz = 0;
@ -917,13 +951,13 @@ abstract class Entity extends Position implements Metadatable{
}
$this->boundingBox->offset(0, 0, $dz);
if(!$this->keepMovement and $movZ != $dz){
if($movZ != $dz){
$dx = 0;
$dy = 0;
$dz = 0;
}
if(!$this->keepMovement and $movY != $dy){
if($movY != $dy){
$dx = 0;
$dy = 0;
$dz = 0;
@ -946,7 +980,7 @@ abstract class Entity extends Position implements Metadatable{
$pos = new Vector3(
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
$this->boundingBox->minY - $this->ySize/* + $this->height*/,
$this->boundingBox->minY - $this->ySize,
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
);
@ -958,16 +992,20 @@ abstract class Entity extends Position implements Metadatable{
}else{
if($this instanceof Player){
if(($this->onGround and $movY != 0) or (!$this->onGround and $movY <= 0)){
if(count($this->getLevel()->getCollisionBlocks($this->boundingBox->getOffsetBoundingBox(0, $movY - 0.1, 0))) > 0){
$isColliding = true;
if(!$this->onGround or $movY != 0){
$bb = clone $this->boundingBox;
$bb->maxY = $bb->minY + 1;
if(count($this->level->getCollisionBlocks($bb->expand(0.01, 0.01, 0.01))) > 0){
$this->onGround = true;
}else{
$isColliding = false;
$this->onGround = false;
}
$this->onGround = ($movY <= 0 and $isColliding);
}
$this->isCollided = $this->onGround;
}else{
$this->isCollidedVertically = $movY != $dy;
$this->isCollidedHorizontally = ($movX != $dx or $movZ != $dz);
$this->isCollided = ($this->isCollidedHorizontally or $this->isCollidedVertically);
$this->onGround = ($movY != $dy and $movY < 0);
}
$this->updateFallState($dy, $this->onGround);
@ -990,31 +1028,45 @@ abstract class Entity extends Position implements Metadatable{
Timings::$entityMoveTimer->stopTiming();
return $result;
//}
}
}
protected function checkBlockCollision(){
$minX = floor($this->boundingBox->minX - 0.001);
$minY = floor($this->boundingBox->minY - 0.001);
$minZ = floor($this->boundingBox->minZ - 0.001);
$maxX = floor($this->boundingBox->maxX + 0.001);
$maxY = floor($this->boundingBox->maxY + 0.001);
$maxZ = floor($this->boundingBox->maxZ + 0.001);
$minX = Math::floorFloat($this->boundingBox->minX + 0.001);
$minY = Math::floorFloat($this->boundingBox->minY + 0.001);
$minZ = Math::floorFloat($this->boundingBox->minZ + 0.001);
$maxX = Math::floorFloat($this->boundingBox->maxX - 0.001);
$maxY = Math::floorFloat($this->boundingBox->maxY - 0.001);
$maxZ = Math::floorFloat($this->boundingBox->maxZ - 0.001);
for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
if($block !== null and $block->getID() > 0){
$vector = new Vector3(0, 0, 0);
$v = new Vector3(0, 0, 0);
for($v->z = $minZ; $v->z <= $maxZ; ++$v->z){
for($v->x = $minX; $v->x <= $maxX; ++$v->x){
for($v->y = $minY; $v->y <= $maxY; ++$v->y){
$block = $this->level->getBlock($v);
if($block !== null and $block->hasEntityCollision){
$block->onEntityCollide($this);
if(!($this instanceof Player)){
$block->addVelocityToEntity($this, $vector);
}
}
}
}
}
if(!($this instanceof Player) and $vector->length() > 0){
$vector = $vector->normalize();
$d = 0.014;
$this->motionX += $vector->x * $d;
$this->motionY += $vector->y * $d;
$this->motionZ += $vector->z * $d;
}
}
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch, $force = false){
if($this->setPosition($pos, $force) === true){
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){
if($this->setPosition($pos) === true){
$this->setRotation($yaw, $pitch);
return true;
@ -1029,18 +1081,13 @@ abstract class Entity extends Position implements Metadatable{
$this->scheduleUpdate();
}
public function setPosition(Vector3 $pos, $force = false){
if($pos instanceof Position and $pos->getLevel() instanceof Level and $pos->getLevel() !== $this->getLevel()){
if($this->switchLevel($pos->getLevel()) === false){
return false;
}
public function setPosition(Vector3 $pos){
if($this->closed){
return false;
}
if(!$this->justCreated and $force !== true){
$ev = new EntityMoveEvent($this, $pos);
$this->server->getPluginManager()->callEvent($ev);
if($ev->isCancelled()){
if($pos instanceof Position and $pos->level instanceof Level and $pos->level !== $this->level){
if($this->switchLevel($pos->getLevel()) === false){
return false;
}
}
@ -1057,11 +1104,11 @@ abstract class Entity extends Position implements Metadatable{
if($this->chunk instanceof FullChunk){
$this->chunk->removeEntity($this);
}
$this->getLevel()->loadChunk($this->x >> 4, $this->z >> 4);
$this->chunk = $this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4);
$this->level->loadChunk($this->x >> 4, $this->z >> 4);
$this->chunk = $this->level->getChunk($this->x >> 4, $this->z >> 4);
if(!$this->justCreated){
$newChunk = $this->getLevel()->getUsingChunk($this->x >> 4, $this->z >> 4);
$newChunk = $this->level->getUsingChunk($this->x >> 4, $this->z >> 4);
foreach($this->hasSpawned as $player){
if(!isset($newChunk[$player->getID()])){
$this->despawnFrom($player);
@ -1091,16 +1138,14 @@ abstract class Entity extends Position implements Metadatable{
return false;
}
}
$this->motionX = $motion->x;
$this->motionY = $motion->y;
$this->motionZ = $motion->z;
if(!$this->justCreated){
if($this instanceof Player){
$pk = new SetEntityMotionPacket;
$pk->entities = [
[0, $this->motionX, $this->motionY, $this->motionZ]
];
$this->dataPacket($pk);
$this->addEntityMotion(0, $this->motionX, $this->motionY, $this->motionZ);
}
$this->updateMovement();
}
@ -1121,9 +1166,20 @@ abstract class Entity extends Position implements Metadatable{
$this->scheduleUpdate();
}
/**
* @param Vector3|Position|Location $pos
* @param float $yaw
* @param float $pitch
*
* @return bool
*/
public function teleport(Vector3 $pos, $yaw = null, $pitch = null){
$from = Position::fromObject($this, $this->getLevel());
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->getLevel());
if($pos instanceof Location){
$yaw = $pos->yaw;
$pitch = $pos->pitch;
}
$from = Position::fromObject($this, $this->level);
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level);
$this->server->getPluginManager()->callEvent($ev = new EntityTeleportEvent($this, $from, $to));
if($ev->isCancelled()){
return false;
@ -1142,12 +1198,12 @@ abstract class Entity extends Position implements Metadatable{
return false;
}
public function getID(){
public function getId(){
return $this->id;
}
public function spawnToAll(){
foreach($this->getLevel()->getUsingChunk($this->x >> 4, $this->z >> 4) as $player){
foreach($this->level->getUsingChunk($this->x >> 4, $this->z >> 4) as $player){
if(isset($player->id) and $player->spawned === true){
$this->spawnTo($player);
}
@ -1161,17 +1217,18 @@ abstract class Entity extends Position implements Metadatable{
}
public function close(){
if($this->closed === false){
if(!$this->closed){
$this->server->getPluginManager()->callEvent(new EntityDespawnEvent($this));
$this->closed = true;
unset($this->level->updateEntities[$this->id]);
if($this->chunk instanceof FullChunk){
$this->chunk->removeEntity($this);
}
if(($level = $this->getLevel()) instanceof Level){
$level->removeEntity($this);
if($this->level instanceof Level){
$this->level->removeEntity($this);
}
$this->despawnFromAll();
$this->level = null;
}
}

View File

@ -24,4 +24,5 @@ namespace pocketmine\entity;
interface Explosive{
public function explode();
}

View File

@ -1,143 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\entity;
use pocketmine\nbt\tag\String;
use pocketmine\nbt\tag\Byte;
use pocketmine\block\Block;
use pocketmine\item\Item;
use pocketmine\network\protocol\AddEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player;
use pocketmine\event\entity\EntityDamageEvent;
class FallingBlock extends Entity{
const NETWORK_ID = 66;
public $width = 0.98;
public $length = 0.98;
public $height = 0.98;
protected $gravity = 0.04;
protected $drag = 0.02;
protected $blockId = 0;
protected function initEntity(){
$this->namedtag->id = new String("id", "FallingSand");
if(isset($this->namedtag->Tile)){
$this->blockId = $this->namedtag["Tile"];
}
if($this->blockId === 0){
$this->close();
}
}
public function canCollideWith(Entity $entity){
return false;
}
public function getData(){
return [];
}
public function onUpdate(){
$this->entityBaseTick();
if($this->closed !== false){
return false;
}
$this->motionY -= $this->gravity;
$this->move($this->motionX, $this->motionY, $this->motionZ);
$friction = 1 - $this->drag;
$this->motionX *= $friction;
$this->motionY *= 1 - $this->drag;
$this->motionZ *= $friction;
$pos = $this->floor();
if($this->ticksLived === 1){
$block = $this->level->getBlock($pos);
if($block->getID() != $this->blockId){
$this->kill();
return true;
}
$this->level->setBlock($pos, Block::get(0, true));
}
if($this->onGround){
$this->kill();
$block = $this->level->getBlock($pos);
if(!$block->isFullBlock){
$this->getLevel()->dropItem($this, Item::get($this->getBlock(), 0, 1));
}else{
$this->getLevel()->setBlock($pos, Block::get($this->getBlock(), 0), true);
}
}
$this->updateMovement();
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
}
public function getBlock(){
return $this->blockId;
}
public function saveNBT(){
$this->namedtag->Tile = new Byte("Tile", $this->blockId);
}
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
}
public function heal($amount){
}
public function spawnTo(Player $player){
$pk = new AddEntityPacket;
$pk->type = FallingBlock::NETWORK_ID;
$pk->eid = $this->getID();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$pk->did = -$this->getBlock();
$player->dataPacket($pk);
$pk = new SetEntityMotionPacket;
$pk->entities = [
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
];
$player->dataPacket($pk);
parent::spawnTo($player);
}
}

View File

@ -0,0 +1,165 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\entity;
use pocketmine\block\Block;
use pocketmine\event\entity\EntityBlockChangeEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\item\Item as ItemItem;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Int;
use pocketmine\network\protocol\AddEntityPacket;
use pocketmine\Player;
class FallingSand extends Entity{
const NETWORK_ID = 66;
public $width = 0.98;
public $length = 0.98;
public $height = 0.98;
protected $gravity = 0.04;
protected $drag = 0.02;
protected $blockId = 0;
protected $damage;
public $canCollide = false;
protected function initEntity(){
if(isset($this->namedtag->TileID)){
$this->blockId = $this->namedtag["TileID"];
}elseif(isset($this->namedtag->Tile)){
$this->blockId = $this->namedtag["Tile"];
$this->namedtag["TileID"] = new Int("TileID", $this->blockId);
}
if(isset($this->namedtag->Data)){
$this->damage = $this->namedtag["Data"];
}
if($this->blockId === 0){
$this->close();
}
}
public function canCollideWith(Entity $entity){
return false;
}
public function getData(){
return [];
}
public function onUpdate($currentTick){
if($this->closed){
return false;
}
$this->timings->startTiming();
$tickDiff = max(1, $currentTick - $this->lastUpdate);
$this->lastUpdate = $currentTick;
$hasUpdate = $this->entityBaseTick($tickDiff);
if(!$this->dead){
if($this->ticksLived === 1){
$block = $this->level->getBlock($pos = (new Vector3($this->x, $this->y, $this->z))->floor());
if($block->getID() != $this->blockId){
$this->kill();
return true;
}
$this->level->setBlock($pos, Block::get(0), true);
}
$this->motionY -= $this->gravity;
$this->move($this->motionX, $this->motionY, $this->motionZ);
$friction = 1 - $this->drag;
$this->motionX *= $friction;
$this->motionY *= 1 - $this->drag;
$this->motionZ *= $friction;
$pos = (new Vector3($this->x, $this->y, $this->z))->floor();
if($this->onGround){
$this->kill();
$block = $this->level->getBlock($pos);
if(!$block->isFullBlock){
$this->getLevel()->dropItem($this, ItemItem::get($this->getBlock(), $this->getDamage(), 1));
}else{
$this->server->getPluginManager()->callEvent($ev = new EntityBlockChangeEvent($this, $block, Block::get($this->getBlock(), $this->getDamage())));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($pos, $ev->getTo(), true);
}
}
$hasUpdate = true;
}
$this->updateMovement();
}
return $hasUpdate or !$this->onGround or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0;
}
public function getBlock(){
return $this->blockId;
}
public function getDamage(){
return $this->damage;
}
public function saveNBT(){
$this->namedtag->TileID = new Int("TileID", $this->blockId);
$this->namedtag->Data = new Byte("Data", $this->damage);
}
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
}
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
}
public function spawnTo(Player $player){
$pk = new AddEntityPacket();
$pk->type = FallingSand::NETWORK_ID;
$pk->eid = $this->getID();
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$pk->did = -($this->getBlock() | $this->getDamage() << 0x10);
$player->dataPacket($pk);
$player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ);
parent::spawnTo($player);
}
}

View File

@ -23,16 +23,15 @@ namespace pocketmine\entity;
use pocketmine\inventory\InventoryHolder;
use pocketmine\inventory\PlayerInventory;
use pocketmine\item\Item;
use pocketmine\item\Item as ItemItem;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum;
use pocketmine\nbt\tag\Short;
use pocketmine\Network;
use pocketmine\network\protocol\AddPlayerPacket;
use pocketmine\network\protocol\RemovePlayerPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Network;
use pocketmine\Player;
use pocketmine\utils\TextFormat;
@ -67,9 +66,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar
$this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1);
}elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor
$this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, Item::get($item["id"], $item["Damage"], $item["Count"]), $this);
$this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, ItemItem::get($item["id"], $item["Damage"], $item["Count"]), $this);
}else{
$this->inventory->setItem($item["Slot"] - 9, Item::get($item["id"], $item["Damage"], $item["Count"]), $this);
$this->inventory->setItem($item["Slot"] - 9, ItemItem::get($item["id"], $item["Damage"], $item["Count"]), $this);
}
}
@ -86,10 +85,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
foreach($this->inventory->getContents() as $item){
$drops[] = $item;
}
foreach($this->inventory->getArmorContents() as $item){
$drops[] = $item;
}
}
return $drops;
@ -140,7 +135,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
//Armor
for($slot = 100; $slot < 104; ++$slot){
$item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100);
if($item instanceof Item and $item->getID() !== Item::AIR){
if($item instanceof ItemItem and $item->getID() !== ItemItem::AIR){
$this->namedtag->Inventory[$slot] = new Compound(false, [
new Byte("Count", $item->getCount()),
new Short("Damage", $item->getDamage()),
@ -156,7 +151,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
if($player !== $this and !isset($this->hasSpawned[$player->getID()])){
$this->hasSpawned[$player->getID()] = $player;
$pk = new AddPlayerPacket;
$pk = new AddPlayerPacket();
$pk->clientID = 0;
if($player->getRemoveFormat()){
$pk->username = TextFormat::clean($this->nameTag);
@ -169,18 +164,13 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$pk->z = $this->z;
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->unknown1 = 0;
$pk->unknown2 = 0;
$item = $this->getInventory()->getItemInHand();
$pk->item = $item->getID();
$pk->meta = $item->getDamage();
$pk->metadata = $this->getData();
$player->dataPacket($pk);
$pk = new SetEntityMotionPacket;
$pk->entities = [
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
];
$player->dataPacket($pk);
$this->inventory->sendHeldItem($player);
$player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ);
$this->inventory->sendArmorContents($player);
}
@ -188,7 +178,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
public function despawnFrom(Player $player){
if(isset($this->hasSpawned[$player->getID()])){
$pk = new RemovePlayerPacket;
$pk = new RemovePlayerPacket();
$pk->eid = $this->id;
$pk->clientID = 0;
$player->dataPacket($pk);
@ -208,22 +198,18 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
17 => ["type" => 6, "value" => [0, 0, 0]],
];
/*if($this->class === ENTITY_MOB and $this->type === MOB_SHEEP){
if(!isset($this->data["Sheared"])){
$this->data["Sheared"] = 0;
$this->data["Color"] = mt_rand(0,15);
}
$d[16]["value"] = (($this->data["Sheared"] == 1 ? 1:0) << 4) | ($this->data["Color"] & 0x0F);
}elseif($this->type === OBJECT_PRIMEDTNT){
$d[16]["value"] = (int) max(0, $this->data["fuse"] - (microtime(true) - $this->spawntime) * 20);
}elseif($this->class === ENTITY_PLAYER){
if($this->player->sleeping !== false){
$d[16]["value"] = 2;
$d[17]["value"] = array($this->player->sleeping->x, $this->player->sleeping->y, $this->player->sleeping->z);
}
}*/
return $d;
}
public function close(){
if(!$this->closed){
if(!($this instanceof Player) or $this->loggedIn){
foreach($this->inventory->getViewers() as $viewer){
$viewer->removeWindow($this->inventory);
}
}
parent::close();
}
}
}

View File

@ -22,22 +22,25 @@
namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\item\Item as ItemItem;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Short;
use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\AddItemEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player;
class DroppedItem extends Entity{
class Item extends Entity{
const NETWORK_ID = 64;
protected $owner = null;
protected $thrower = null;
protected $pickupDelay = 0;
/** @var Item */
/** @var ItemItem */
protected $item;
public $width = 0.25;
@ -46,10 +49,11 @@ class DroppedItem extends Entity{
protected $gravity = 0.04;
protected $drag = 0.02;
public $canCollide = false;
protected function initEntity(){
$this->namedtag->id = new String("id", "Item");
$this->setMaxHealth(5);
$this->setHealth(@$this->namedtag["Health"]);
$this->setHealth($this->namedtag["Health"]);
if(isset($this->namedtag->Age)){
$this->age = $this->namedtag["Age"];
}
@ -62,57 +66,86 @@ class DroppedItem extends Entity{
if(isset($this->namedtag->Thrower)){
$this->thrower = $this->namedtag["Thrower"];
}
$this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]);
$this->item = ItemItem::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]);
$this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this));
}
public function onUpdate(){
$this->entityBaseTick();
public function onUpdate($currentTick){
if($this->closed !== false){
return false;
}
if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay
--$this->pickupDelay;
$tickDiff = max(1, $currentTick - $this->lastUpdate);
$this->lastUpdate = $currentTick;
$this->timings->startTiming();
$hasUpdate = $this->entityBaseTick($tickDiff);
if(!$this->dead){
if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay
$this->pickupDelay -= $tickDiff;
}
$this->motionY -= $this->gravity;
$this->keepMovement = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
$this->move($this->motionX, $this->motionY, $this->motionZ);
$friction = 1 - $this->drag;
if($this->onGround and ($this->motionX != 0 or $this->motionZ != 0)){
$friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction;
}
$this->motionX *= $friction;
$this->motionY *= 1 - $this->drag;
$this->motionZ *= $friction;
$this->updateMovement();
if($this->onGround){
$this->motionY *= -0.5;
}
if($this->age > 6000){
$this->server->getPluginManager()->callEvent($ev = new ItemDespawnEvent($this));
if($ev->isCancelled()){
$this->age = 0;
}else{
$this->kill();
$hasUpdate = true;
}
}
}
$this->motionY -= $this->gravity;
$this->timings->stopTiming();
$this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
$this->move($this->motionX, $this->motionY, $this->motionZ);
$friction = 1 - $this->drag;
if($this->onGround){
$friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction;
}
$this->motionX *= $friction;
$this->motionY *= 1 - $this->drag;
$this->motionZ *= $friction;
if($this->onGround){
$this->motionY *= -0.5;
}
if($this->age > 6000){
$this->kill();
}
$this->updateMovement();
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
return $hasUpdate or !$this->onGround or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0;
}
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
if($source instanceof EntityDamageEvent){
$this->server->getPluginManager()->callEvent($source);
$damage = $source->getFinalDamage();
if($source->isCancelled()){
return;
}
}
$this->setLastDamageCause($source);
$this->setHealth($this->getHealth() - $damage);
}
public function heal($amount){
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
}
public function saveNBT(){
parent::saveNBT();
$this->namedtag->Item = new Compound("Item", [
"id" => new Short("id", $this->item->getID()),
"Damage" => new Short("Damage", $this->item->getDamage()),
@ -139,7 +172,7 @@ class DroppedItem extends Entity{
}
/**
* @return Item
* @return ItemItem
*/
public function getItem(){
return $this->item;
@ -203,11 +236,7 @@ class DroppedItem extends Entity{
$pk->item = $this->getItem();
$player->dataPacket($pk);
$pk = new SetEntityMotionPacket;
$pk->entities = [
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
];
$player->dataPacket($pk);
$player->addEntityMotion($this->getId(), $this->motionX, $this->motionY, $this->motionZ);
parent::spawnTo($player);
}

View File

@ -22,16 +22,18 @@
namespace pocketmine\entity;
use pocketmine\block\Block;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDeathEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\Timings;
use pocketmine\item\Item;
use pocketmine\item\Item as ItemItem;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\Short;
use pocketmine\network\protocol\EntityEventPacket;
use pocketmine\Server;
use pocketmine\utils\BlockIterator;
abstract class Living extends Entity implements Damageable{
@ -62,13 +64,29 @@ abstract class Living extends Entity implements Damageable{
public function hasLineOfSight(Entity $entity){
//TODO: head height
return $this->getLevel()->rayTraceBlocks(new Vector3($this->x, $this->y + $this->height, $this->z), new Vector3($entity->x, $entity->y + $entity->height, $entity->z)) === null;
return true;
//return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null;
}
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
if($this->attackTime > 0){
$lastCause = $this->getLastDamageCause();
if($lastCause instanceof EntityDamageEvent and $lastCause->getDamage() >= $damage){
if($source instanceof EntityDamageEvent){
$source->setCancelled();
$this->server->getPluginManager()->callEvent($source);
$damage = $source->getFinalDamage();
if($source->isCancelled()){
return;
}
}else{
return;
}
}
}elseif($source instanceof EntityDamageEvent){
$this->server->getPluginManager()->callEvent($source);
$damage = $source->getFinalDamage();
if($source->isCancelled()){
return;
}
}
@ -78,26 +96,41 @@ abstract class Living extends Entity implements Damageable{
$pk->event = 2; //Ouch!
Server::broadcastPacket($this->hasSpawned, $pk);
$this->setLastDamageCause($source);
$motion = new Vector3(0, 0, 0);
if($source instanceof EntityDamageByEntityEvent){
$e = $source->getDamager();
$deltaX = $this->x - $e->x;
$deltaZ = $this->z - $e->z;
$yaw = atan2($deltaX, $deltaZ);
$motion->x = sin($yaw) * 0.5;
$motion->z = cos($yaw) * 0.5;
$this->knockBack($e, $damage, sin($yaw), cos($yaw));
}
$this->setMotion($motion);
$this->setHealth($this->getHealth() - $damage);
$this->attackTime = 10; //0.5 seconds cooldown
}
public function heal($amount){
$this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount));
if($ev->isCancelled()){
return;
public function knockBack(Entity $attacker, $damage, $x, $z){
$f = sqrt($x ** 2 + $z ** 2);
$base = 0.4;
$motion = new Vector3($this->motionX, $this->motionY, $this->motionZ);
$motion->x /= 2;
$motion->y /= 2;
$motion->z /= 2;
$motion->x += ($x / $f) * $base;
$motion->y += $base;
$motion->z += ($z / $f) * $base;
if($motion->y > $base){
$motion->y = $base;
}
$this->setMotion($motion);
}
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
$this->setHealth($this->getHealth() + $amount);
}
@ -112,44 +145,100 @@ abstract class Living extends Entity implements Damageable{
}
}
public function entityBaseTick(){
public function entityBaseTick($tickDiff = 1){
Timings::$timerEntityBaseTick->startTiming();
parent::entityBaseTick();
parent::entityBaseTick($tickDiff);
if($this->dead !== true and $this->isInsideOfSolid()){
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1));
if(!$ev->isCancelled()){
$this->attack($ev->getFinalDamage(), $ev);
}
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1);
$this->attack($ev->getFinalDamage(), $ev);
}
if($this->dead !== true and $this->isInsideOfWater()){
--$this->airTicks;
$this->airTicks -= $tickDiff;
if($this->airTicks <= -20){
$this->airTicks = 0;
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2));
if(!$ev->isCancelled()){
$this->attack($ev->getFinalDamage(), $ev);
}
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2);
$this->attack($ev->getFinalDamage(), $ev);
}
$this->extinguish();
}else{
$this->airTicks = 300;
}
if($this->attackTime > 0){
--$this->attackTime;
$this->attackTime -= $tickDiff;
}
Timings::$timerEntityBaseTick->stopTiming();
}
/**
* @return Item[]
* @return ItemItem[]
*/
public function getDrops(){
return [];
}
/**
* @param int $maxDistance
* @param int $maxLength
* @param array $transparent
*
* @return Block[]
*/
public function getLineOfSight($maxDistance, $maxLength = 0, array $transparent = []){
if($maxDistance > 120){
$maxDistance = 120;
}
if(count($transparent) === 0){
$transparent = null;
}
$blocks = [];
$nextIndex = 0;
$itr = new BlockIterator($this->level, $this->getPosition(), $this->getDirectionVector(), $this->getEyeHeight(), $maxDistance);
while($itr->valid()){
$itr->next();
$block = $itr->current();
$blocks[$nextIndex++] = $block;
if($maxLength !== 0 and count($blocks) > $maxLength){
array_shift($blocks);
--$nextIndex;
}
$id = $block->getID();
if($transparent === null){
if($id !== 0){
break;
}
}else{
if(!isset($transparent[$id])){
break;
}
}
}
return $blocks;
}
/**
* @param int $maxDistance
* @param array $transparent
*
* @return Block
*/
public function getTargetBlock($maxDistance, array $transparent = []){
$block = array_shift($this->getLineOfSight($maxDistance, 1, $transparent));
if($block instanceof Block){
return $block;
}
return null;
}
}

View File

@ -22,10 +22,6 @@
namespace pocketmine\entity;
use pocketmine\nbt\tag\String;
class Ozelot extends Animal implements Tameable{
class Ocelot extends Animal implements Tameable{
protected function initEntity(){
$this->namedtag->id = new String("id", "Ozelot");
}
}

Some files were not shown because too many files have changed in this diff Show More