Compare commits

...

479 Commits

Author SHA1 Message Date
716c1f29b4 Fixed slabs again 2017-10-24 10:23:07 +01:00
0df3b00de4 Fixed incompatible protocol message showing an empty pair of brackets when protocol is null
this happens if an exception occurs while or before trying to read the protocol version
2017-10-23 19:44:19 +01:00
13e5718463 Using BlockFactory instead of Block 2017-10-23 18:50:37 +01:00
270e0c076c Fixed items not removed when put in the lava 2017-10-23 18:50:37 +01:00
3765511317 rename WritableBook->swapPage() to swapPages() 2017-10-23 17:55:01 +01:00
8daa8deae9 Added Living->lookAt() 2017-10-23 17:29:20 +01:00
e055ce9526 Use translation for flight kick message (#1489) 2017-10-23 13:18:57 +01:00
3ed8855894 fix drop chance of rotten flesh 2017-10-23 12:35:57 +01:00
f25255e46c fix zombie drops 2017-10-23 12:24:34 +01:00
7db8345424 Added rough support for reading entity saves with multiple save IDs (for PC 1.11 compatibility)
this will still always save using the legacy format to remain compatible with PC < 1.11.

TODO: entirely separate entity NBT format from entity implementation for proper multi-format compatibility
2017-10-22 10:16:24 +01:00
bc7ba3b3c1 Found field of ShowProfilePacket 2017-10-21 14:53:49 +01:00
1dd2203ee5 Fixed burning mobs not getting onfire data flag set when read from disk
they'd just flash red and take damage for no apparent reason
2017-10-21 12:36:30 +01:00
554096953b Abuse property visibility to micro optimize CompoundTags
this produced a little less than 10% performance improvement under xdebug, and while the real-time benefit is negligible, it's harmless to have.
2017-10-20 20:07:54 +01:00
55a1731da3 Remove redundant asserting function in Binary
If this was an inline assert, it would be harmless. Since it's in a function, it contributes to a 20% performance loss when using these functions on a large scale regardless of whether assertions are enabled or not.
Additionally, there's no need to assert that we have enough bytes since unpack() will raise warnings if there isn't, which will trigger exceptions, and for readByte(), an undefined offset notice will be raised, which will also trigger an exception.

TL;DR: This is simply wasting CPU time for no good reason.
2017-10-20 19:23:04 +01:00
ba3fe20227 Fixed missing variant bitmask for Leaves, close #1478 2017-10-20 18:37:46 +01:00
7b04049bb7 Throw exceptions when trying to add closed entities or tiles to levels 2017-10-20 18:22:28 +01:00
30211bee82 Fixed excessive idle CPU usage for chunk ticking
"excessive" = 5%, after changes = 1.6% - YMMV, but that's my machine.
2017-10-20 15:54:22 +01:00
e318dc12a5 missed target 2017-10-20 15:36:59 +01:00
967ce99b03 Made incompatible PHP version messages more useful 2017-10-20 15:35:43 +01:00
9bdda54aec Fixed PocketMine.php compatibility with < PHP7 2017-10-20 15:34:03 +01:00
18e4e5364f Fixed getBlock() performance degradation caused by 781de3efab, added Level->getBlockAt() to avoid creating vectors everywhere 2017-10-20 13:22:49 +01:00
98cfd0b398 fix entity rotation changes not getting broadcast until the entity moves 2017-10-20 10:13:19 +01:00
a245615531 fixed non-living entities lingering for a second after being kill()ed
only living entities should have death animation time
2017-10-19 20:51:50 +01:00
0a19a2611a Re-organise some Entity methods 2017-10-19 19:03:11 +01:00
50be26958a Added a helper function Entity->createBaseNBT() to cut down on boilerplate code 2017-10-19 17:36:51 +01:00
67c6fca0ed Relocate a couple of Entity API methods and add some documentation 2017-10-19 17:05:27 +01:00
d99e9513b0 Remove some redundant constructor overrides 2017-10-19 16:42:14 +01:00
5a353012de Clean up some unused imports 2017-10-19 16:39:34 +01:00
087badcb48 Remove deprecated effects methods from Entity 2017-10-19 16:35:44 +01:00
d9769360fe Remove redundant code from Entity->entityBaseTick()
this will never be called because onUpdate() checks this and returns.
2017-10-19 16:32:45 +01:00
9fb93985d6 Cleaned up Entity->spawnTo() 2017-10-19 16:13:09 +01:00
2b22d5d8cc Added EntityIds interface with constants 2017-10-19 15:43:55 +01:00
2db13bd114 added throwable eggs and refactor some projectile logic
close #1473
2017-10-19 14:12:50 +01:00
11cc20972f extended death animation time 2017-10-19 13:39:51 +01:00
4821e7386d fixed entities despawning too soon when killed 2017-10-19 13:39:10 +01:00
584810780a Moved projectile-related classes to their own namespace 2017-10-19 12:27:44 +01:00
55de75b914 Let blast resistance be computed from hardness for flowable blocks
fixes several flowable blocks apparently not having any resistance to explosions
2017-10-19 11:50:21 +01:00
2a1a17aa7a Refactored button code, fix placement rotation 2017-10-19 11:36:30 +01:00
90165cf99d Implemented farmland hydration
TODO: make crops take notice of this
2017-10-19 11:23:54 +01:00
a4ca3f1d1c Updated PocketMine-Language submodule 2017-10-18 21:08:39 +01:00
f783789e5a fixed escape code unescaping in language files, close #1474 2017-10-18 20:43:35 +01:00
43be64baed Register some more items
the item-blocks will allow their blocks to be placed, but they still won't work until the blocks themselves are added.
2017-10-18 19:52:19 +01:00
5c92c8a9d3 added red sandstone and red sandstone stairs 2017-10-18 19:42:12 +01:00
d2dc49cd9c Refactor Slab logic away from WoodenSlab, added StoneSlab2 and its double 2017-10-18 19:27:54 +01:00
f148c366f9 Use Block->getVariant() more, get rid of hardcoded bitmasks 2017-10-18 17:46:24 +01:00
91d84aaff4 Fixed a direct Block construction that PhpStorm somehow couldn't see 2017-10-18 17:03:55 +01:00
6b78ba8c25 replace some hardcoded values with Vec3 constants 2017-10-18 17:03:18 +01:00
b9de2e8b4b Use bit operations for rotations instead of hardcoded values 2017-10-18 16:47:37 +01:00
15764543b4 Use PillarRotationHelper for hay bales 2017-10-18 16:41:43 +01:00
2c34648c3d fixed second half of double chest items getting deleted, close #1477 2017-10-18 12:29:57 +01:00
3e3157cbe1 fix tick diff debug spam when entities are spawned 2017-10-17 17:38:43 +01:00
07abd61f73 Added a FIXME for Entity->move() 2017-10-17 17:14:45 +01:00
a456b7cfca Disable movement anti-cheat by default
shit's useless and an annoyance.
2017-10-17 16:45:18 +01:00
ece37d1e19 Added more methods to PlayerIllegalMoveEvent 2017-10-17 16:14:41 +01:00
cccaade00c make Player#unloadChunk() method protected 2017-10-17 14:22:57 +01:00
7f0a961526 "Creator" tag on signs may not exist 2017-10-17 13:35:31 +01:00
68ac4f538f Added ContainerTrait, reduce copy-pasted code in Tile 2017-10-16 20:01:17 +01:00
f14b7cbf78 Renamed BlockEventPacket fields 2017-10-16 19:55:42 +01:00
f4ff5d81ea Added missing parent calls for saveNBT() in Chest and Furnace 2017-10-16 18:56:48 +01:00
28a840d161 Make use of CompoundTag->hasTag() 2017-10-16 18:32:08 +01:00
292e462ea0 Remove nullable return types on CompoundTag getters
this doesn't make sense because there are default value parameters for this
2017-10-16 18:22:45 +01:00
c8379efbce Added expectedClass parameter to hasTag() to allow type-checking 2017-10-16 17:26:12 +01:00
1b5746fd97 Use NamedTag::class for default expectedClass in CompoundTag->getTag() 2017-10-16 17:22:38 +01:00
4a0ac01697 Fix PhpStorm derp
wtf?
2017-10-16 17:02:00 +01:00
9bcb41fb21 Refactor misleading parameter names in CompoundTag
these are NBT tag classes, not the NBT tag type. The tag type is an integer which describes the tag on disk.
2017-10-16 17:00:57 +01:00
20b86bdea8 Cleaned up tile NBT handling, use new CompoundTag API methods 2017-10-16 16:48:24 +01:00
0b1a9ba062 Added more typehints to Tile namespace 2017-10-16 16:14:44 +01:00
45b003ac2e Removed unnecessary return from Sign 2017-10-16 16:10:33 +01:00
769a50faa5 Refactor confusing parameter names for Item->onActivate()
next: refactor the function itself
2017-10-16 13:30:36 +01:00
af85659c63 Remove redundant property from Tile 2017-10-16 12:35:32 +01:00
95fa1824c8 Use a trait for nameable tiles instead of repeating code 2017-10-16 12:32:10 +01:00
251d5d7946 Fixed some hardcoded values in Tree 2017-10-16 12:30:46 +01:00
3b5eb45ff5 More usages of Item->isNull() 2017-10-16 12:29:39 +01:00
fd847f02ad Added BaseInventory->dropContents() 2017-10-16 12:18:06 +01:00
18d3a97466 Anvil result slot is not a real inventory slot
like the crafting grid result slot, this doesn't actually exist, it's
just somewhere you get the result item from.
2017-10-16 12:00:43 +01:00
04668d534d Oops, these fields need to be filled 2017-10-16 11:50:34 +01:00
092cc2750f Added entity unique ID for Entity containers
minecart with chest for example
2017-10-16 11:49:34 +01:00
68809d992b Added BaseInventory->removeAllViewers() 2017-10-16 11:15:03 +01:00
1641183674 added some typehints to Item 2017-10-16 10:29:44 +01:00
72531209bf Added some constants for frequently-accessed item NBT tags 2017-10-16 10:24:32 +01:00
8c6ab3e634 Some cleanup to item NBT handling 2017-10-16 10:15:41 +01:00
97e2d64592 "Fixed" shift-clicking recipe book, close #1401
this is not an optimal solution because you'll still only get 1 crafting
event when the user actually crafted a lot of items, so this isn't very
nice for plugins to work with. However, for gameplay purposes it works,
so it'll do for now.
2017-10-15 18:08:32 +01:00
a547e2cca8 Fixed sub-optimal code in WritableBook 2017-10-15 10:14:02 +01:00
cdebb62c35 added typecast for forceLanguage property read 2017-10-14 23:26:00 +01:00
2e73fd7f8c Add missing setValue() override to LongTag
why did this take two commits ;-;
2017-10-14 22:24:17 +01:00
51906daad0 Add typehints and PhpDoc to NBT API 2017-10-14 22:07:25 +01:00
ce67bc620a add Travis Test data directory to gitignore 2017-10-14 22:06:07 +01:00
bcefc3a54b Flag expectedType as nullable 2017-10-14 20:45:37 +01:00
f5378ab604 Fixed assertion failure when using getTag() without specifying an expected type 2017-10-14 20:45:32 +01:00
dab7cfde1c Added new API methods in CompoundTag to allow developers to stay sane (#1469)
Added getters and setters to CompoundTag with type safety
we need generics so badly here it hurts

This is fully backwards compatible, however the following API methods have been added to the `CompoundTag` class:

- getTag(string $name, string $expectedType = null) : ?NamedTag
- getListTag(string $name) : ?ListTag
- getCompoundTag(string $name) : ?CompoundTag
- setTag(NamedTag $tag) : void
- removeTag(string ...$names) : void
- hasTag(string $name) : bool

- getTagValue(string $name, string $expectedType, $default = null)
- getByte(string $name, ?int $default = null) : ?int
- getShort(string $name, ?int $default = null) : ?int
- getInt(string $name, ?int $default = null) : ?int
- getLong(string $name, ?int $default = null) : ?int
- getFloat(string $name, ?float $default = null) : ?float
- getDouble(string $name, ?float $default = null) : ?float
- getByteArray(string $name, ?string $default = null) : ?string
- getString(string $name, ?string $default = null) : ?string
- getIntArray(string $name, ?array $default = null) : ?array

- setTagValue(string $name, string $tagType, $value) : void
- setByte(string $name, int $value) : void
- setShort(string $name, int $value) : void
- setInt(string $name, int $value) : void
- setLong(string $name, int $value) : void
- setFloat(string $name, float $value) : void
- setDouble(string $name, float $value) : void
- setByteArray(string $name, string $value) : void
- setString(string $name, string $value) : void
- setIntArray(string $name, array $value) : void
2017-10-14 18:36:02 +01:00
6e1318b522 Push minimum requirement to PHP 7.2.0RC3
there are needed ZTS bugfixes included in RC3. I didn't move this earlier because Travis didn't have an RC3 build.
2017-10-14 14:26:21 +01:00
cd8006e242 Use constructor parameter for ListTags instead of setTagType() and removed some unnecessary type setting 2017-10-14 13:49:24 +01:00
f5abed95ec added missing type doc to ListTag 2017-10-14 12:48:38 +01:00
489b9fc29b Added missing getter override for LongTag
adds a return typehint
2017-10-14 11:34:41 +01:00
b524b841c5 Reduced duplicated code in AxisAlignedBB->calculateIntercept() 2017-10-14 11:01:00 +01:00
41f292d995 BlockUpdateEvent doesn't allow changing the target block anyway 2017-10-14 10:10:19 +01:00
fd8a562e02 Fixed collision bugs caused by not clearing pre-computed outdated AABBs for blocks
take fences as an example: say you have fence1 and fence2 next to each other, like this:
|==|
and they are joined together
then delete the fence on the right
the left fence will then look like this
|
but the server would still think its collision boxes were like this:
|=
so you wouldn't be able to shoot arrows through that space.

This commit clears pre-computed bounding boxes when a block is set using Level->setBlock() (in case the block was previously already set and has pre-calculated outdated AABB). However, because of weird blocks like fences, glass and walls, they must also be cleared on neighbour block update (since connection state isn't shown in the block data).
2017-10-14 10:07:17 +01:00
cc553a157d Clean up BlockEventPacket handling for Chests and fix wrong data for chest open 2017-10-13 20:07:33 +01:00
a6d1cc27ec Fix for explosions not removing tiles, close #1450 (#1463) 2017-10-13 13:57:50 +01:00
d8c90be5b8 Make on-ground checking less fussy 2017-10-13 13:19:20 +01:00
060426ff12 Add ability to unregister a command completely, close #1229 (#1464) 2017-10-13 11:55:36 +01:00
eeea4fa06a Added some new blocks 2017-10-13 11:51:38 +01:00
401e33dd85 fix anvil bounding box 2017-10-13 11:18:19 +01:00
2893aac3ac ... 2017-10-13 11:06:10 +01:00
c5c74c1898 fixing glass & bars collision detection
so much duplicated code, it would be nice if Fence could inherit from Thin, but that causes too many issues with block connections.
2017-10-13 11:04:51 +01:00
423bea4b57 Fixed a couple of blocks incorrectly descending from Solid 2017-10-13 10:37:48 +01:00
e3567faa94 Anvils aren't non-solid, they are transparent
solid and transparent are not mutually exclusive!
2017-10-13 10:22:22 +01:00
4b5040dcc7 Blocks extending Thin ARE solid 2017-10-13 09:52:08 +01:00
21c79b0645 Use up to 2 AABBs for fence collision checks instead of 5
overlapping cuboids do fine
2017-10-13 09:40:29 +01:00
7b5df10b6a Reset position properly when reverting movement 2017-10-12 20:33:26 +01:00
c4fe9ad32d Remove pointless API method from PlayerMoveEvent 2017-10-12 19:59:32 +01:00
60b62a4890 fixed wall collision detection
walls have to be weird...
2017-10-12 19:36:06 +01:00
061a9444cc implemented multi AABB collision checks for fences and walls
fixes anti-cheat getting triggered when falling down between a square of fences
fixes not being able to shoot arrows between a square of fences
2017-10-12 18:33:26 +01:00
3eb73ab468 Abstracted Fence code away from wooden fences 2017-10-12 17:04:49 +01:00
15d6fd86e2 Added basic support for blocks with multiple AABBs, fixed stairs (#1303) 2017-10-12 16:29:24 +01:00
0c092a7ceb reduced size of arrow bounding box
as per MCPE addon data
2017-10-12 16:21:23 +01:00
b9501ef415 Remove unnecessary duplicated ray-trace code from Block
this isn't actually used anywhere, but "backwards compatibility"
2017-10-12 13:40:12 +01:00
5afe4fdb5b Use Vector3 constants instead of hardcoded integers 2017-10-12 13:32:17 +01:00
cc7ed7a28f Added some documentation to AxisAlignedBB 2017-10-12 12:22:13 +01:00
7e9b89e48a Make Entity->checkObstruction() less confusing 2017-10-12 11:59:02 +01:00
63fccd4682 farmland and grass path should die when a solid block is above them 2017-10-12 11:11:33 +01:00
35e7aca88f refactor some more stupid variable names 2017-10-12 10:45:22 +01:00
9413f155ce implement updating properly for multi-face vines 2017-10-12 10:21:08 +01:00
6569fdbe04 Refactor some variable names in Vine 2017-10-11 20:12:12 +01:00
d8b1757ebc added some nullable and void typehints to Block API 2017-10-11 18:45:40 +01:00
8f0ee84277 Cleaned up Ladder AABB calculation code 2017-10-11 18:25:16 +01:00
b7a9e10d49 Some cleanup to how tiles are created 2017-10-11 18:08:08 +01:00
be2d134994 Added API to allow flagging an entity not to be saved to disk when its chunk is saved (#1452) 2017-10-11 16:09:08 +01:00
7b1bfc0520 fix some typos in pocketmine.yml 2017-10-11 13:42:32 +01:00
59d9d6a7df Fixed logic for low memory chunk radius override 2017-10-11 13:40:13 +01:00
8d095dff6c Given some MemoryManager fields less confusing names 2017-10-11 13:27:33 +01:00
4981931c4a Remove reliability hacks for RakLib
bug was fixed in 691a7be66b
2017-10-11 10:59:27 +01:00
5dafabbec2 Updated RakLib submodule 2017-10-11 10:59:27 +01:00
2a5d954c67 fixed yaw/headyaw field order
I wish they'd stop changing this shit... this is the third or fourth time now?
2017-10-10 22:45:30 +01:00
287f08cbd1 Changed confusing MovePlayerPacket field name to be consistent with other packets 2017-10-10 21:56:17 +01:00
76469e1d5f Remove useless properties from pocketmine.yml
these have been here for years but have never been of any use, they just confuse new users.
2017-10-10 00:01:05 +01:00
c4c83e23ca Revert RakLib to 1830bb7
disconnect & transfer issues... no idea why
2017-10-09 20:30:44 +01:00
eccc7bf7b3 Moved EntityLink to its own type 2017-10-09 19:15:53 +01:00
78ca2f2e58 fix heads rotating 45 degrees when placed facing north 2017-10-09 18:12:56 +01:00
cef9c4621c added som PhpDoc to Tile 2017-10-09 17:27:34 +01:00
151681bd80 Remove some dead properties from Tile 2017-10-09 17:25:10 +01:00
327907988b Fixed a typo in Sign->setText() docs 2017-10-09 16:56:25 +01:00
97dbf61236 Remove some no-longer-needed item classes 2017-10-09 12:31:57 +01:00
2be8b576ef Changed constructor of ItemBlock to allow handling blocks with different item IDs, added more doors 2017-10-09 11:58:58 +01:00
6dbdefafdd Add the long-awaited Enchantment::registerEnchantment() API method
api3/blocks users: I am sorry I kept you waiting so long
2017-10-09 11:40:53 +01:00
9598b8cee4 Use API methods instead of directly setting properties 2017-10-09 11:38:52 +01:00
246c6daef6 how irritating 2017-10-09 11:30:11 +01:00
2601e35990 Cleaned up and added API for entity air supply, fixed oxygen being used in creative/spectator
this commit also includes respiration checks because it's cherry-picked
from api3/blocks, but respiration won't work until it's registered.
2017-10-09 11:28:40 +01:00
bdfd9c95dd Minor cleanup to attack handler 2017-10-09 11:02:00 +01:00
cd44551d64 Cleaned up checks for handling inventory transactions 2017-10-09 10:57:28 +01:00
cebb4b35f6 Fixed beds not getting deleted properly in survival
the anti-instabreak kicked in twice... damned anti-cheat... luckily the player is not needed for this part
2017-10-09 10:49:30 +01:00
7267f1a520 Fixed some usages of Item constants for Blocks
only cosmetic change
2017-10-09 10:37:19 +01:00
66a3354b31 Fixed not respawning adjacent tiles correctly when cancelling block break events 2017-10-09 10:30:48 +01:00
ac7384a2b4 Re-organise some Player methods
- group spawn-related methods
- group achievement-related methods
- move isSleeping()
- group name-related methods
- move Player->sendAllInventories()
- move Player->jump()
2017-10-09 10:25:33 +01:00
748beaaaa7 Changed a couple of very misleading default values
why on earth did I do this
2017-10-09 09:55:18 +01:00
58788b4bc7 Removed some unnecessary stuff PhpStorm complained about 2017-10-09 09:46:21 +01:00
ae76ac82c8 Removed unnecessary delegate packet handlers
let's keep all the TODOs in one place
2017-10-09 09:44:22 +01:00
e4000f8f03 Reorganise some packet methods in Player 2017-10-09 09:35:31 +01:00
ebcce43131 Don't hold player references for hiddenPlayers
they aren't needed, and this is just one more thing that could go wrong in Player->close() that could lead to leaks.
2017-10-09 09:20:44 +01:00
119913da30 Modified misleading comment (#1455)
The plugin isn't supposed to extend PluginTask, the task is
2017-10-09 07:52:40 +01:00
1a88f59b23 Moved some stuff from join to login
this is how it should be
2017-10-08 19:38:03 +01:00
fdfe70b9f2 Removed entity metadata setting from LoginPacket handler
why the f was this here
2017-10-08 19:10:49 +01:00
3bda1473e7 Removed outdated documentation for Player->getClientId() 2017-10-08 18:47:13 +01:00
29cd071108 Added some documentation on player UUIDs 2017-10-08 18:40:27 +01:00
1810088acf Use Player->isCreative() 2017-10-08 18:17:12 +01:00
51e4a62e7b Use setUsingItem() instead of directly setting data flags 2017-10-08 18:03:19 +01:00
aa91183504 Added Durable class, fixed some tools not breaking correctly, removed some boilerplate code 2017-10-08 15:54:31 +01:00
ae5aa31e7b Add Item->setNamedTagEntry() and Item->removeNamedTagEntry() 2017-10-08 15:06:30 +01:00
7239dbbb1a Merge remote-tracking branch 'origin/pr/1453' 2017-10-08 14:20:02 +01:00
3738ab1f8a Fixed villager professions being useless 2017-10-08 14:14:42 +01:00
8fafef2f7f Added tagType parameter to ListTag constructor, remove some boilerplate code 2017-10-08 13:28:01 +01:00
5b9515b20f Peaceful difficulty allows PvP 2017-10-08 13:57:25 +02:00
69e29236aa Remove some redundant code for checking existence of creative items
getCreativeItemIndex() does basically the same thing anyway
2017-10-08 12:50:53 +01:00
e8453b7872 Item->getNamedTag() now always returns a CompoundTag object, removed lots of boilerplate code
This change resulted from many complaints and ugly boilerplate code because getNamedTag() is only ever used when you want to read from the tag or modify it. If you have code that depends on this returning null, you should use hasCompoundTag() instead.
2017-10-08 12:41:57 +01:00
00bf190e54 Make Item->getNamedTag() a bit less ugly 2017-10-08 12:17:18 +01:00
81dee2f9fc Adding writable and written books. (#1397)
* Adding writable and written books.
* Added a PlayerEditBookEvent.
* Changed BookEditPacket field names.
2017-10-08 11:49:57 +01:00
f6875705a1 Found fields of PhotoTransferPacket
now if we could only get portfolios...
2017-10-08 11:25:27 +01:00
d294d5a91b Clarified location table doc for RegionLoader 2017-10-06 09:40:46 +01:00
a7e9aa4bc1 Fixed falling sand replacing wrong blocks when moved slightly by currents 2017-10-05 17:38:32 -04:00
628ff9449e Fixed respawn fall damage when dying while falling from causes other than fall damage
tl;dr: fall distance didn't get reset
2017-10-05 16:47:50 -04:00
7f5fe137d1 Added some type docs to RegionLoader 2017-10-05 18:47:32 +01:00
18448cbcb8 Fixed several bugs with statistics updating and resetting
- fixed ridiculous network stats when title ticker or console colours are disabled (shoghicp, what fit of madness led you to think this was a good idea)
- fixed network stats reporting kb/16ticks instead of kb/s
- fixed TPS reporting getting reset after 16 ticks instead of 20
- title ticker and MOTD is now updated every 20 ticks instead of 16
2017-10-05 16:48:50 +01:00
b0104099fe Add a couple of comments to pocketmine.yml to clarify settings usage 2017-10-04 14:44:52 +01:00
68195c64ce Remove dead COMPRESSION_LEVEL property from Level 2017-10-04 14:26:04 +01:00
27aa51bac4 Added some type docs to Level 2017-10-04 14:25:06 +01:00
eac1d76e8b Fixed Level->stopTime not being set 2017-10-04 14:08:23 +01:00
a8c6e14d02 Chunk cache is now non-optional, close #1448 2017-10-04 13:50:32 +01:00
bf68a6a9fc Fixed canUseChunkCache() logic (#1446)
Fix setting disable chunk cache on low memory being useless, fix chunk cache not working if low memory cache clear is enabled
2017-10-03 20:27:53 +01:00
4dfd171af0 Add flint-steel light sound, close #1434 2017-10-03 19:39:01 +01:00
fc9c264e77 Resend blocks around targeted blocks when interactions & block-break are cancelled, fixes #906
this solution is dumber but more effective (also solves the beds & doors placement problem)
2017-10-03 19:28:01 +01:00
04ba41c58c Remove redundant properties from recipes.json
- we don't use the UUIDs, and they change every time, this just pollutes the diffs and makes my contribs ridiculous
- we don't need the height/width of shaped recipes because the generated shape tells us what it is
2017-10-03 17:30:26 +01:00
736cc927ff Enable chunk caching by default
the footprint of compressed chunk batches is so small now that it doesn't make sense to disable it out of the box. The performance gains from caching chunks are more than worth it.
As of 1.2, the average footprint of these caches is usually ~2% or less of the size of the actual chunk itself. Moving around a lot will frequently cause the same chunks to get sent several times as it passes in and out of your render distance, and the chunk isn't even changing in that time, so the chunk is getting needlessly re-serialized over and over again. So even if your world is not static (for example a creative server) chunk caching will still offer benefits, and the memory expense is so small it's a no-brainer.
2017-10-03 13:16:30 +01:00
4be7885ee4 Remove redundant assignment in Level constructor 2017-10-03 12:57:30 +01:00
7dc5dc3a9f Restrict item meta values to max signed short value, closes #1101 2017-10-03 12:35:08 +01:00
f7ee78233b Item IDs should always be unsigned, treat them with appropriate measures (fixes #1376) 2017-10-03 12:28:50 +01:00
88807e8b22 Fixed Binary::unsignShort() being non-static 2017-10-03 12:21:09 +01:00
5a6812357b imports 2017-10-03 11:34:41 +01:00
ca401ec3f5 Force-close the crafting window only when doing crafting transactions
otherwise the client will crash when using right-click on the recipe book
2017-10-03 11:33:09 +01:00
9bbebaa071 Force-close the inventory window when crafting fails to avoid desync issues
mojang, why does this have to be hard work
2017-10-03 11:04:21 +01:00
76117e7fa0 Get XUID from LoginPacket after authentication, add Player->getXuid() 2017-10-02 18:51:51 +01:00
088a44ea3a Fixed bug reading pubkey from LoginPacket
this isn't part of extraData
2017-10-02 18:05:50 +01:00
b54f256fea Added a hack to cut down on excess skin geometry bloat
there are further ways this can be debloated, but non-pretty-printing it cuts the size down by ~70-80%.
2017-10-01 16:50:16 +01:00
c09d782503 Fix #145, take 2 (slab placement in half gaps doesn't work) (#1411) 2017-10-01 16:19:59 +01:00
b3b3ee7c56 Use transparent skin on FloatingTextParticle 2017-10-01 14:10:47 +01:00
ab5bbaa7bd Remove redundant property from Player 2017-10-01 12:19:11 +01:00
afa37bd2aa check range of valid compression values
zero is not allowed because it's pointless, just raise your compression threshold if you want zero compression.

Chunks will always be compressed regardless of threshold because they are huge. It doesn't make sense to allow uncompressed chunks when even compression level 1 will reduce their size 50x. The point of the last two (reverted) commits was to prevent compression level zero being used on chunks. Probably obvious that I was up late and not thinking very clearly.

Revert "Reduced chunk compression level to 7"

This reverts commit 49ac2555ce.

Revert "Always use best compression for chunks"

This reverts commit 42dd9d6abd.
2017-10-01 11:06:14 +01:00
49ac2555ce Reduced chunk compression level to 7
According to benchmarks 8 and 9 are simply orders of magnitude slower while not saving enough bytes to make it worth the performance loss. 7 is a good balance.
2017-10-01 09:20:14 +01:00
edd0189d59 Some improvements to issue template 2017-09-30 21:19:38 +01:00
b76b9d53fe Fixed drops for DeadBush 2017-09-30 21:04:39 +01:00
42dd9d6abd Always use best compression for chunks 2017-09-30 20:30:24 +01:00
9cd7f39c03 Fixed typo on ProjectileItem class (#1431) 2017-09-30 16:17:22 +01:00
f6e30d4225 s/online-mode/xbox-auth/
lots of servers are currently running in insecure mode without realizing because of old Genisys shit configs?!
2017-09-30 12:19:24 +01:00
27798c69ee fix collision detection not detecting fence & fence-gate, fixed nether-brick fence gate AABB, close #1299 2017-09-29 15:27:14 +01:00
a33be643c4 Fixed falling blocks not falling when placed above fire, close #1425
yes, hardcoding this is not a nice solution - PC also does this, want to fight?
2017-09-29 14:53:23 +01:00
a06ff3d96b Revert "Fixed falling blocks glitching when spawned"
This reverts commit 827ee5d4f9.

can't ever seem to get falling blocks right... should I blame mojang?
2017-09-29 14:22:03 +01:00
e6cecabf3f New skin API, add support for custom capes & custom geometry (#1416)
* Added support for changing skins ingame, custom capes & geometry
* Use PlayerSkinPacket for setting Human skin instead of PlayerList hack
2017-09-29 14:09:00 +01:00
c273a46537 Ditch crafting transaction if we get normal inventory action with incomplete crafting transaction 2017-09-28 20:07:07 +01:00
c448f4a3b5 Added handling for reflected ShapedRecipe crafting, close #1415 2017-09-28 18:45:22 +01:00
86b76bfcab Fixed trying to get pubkey that doesn't exist in VerifyLoginTask
bug was exposed by previous commit
2017-09-28 18:14:53 +01:00
7ba193dc2e Set ErrorException handler on AsyncWorkers 2017-09-28 18:01:31 +01:00
f565791e41 World loading: Actually use the data in each item instead of getProperty() 2017-09-28 16:38:10 +01:00
bc0434913e Fixed crash when a numeric world seed is set in pocketmine.yml 2017-09-28 16:35:19 +01:00
9bc8d8db79 Revert "Add buffering for non-immediate priority packets to reduce compression overhead"
This reverts commit 2162675b64.

This broke Human skins... it seems MCPE doesn't like you adding and
removing a player from the list in the same batch.
2017-09-28 14:29:17 +01:00
d0bf0ff083 Imports cleanup 2017-09-28 10:51:05 +01:00
7dc1fc54b1 Oops, didn't mean to commit this 2017-09-27 20:34:37 +01:00
bae42dc0d9 Fixed incorrect field names in PlayerSkinPacket 2017-09-27 17:55:04 +01:00
ab809f8a2b Updated RakLib submodule 2017-09-27 15:53:43 +01:00
2162675b64 Add buffering for non-immediate priority packets to reduce compression overhead 2017-09-27 14:06:42 +01:00
8f63117dac Use try...finally in Player->sendDataPacket() so we don't forget to stop timings 2017-09-27 13:52:25 +01:00
1c9b4f3e21 Fixed ItemBlocks retaining Level references after being placed, close #1395 2017-09-27 12:04:56 +01:00
48d2d7e422 Remove unused import from FoodSource 2017-09-27 12:01:55 +01:00
52bd042bde BaseInventory: Don't keep calling getSize() over and over and over again 2017-09-27 11:24:21 +01:00
4b63a22f8c More use of Item->isNull() 2017-09-27 11:05:40 +01:00
c47f1f572c Added API method Item->pop() 2017-09-27 10:56:04 +01:00
7a77bb0402 Login verification: guilty until proven innocent
assume it's invalid until we've verified everything
2017-09-27 10:29:01 +01:00
90cb018de2 Re-organise some Block code 2017-09-26 19:39:05 +01:00
992c4ce6a0 Added API method Block->getVariant() 2017-09-26 19:35:04 +01:00
78af87a572 ConcretePowder: add tool type 2017-09-26 19:00:53 +01:00
c79a5509f6 Implemented concrete powder
this is a little buggy with water updating due to a hack for liquids to fix a CPU leak (210bdc2436), but everything works fine when a block nearby gets updated.
2017-09-26 18:56:43 +01:00
827ee5d4f9 Fixed falling blocks glitching when spawned
this now (finally) works flawlessly
2017-09-26 18:33:34 +01:00
f5b0cbb337 Generated some TODOs for BlockFactory & ItemFactory 2017-09-26 16:15:35 +01:00
18777a9041 Remove useless EntityEventPacket
vanilla doesn't send this, and it doesn't do anything if we _do_ send it.
2017-09-26 12:50:36 +01:00
13d50aff62 don't break bows, stupid 2017-09-26 12:20:40 +01:00
5b191327bc Fixed players' arms staying stuck up after eating something 2017-09-26 12:14:10 +01:00
8811188e71 Split FoodSource up into two interfaces 2017-09-26 11:48:47 +01:00
38fad4b963 Implement difficulty per-world (#878)
* Moved Server::getDifficultyFromString() to Level
* Added ability to set difficulty in worlds section of pocketmine.yml for generation
2017-09-26 11:16:51 +01:00
e64076ec81 Disconnect 1.1 clients properly (HACK!) 2017-09-26 10:01:32 +01:00
ccbdb77618 Cleaned up LoginPacket handling, don't nuke the buffer 2017-09-26 09:49:35 +01:00
91c6086ae1 Updated PocketMine-Language submodule 2017-09-26 09:35:43 +01:00
85ec7d9732 Change default MOTD
"Minecraft: PE Server" is no longer accurate, "Minecraft: Bedrock
Edition Server" is too wordy, and "Minecraft: BE Server" just sounds
weird.

and I'm not calling it simply a "Minecraft Server"
2017-09-25 23:43:09 +01:00
10f597cd64 Stop hardcoding "PocketMine-MP" everywhere 2017-09-25 18:17:35 +01:00
6e5759b1d1 Made incompatible client disconnect messages more informative 2017-09-25 14:30:11 +01:00
03d3e595d6 Implement JWT signature verification and Xbox Live checks, close #315
This can be enabled or disabled using the "online-mode" directive in
server.properties.

NOTE: For safety reasons it is enabled by default, since many naive server owners currently believe that authentication is not needed because "the client is forced to sign-in".
Newsflash for readers: the forced authentication is easily bypassed using a LAN proxy.

Un-authenticated LAN connections will still work fine if the online mode is disabled.

Added the following API methods:
- Server->getOnlineMode() : bool
- Server->requiresAuthentication() : bool
- Player->isAuthenticated() : bool

JWT verification is rather expensive, so it is done in an AsyncTask. Make sure you don't hog your worker threads.
2017-09-25 12:30:58 +01:00
8ca59d12e9 Updated PocketMine-Language submodule 2017-09-25 11:36:39 +01:00
89e4defa29 use null coalesce in Server->getLevel() 2017-09-25 09:51:21 +01:00
f5534a9ab0 Server: add some typehints 2017-09-25 09:49:19 +01:00
28bce8d48c Fixed plugins causing crashes by using Level->unload() and add a warning
yes, we don't want you to use this, but it still shouldn't crash if it can be prevented...
2017-09-25 09:46:19 +01:00
3c02a6a8ed Fixed eating sounds 2017-09-24 21:18:08 +01:00
6b0ac8adb8 Don't overwrite the input map with reindexed stuff
we might need this again?
2017-09-24 19:17:00 +01:00
38ec5da260 Refactored API compatibility checking code into its own method (#1394)
Refactored API compatibility checking code into its own method so plugins can use it
this change was inspired by https://github.com/poggit/devirion/blob/master/src/poggit/virion/devirion/DEVirion.php#L140-L172
2017-09-24 15:00:08 +01:00
240cc3043a Rewritten crafting, fixed #45 2017-09-24 14:14:24 +01:00
043ae487de Fixed some inconsistent uses of new ShortTag vs setValue() in Furnace 2017-09-24 10:34:25 +01:00
f12701e582 Fixed possible undefined NBT in Furnace, close #1398 2017-09-24 10:29:36 +01:00
6e961ae897 Addition of Coarse Dirt (#1396) 2017-09-23 22:25:03 +01:00
e1d10f595a AdventureSettingsPacket: removed leftover TODO comment 2017-09-23 16:51:58 +01:00
178dd1b981 Fixed block picking, added PlayerBlockPickEvent 2017-09-23 14:42:28 +01:00
826ec90856 Revert "Workaround for some plugins crashing clients during PlayerLoginEvent"
This reverts commit 087a994393.
2017-09-23 13:23:19 +01:00
0523f26613 Send forced movement when getting bad movements after teleport, fixes AlwaysSpawn-type plugins
it's mostly harmless to send it here anyway
2017-09-23 12:49:46 +01:00
5190d9c1e2 Fixed possible issue with JWT decoding
this is url-encoded, these characters should be replaced before base64_decode()ing. Not sure how this didn't get noticed before now.
2017-09-22 19:52:08 +01:00
c8fd0eaf8b Removed autogenerated stub TODO from BoneBlock 2017-09-21 19:50:03 +01:00
53ef9b653a Added some getters to FloatingTextParticle 2017-09-21 19:10:30 +01:00
030cc4afb0 FloatingTextParticle: import cleanup & typehints 2017-09-21 19:09:33 +01:00
9bd7f771d3 "Fixed" FloatingTextParticle yet again
- nametag visibility flags don't work properly, only players show them all the time
- invisibility overrides nametag visibility
- scale 0 triggers asserts on debug builds

..... how hard is it to NOT break these simple things each update Mojang?

closes #1205
2017-09-21 19:04:45 +01:00
10f6a0eef0 FloatingTextParticle: fixed incorrect parameter type doc 2017-09-21 18:31:12 +01:00
d0a96f35da ./ hack is back (/help is client-side >_<) 2017-09-21 17:51:39 +01:00
65e908a403 Move Travis Test server files into a separate directory
this is for convenience locally running Travis Test so my existing data doesn't interfere
2017-09-21 17:16:27 +01:00
d7091f4460 Fixed not being able to disable stats reporting using command line options 2017-09-21 17:14:44 +01:00
c6670b2e74 Fixed Nether Wart's name 2017-09-21 16:56:41 +01:00
194278d986 Updated TesterPlugin submodule 2017-09-21 16:56:27 +01:00
0e2e9aab2e Fixed crash when block classes override the constructor but don't specify a fallback name 2017-09-21 16:43:33 +01:00
1b5fed983b Revert "Fixed slab placement, close #145", reopen #145, close #1314
This reverts commit f2ff0198cc.
2017-09-21 14:41:18 +01:00
5aba87b250 Added brown and red mushroom blocks 2017-09-21 14:07:51 +01:00
f01ce8e994 null and void typehints 2017-09-21 12:54:04 +01:00
d89b8cf12e Clean up SlotChangeAction inventory handling 2017-09-21 12:44:03 +01:00
6aa9b081e9 Cleanup unused imports 2017-09-21 12:26:41 +01:00
dbed80386a Removed redundant interface 2017-09-21 12:22:47 +01:00
cefad0444c Merge branch 'master' into mcpe-1.2 2017-09-21 10:32:35 +01:00
ee052f91d4 Fixed some air items with count 1 instead of 0 2017-09-21 10:30:14 +01:00
ef6250967f Use Item->isNull() more 2017-09-21 10:29:29 +01:00
61cfdac6a1 Fixed a mistake in entity attack handler 2017-09-21 10:18:52 +01:00
fd7fb10223 Return null on unmatched inventory action and log details 2017-09-20 18:38:14 +01:00
6897cb4774 Moved inventory action magic slot constants where they belong 2017-09-20 18:27:29 +01:00
8e7ad532f1 Updated RakLib submodule 2017-09-20 18:16:41 +01:00
9e8366725a Bump for 1.2.0.81 2017-09-20 17:30:27 +01:00
b14ecc18c4 Remove unused imports 2017-09-20 12:24:44 +01:00
55720d9f0a Added InventoryAction->onPreExecute(), fixed PlayerDropItemEvent deleting items 2017-09-20 12:19:42 +01:00
0262465a26 Fixed dupe cake glitch
this is what happens when you try to be clever when not properly awake
2017-09-20 11:19:15 +01:00
7996a7b08c Testing handling multiple result items for ShapedRecipes
this doesn't work yet, I wanted to see how glitchy it is with cakes. The answer is: very glitchy.
2017-09-20 11:14:09 +01:00
4a1fc1bdf7 don't try to send contents during inventory construction 2017-09-20 10:18:24 +01:00
85b2b2ae2e Don't send tile inventory slots during the constructor
This is completely pointless and a waste of time.
2017-09-20 10:15:28 +01:00
38e11aae5e Some cleanup to how EntityInventoryChangeEvents are handled 2017-09-20 10:13:05 +01:00
f0755d1659 Fixed handling of recipes that require a crafting table 2017-09-20 09:43:49 +01:00
fd33a65e3b Small cleanup of recipe UUID handling (furnace recipes don't need UUIDs) 2017-09-20 09:34:00 +01:00
7baadf9dad Throw updated pthreads at Travis 2017-09-19 20:49:41 +01:00
ca23864e4c CraftingManager: use null coalesce for matching furnace recipes 2017-09-19 20:03:21 +01:00
8728547a11 Remove unused imports 2017-09-19 19:58:53 +01:00
90fb3c5e12 Moved getNetworkType() to ContainerInventory since it's not used anywhere else 2017-09-19 19:57:22 +01:00
1fb6d12a6b Add getInventory() to Container interface where it's actually useful 2017-09-19 19:26:41 +01:00
1323d89139 Remove redundant duplicated code for sendContents() and sendSlot() 2017-09-19 19:07:12 +01:00
136ab1dba1 Inventory->getItem(): Removed useless clones
this already returns a copy of the item anyway... wtf?
2017-09-19 18:49:08 +01:00
8cae20e818 Removed hotbar slot linking (works like PC now) 2017-09-19 18:36:57 +01:00
ff2b3bfa2a SimpleCommandMap: remove some dupe and arrange commands alphabetically 2017-09-18 18:43:06 +01:00
361b262d3a Merge branch 'master' into mcpe-1.2 2017-09-18 10:29:38 +01:00
1fd7f441b4 Travis: use older version of pthreads
master is broken - https://github.com/krakjoe/pthreads/issues/757
2017-09-18 10:20:15 +01:00
3f56d6ddc8 RakLibInterface: removed useless needACK condition 2017-09-18 09:42:25 +01:00
1e4cbb0dd9 RakLibInterface: move array initialization to default value
doesn't make sense to do this in the ctor when all the others are normal
2017-09-18 09:34:00 +01:00
a99eee9def Removed redundant assignment 2017-09-17 20:01:11 +01:00
bdee746e46 Automatically enable ANSI colours on Windows versions that support it
Note that stream_isatty() and sapi_windows_vt100_support() are ONLY defined on PHP 7.2, and the latter is only available on Windows.
2017-09-17 19:57:20 +01:00
642c7733cd Cleaned up ShapedRecipe handling, ShapedRecipe API changes
use shapes from json instead of just generating maps
fix a ton of bugs
2017-09-17 11:45:16 +01:00
c8199e14ad Removed redundant duplicate method call 2017-09-16 23:09:14 +01:00
0f37bc35ba Always evacuate the crafting grid on close, no matter whether it's big or not
otherwise items will get deleted and people will cry
2017-09-16 21:58:10 +01:00
8dc3d019f6 Return handled on fake window close 2017-09-16 21:55:25 +01:00
bd64172750 Added API method Item->equalsExact() and removed some boilerplate code 2017-09-15 16:48:46 +01:00
0e51820dfb Merge remote-tracking branch 'origin/master' into mcpe-1.2 2017-09-15 15:54:30 +01:00
30d2318bb7 Merge pull request #1383 from pmmp/quoted-command-args
Quoted command args & allow playernames with spaces
2017-09-15 14:04:48 +01:00
63634d7e7d Added compaction and sorting for repeated slot changes in a single transaction
Now items should be able to move around the crafting grid correctly.
2017-09-15 13:32:17 +01:00
d941bf8e74 Add vanilla-style crafting grid item evacuation server-side when closing the window in case something goes wrong 2017-09-15 13:22:53 +01:00
8c9d9626ab Merge branch 'new-pack-codes' 2017-09-14 19:53:07 +01:00
6b34c47c96 Merge branch 'master' into mcpe-1.2 2017-09-14 18:16:45 +01:00
77241e14ce Bumped to ALPHA8 to account for AsyncTask API changes 2017-09-14 17:49:12 +01:00
15b08c1417 Added capability to dump AsyncWorkers' memory (#1379)
This now actually works with PHP 7.2 + latest pthreads, before it was too unstable.
2017-09-14 16:45:48 +01:00
4d1daecd91 oops! 2017-09-14 11:01:47 +01:00
53e5db5142 Updated PreProcessor submodule 2017-09-14 10:58:46 +01:00
ad72fe6232 Make use of awesome new pack() codes for floats 2017-09-14 10:41:53 +01:00
8b33f711d0 Allow spaces in player names 2017-09-14 10:15:35 +01:00
319735db3a Add support for quoting command arguments
Un-escape quotes in inputted strings
2017-09-14 10:15:30 +01:00
c283d87494 Some minor cleanup of PocketMine.php 2017-09-13 19:14:31 +01:00
be27e03126 Some minor AutoUpdater cleanup, stop hardcoding everything 2017-09-13 18:51:06 +01:00
c1c290cd39 Beware matching items that aren't actually correct
This would only ever happen if we received the actions in the wrong order, but that wouldn't surprise me.
2017-09-13 11:37:10 +01:00
5267c571e9 add handling for -100 fake source type (evacuate crafting table contents) 2017-09-13 11:15:31 +01:00
0fac3b9a9d Added encode for InventoryTransactionPacket and refactor some stuff 2017-09-13 11:14:04 +01:00
23a38400e2 Added CraftingGrid and BigCraftingGrid, WIP stuff for crafting
moving whole stacks in & out of the crafting grid works now, splitting stacks is fucked up because the transaction system can't handle the same slot changing multiple times in one transaction
2017-09-12 19:34:06 +01:00
297172d111 Send creative inventory for all gamemodes, fixed recipe book 2017-09-12 14:40:16 +01:00
825d4f9702 Location cleanup (#1380)
There's no sense rewriting code that the parent constructor already implements.
2017-09-12 12:18:35 +01:00
1d31958ce6 Updated preprocessor submodule 2017-09-12 09:12:38 +01:00
130a60f2b2 Fixed ItemFactory::isRegistered() returns false for blocks 2017-09-11 18:23:26 +01:00
07268e4b37 Added API methods to determine if a block or item is already registered 2017-09-11 16:22:55 +01:00
441efc4ae2 Merge branch 'master' into mcpe-1.2 2017-09-11 14:40:25 +01:00
88bd7713c5 Fix preprocessor 2017-09-11 09:42:31 +01:00
aaa3b6e59a Added explicit AsyncTask->storeLocal(), removed AsyncTask->__construct() object storage (#1322)
Far too often I see people using IDEs which generate the constructors for them and then accidentally unintentionally store things in the object store. This parent constructor behaviour is unexpected. If a developer wants to store something, they should now do so explicitly by calling storeLocal().
2017-09-10 20:31:28 +01:00
25adac8859 Added support for Composer (#323) 2017-09-10 19:23:34 +01:00
8d0b881762 fixed command arg types 2017-09-10 13:56:34 +01:00
16cb75ef38 Merge branch 'master' into mcpe-1.2 2017-09-09 21:58:30 +01:00
3b9689674d Merge remote-tracking branch 'origin/php/7.0' 2017-09-09 21:57:44 +01:00
7f5d8cc900 Always log stack traces regardless of whether log-debug is enabled 2017-09-09 19:27:26 +01:00
8761256246 Be more clear about WHY not to use source installs in production 2017-09-09 19:21:32 +01:00
8c363cb571 Added capability to specify arguments to PocketMine.php when running start.ps1
Example: .\start.ps1 --disable-ansi --debug.level=2
2017-09-09 18:44:18 +01:00
10b765e17a Merge branch 'php/7.0' into mcpe-1.2 2017-09-09 18:08:47 +01:00
0eb866bf25 Updated AvailableCommandsPacket 2017-09-09 14:23:19 +01:00
c46caa38e1 merge 2017-09-09 11:33:00 +01:00
17d949f476 Fixed SPL being reported as incompatible when it's actually not found 2017-09-09 11:25:59 +01:00
c569f55933 Fixed can't find sources when PocketMine.php is run from anywhere other than the repository root 2017-09-09 11:22:56 +01:00
01d8d216ca Yet another merge commit 2017-09-09 00:53:03 +01:00
f1ccee505b Submodule update (this is getting annoying) 2017-09-09 00:51:20 +01:00
a61adb5991 Merge branch 'php/7.0' 2017-09-08 21:40:25 +01:00
cae1a3bb4b Updated DevTools submodule 2017-09-08 21:38:14 +01:00
6681bd250a Merge branch 'php/7.0' 2017-09-08 20:37:09 +01:00
38293913ee Updated DevTools submodule 2017-09-08 20:36:32 +01:00
8493ce8a35 Merge branch 'php/7.0' 2017-09-07 20:07:16 +01:00
9b7868238c Improved Travis Test, capture error output from console, test phar 2017-09-07 20:03:58 +01:00
953c1ef4ec Fixed formatting issues in Travis test script 2017-09-07 20:03:54 +01:00
021a9a4820 Merge branch 'php/7.0' 2017-09-07 19:33:01 +01:00
5b7565664c Removed WeakRef from Travis CI 2017-09-07 19:32:04 +01:00
ebdfbe6bb9 Removed flight controls hack for spectator mode
THEY FINALLY FIXED IT
2017-09-07 19:06:36 +01:00
85ff236461 Fixed formatting issues in Travis test script 2017-09-07 17:27:07 +01:00
d7422d9283 Updated for 1.2.0.31 beta 2017-09-07 10:50:53 +01:00
fcb3c4820e Merge branch 'php/7.0' into mcpe-1.2 2017-09-07 10:42:20 +01:00
c72ef605b9 Fixed server crash when a garbage timezone value is set in php.ini, fallback to auto-detection 2017-09-07 10:40:32 +01:00
e274f1b7f8 Merge branch 'php/7.0' 2017-09-06 17:54:50 +01:00
69514c5763 Submodule update: Fixes little-endian longs being written in the wrong order, closes #1358 2017-09-06 17:54:38 +01:00
12c154badf Merge branch 'php/7.0' 2017-09-05 20:06:02 +01:00
c9ee206fe6 Merge branch 'php/7.0' 2017-09-04 19:42:03 +01:00
6877ac35eb Merge branch 'php/7.0' 2017-09-04 10:01:47 +01:00
78d49f8e66 Merge branch 'php/7.0' into mcpe-1.2 2017-09-03 15:02:41 +01:00
de6ebc5791 Merge branch 'php/7.0' 2017-09-03 15:00:29 +01:00
2cff5a500c Merge branch 'php/7.0' 2017-09-02 19:05:27 +01:00
f077ba4748 Merge branch 'php/7.0' into mcpe-1.2 2017-09-02 19:05:18 +01:00
dcf34b7188 Merge branch 'php/7.0' 2017-09-02 18:57:49 +01:00
ca84532640 Merge branch 'php/7.0' into mcpe-1.2 2017-09-02 18:57:39 +01:00
75e32b11b7 Merge branch 'php/7.0' into mcpe-1.2 2017-09-02 18:29:53 +01:00
9f44b2ed75 fixing ClientboundMapItemDataPacket 2017-09-02 18:22:53 +01:00
1c02c747ca Merge branch 'php/7.0' 2017-09-02 13:13:54 +01:00
a6c0f1512c Send the hotbar instead of contents when resetting hotbar
This used to be fine before 1.2, but now hotbar is handled separately.
2017-09-02 11:07:14 +01:00
604d8ecf9a Protocol changes for 1.2.0.25 2017-09-02 11:05:49 +01:00
5d75d3d5b6 Merge branch 'php/7.0' into mcpe-1.2 2017-09-01 23:10:58 +01:00
8b13b520e0 Merge branch 'php/7.0' 2017-09-01 20:22:25 +01:00
00e4fff259 Fixed Item fromString() crash on PHP 7.2 2017-09-01 20:05:04 +01:00
a06c934f4d Merge branch 'php/7.0' 2017-09-01 19:37:27 +01:00
5335ed9394 Merge branch 'php/7.0' 2017-09-01 16:57:51 +01:00
16aeb0ac85 Update .travis.yml 2017-08-31 21:12:45 +01:00
8caabd3267 Check for existence of ChunkUtils extension 2017-08-31 21:04:36 +01:00
ddfe828445 Require PHP 7.2, bump PocketMine-MP version to 1.7dev 2017-08-31 20:27:05 +01:00
67ad2d25b9 Added FireImmune data flag 2017-08-30 18:36:36 +01:00
190f4dd6ab New entity metadata flags 2017-08-30 14:13:24 +01:00
6d6283b7f3 Fixed Player->sendPosition() not working correctly 2017-08-28 20:07:04 +01:00
a3d21de559 Cleaned up network inventory action reading and core action creation 2017-08-28 20:04:35 +01:00
ece0692229 Fixed UUID corruption in recipe data
this is important for MultiRecipes to work correctly (yes I know we don't use these yet!)
2017-08-28 18:04:11 +01:00
b5d2402c9b Merge branch 'master' into mcpe-1.2 2017-08-28 18:02:09 +01:00
c7fd3eb725 Merge branch 'master' into mcpe-1.2 2017-08-27 16:09:23 +01:00
5433a3f964 Merge branch 'master' into mcpe-1.2 2017-08-24 19:26:52 +01:00
2c3d7c49f9 Updated creative inventory data with new item json serialization (more compact) 2017-08-24 12:17:17 +01:00
76acb1da7b New crafting recipe data format, more readable & more compact 2017-08-24 12:05:35 +01:00
17518195d1 Be more smart about json-serializing items
Don't include nbt_hex if we don't have a NBT tag
Don't include damage unless it's non-zero
Don't include count unless it's non-1
2017-08-24 12:02:03 +01:00
2443a57234 Merge branch 'master' into mcpe-1.2 2017-08-24 11:57:41 +01:00
95752ef542 Merge branch 'master' into mcpe-1.2 2017-08-23 13:20:35 +01:00
da4c9cf404 Fixed inventory cyclic references causing players to not get garbage-collected 2017-08-23 13:13:15 +01:00
770616d4ab Merge branch 'master' into mcpe-1.2 2017-08-22 20:48:32 +01:00
445a67954d Merge changes from master 2017-08-22 14:13:31 +01:00
4250e99e3a Updated for 1.2.0.22 2017-08-22 11:35:56 +01:00
121777375e Rewired eating 2017-08-21 12:52:20 +01:00
93e149e91c Rewiring release-item action to fix bows 2017-08-20 22:14:31 +01:00
1f70a7830e Branch merge 2017-08-20 21:07:19 +01:00
159b2e3d5e Merge branch 'master' into mcpe-1.2 2017-08-19 21:42:33 +01:00
e0307411da Cleaned up PlayerList handling 2017-08-19 19:36:15 +01:00
e5e76d4c93 Merge branch 'master' into mcpe-1.2 2017-08-18 18:39:39 +01:00
2688228a6f Don't dump subchunk raw data 2017-08-18 16:57:07 +01:00
e15eefc58f ... 2017-08-18 13:58:33 +01:00
8853452feb Updated for 1.2.0.18 2017-08-18 12:36:04 +01:00
09c53552c1 Merge branch 'master' into mcpe-1.2 2017-08-18 08:29:40 +01:00
1f6d325328 Added API for assigning permanent windows, fixed teleportation breaking inventory 2017-08-17 19:43:59 +01:00
f35ca147bb Merge branch 'master' into mcpe-1.2 2017-08-17 18:38:30 +01:00
b6fb2bca13 forgot to add this to the merge 2017-08-17 17:27:49 +01:00
4f1302adf2 Merge branch 'master' into mcpe-1.2 2017-08-17 17:14:16 +01:00
643e10037c Merge branch 'master' into mcpe-1.2 2017-08-16 13:19:37 +01:00
eda2473e78 New LevelEventPacket constants 2017-08-16 12:53:53 +01:00
4b65fef957 Fixed LevelEvent broadcasting 2017-08-16 12:53:32 +01:00
fbe2567e58 Merge branch 'master' into mcpe-1.2 2017-08-16 12:31:12 +01:00
5fc50aeda5 Found an unknown field in StartGamePacket 2017-08-16 10:10:42 +01:00
9be1b929a5 Added PhpDoc for packet field types and changed float x,y,z to Vector3 2017-08-13 20:02:07 +01:00
6480f7a989 Found an unknown field in TextPacket and added some docs 2017-08-13 18:20:06 +01:00
1576a79644 more packets 2017-08-13 17:43:33 +01:00
02cbf800d0 Added encode/decode for ModalFormResponsePacket 2017-08-12 19:33:16 +01:00
5a4fbc6f5a Handle exception for crafting and resend inventories 2017-08-12 19:11:57 +01:00
83fcec3e94 Don't add actions to the transaction if a crash occurred when getting the source inventory 2017-08-12 14:29:12 +01:00
5d436a06ec Added a method to get player cursor inventory 2017-08-12 14:10:47 +01:00
8958b3c51c Many many changes related to inventory transactions, fixed item dropping, fixed creative menu 2017-08-11 19:57:30 +01:00
c1ff7bbef4 Added creative-inventory magic slot numbers and renamed some constants 2017-08-11 12:31:11 +01:00
74ee94b385 Duct tape for inventory transactions, removed ContainerSetSlotPacket 2017-08-10 20:05:15 +01:00
5208ad885c Added crafting use-ingredient fake transaction source 2017-08-10 18:42:14 +01:00
51be88c698 Fixed AdventureSettings not working 2017-08-10 13:01:20 +01:00
0dc8362536 Added custom player permission level 2017-08-10 11:34:34 +01:00
9bae4d8ef6 updates for 1.2.0.11 2017-08-10 11:15:23 +01:00
bb4808c23e attacking entities working
just moved some code :P
2017-08-10 10:49:14 +01:00
3025f76cd0 Fix a couple of Sign bugs 2017-08-10 08:57:57 +01:00
1e539c4e3b fix some 1.2 translation issues, close pmmp/PocketMine-Language#19 2017-08-09 21:40:20 +01:00
590003d7c1 Fixed PlayerListPacket 2017-08-09 19:51:39 +01:00
72d40860f3 Remove useless else branch and and return unhandled for unmatched window IDs 2017-08-09 19:05:00 +01:00
d3d1e32309 Removed teleport zero-offsets (not needed in 1.2) 2017-08-09 17:01:56 +01:00
36d47a33f3 Fixed crash on player death 2017-08-09 13:34:25 +01:00
260179197b Use SplFixedArrays in inventory, added more typehints and cleaned up some duplicated code 2017-08-09 13:12:07 +01:00
75644b5df2 s/windowid/windowId 2017-08-08 12:37:26 +01:00
3ad1b1ba7f Added some ContainerSetDataPacket constants 2017-08-08 12:19:11 +01:00
b4c2305c7f Minor cleanup of Human->initEntity() 2017-08-08 10:44:11 +01:00
1d0f0a2999 Merge branch 'master' into mcpe-1.2 2017-08-08 10:23:19 +01:00
8ca37b3813 Fixed a bug in multiline chat handling 2017-08-07 19:41:08 +01:00
2ba601b6e9 Fixed signs 2017-08-07 19:40:45 +01:00
7958fffa07 Move some code around to fix block placing, breaking, and throwing snowballs 2017-08-07 12:28:07 +01:00
98e0a2ecba Removed InventoryType, added new inventory API methods 2017-08-07 11:31:36 +01:00
899e318a88 Merge branch 'master' into mcpe-1.2 2017-08-06 18:46:56 +01:00
989505c42c Updated crafting & creative data from 1.2.0.7 2017-08-06 17:21:52 +01:00
d9da9accbc Fix packet buffers when encoding twice 2017-08-06 17:21:52 +01:00
711d62b5eb Updated block & item IDs from 1.2.0.7
Note to self: these may need updating again later in the beta.
2017-08-06 17:21:52 +01:00
49506659e0 More constants 2017-08-06 17:21:51 +01:00
7886918140 Cleaned up some bad code in DataPacket, added encode/decodeHeader and made encode/decodePayload protected 2017-08-06 17:21:51 +01:00
8a151dc373 Fixed PlayerSkinPacket for 1.2.0.7 2017-08-06 17:21:51 +01:00
58a12fdfa3 Updated for 1.2.0.7 2017-08-06 17:21:51 +01:00
50dffeb6a1 Day 3, part 1 2017-08-06 17:21:51 +01:00
63d2b341b9 Day 2 2017-08-06 17:21:51 +01:00
77cd8e7799 More broken mess to spawn 1.2 2017-08-06 17:21:51 +01:00
388 changed files with 34984 additions and 27578 deletions

View File

@ -3,16 +3,17 @@
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
- https://forums.pmmp.io - PMMP Forums
-->
<!--- Any issues requesting updates to new versions of MCPE will be treated as spam. We do not need issues to tell us that there is a new version available. -->
<!---
Write a short description about the issue
If you are reporting a regression or unexpected behaviour, please include the below information:
Expected result: What were you expecting to happen?
Actual result: What actually happened?
Any issues requesting updates to new versions of MCPE will be treated as spam.
Please do not create issues for missing/un-implemented gameplay features - they will be closed.
-->
<!--- Write a short description about the issue -->
<!--- If you are reporting a regression or unexpected behaviour, please include the below information: -->
- Expected result: What were you expecting to happen?
- Actual result: What actually happened?
### Steps to reproduce the issue
<!--- help us find the problem by adding steps to reproduce the issue -->
1. ...
@ -21,9 +22,9 @@ Actual result: What actually happened?
### OS and versions
<!--- use the 'version' command in PocketMine-MP
NOTE: LATEST is not a valid version. PocketMine version should include Jenkins build number and/or git commit hash.
NOTE: LATEST is not a valid version. PocketMine-MP version should include Jenkins build number and/or git commit hash.
NO support whatsoever will be provided for forks or spoons of PocketMine. Issues relating to non-official distributions will be closed as spam. Please send such issues to whoever is responsible for the fork or spoon you are using.
NO support whatsoever will be provided for third-party modified variants of PocketMine-MP. Issues relating to third-party modifications will be closed as spam.
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
-->

6
.gitignore vendored
View File

@ -28,3 +28,9 @@ Desktop.ini
# Sphinx-doc
/docs/build/
!/docs/requirements.txt
# Composer
vendor/*
# Travis files
test_data/*

View File

@ -1,12 +1,21 @@
language: php
php:
- 7.0
- 7.2
before_script:
- pecl install channel://pecl.php.net/pthreads-3.1.6
- pecl install channel://pecl.php.net/weakref-0.3.3
- echo | pecl install channel://pecl.php.net/yaml-2.0.0
# - pecl install channel://pecl.php.net/pthreads-3.1.6
- echo | pecl install channel://pecl.php.net/yaml-2.0.2
- git clone https://github.com/krakjoe/pthreads.git
- cd pthreads
- git checkout 6c6b15138c923b69cfa46ee05fc2dd45da587287
- phpize
- ./configure
- make
- make install
- cd ..
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- composer install
script:
- ./tests/travis.sh

33
composer.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "pmmp/pocketmine-mp",
"description": "A server software for Minecraft: Pocket Edition written in PHP",
"type": "project",
"homepage": "https://pmmp.io",
"license": "LGPL-3.0",
"require": {
"php": ">=7.2",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-hash": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-reflection": "*",
"ext-sockets": "*",
"ext-spl": "*",
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11"
},
"autoload": {
"exclude-from-classmap": [
"src/spl/stubs"
],
"psr-0": {
"": ["src", "src/spl"]
}
}
}

36
composer.lock generated Normal file
View File

@ -0,0 +1,36 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "d4fecad9dce5314493052c870c8cf059",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"ext-pthreads": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.2",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-hash": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-reflection": "*",
"ext-sockets": "*",
"ext-spl": "*",
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11"
},
"platform-dev": []
}

View File

@ -25,7 +25,9 @@ namespace pocketmine;
use pocketmine\event\server\LowMemoryEvent;
use pocketmine\event\Timings;
use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Utils;
class MemoryManager{
@ -63,16 +65,19 @@ class MemoryManager{
private $garbageCollectionAsync;
/** @var int */
private $chunkRadiusOverride;
private $lowMemChunkRadiusOverride;
/** @var bool */
private $chunkCollect;
private $lowMemChunkGC;
/** @var bool */
private $chunkTrigger;
private $lowMemReduceChunkRadius;
/** @var bool */
private $chunkCache;
private $lowMemDisableChunkCache;
/** @var bool */
private $cacheTrigger;
private $lowMemClearWorldCache;
/** @var bool */
private $dumpWorkers = true;
public function __construct(Server $server){
$this->server = $server;
@ -124,13 +129,13 @@ class MemoryManager{
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
$this->chunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
$this->chunkCollect = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
$this->chunkTrigger = (bool) $this->server->getProperty("memory.max-chunks.low-memory-trigger", true);
$this->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
$this->chunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
$this->cacheTrigger = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
$this->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
$this->lowMemClearWorldCache = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
$this->dumpWorkers = (bool) $this->server->getProperty("memory.memory-dump.dump-async-worker", true);
gc_enable();
}
@ -145,7 +150,7 @@ class MemoryManager{
* @return bool
*/
public function canUseChunkCache() : bool{
return !($this->lowMemory and $this->chunkTrigger);
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
}
/**
@ -156,7 +161,7 @@ class MemoryManager{
* @return int
*/
public function getViewDistance(int $distance) : int{
return $this->lowMemory ? (int) min($this->chunkRadiusOverride, $distance) : $distance;
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? (int) min($this->lowMemChunkRadiusOverride, $distance) : $distance;
}
/**
@ -170,13 +175,13 @@ class MemoryManager{
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
if($this->cacheTrigger){
if($this->lowMemClearWorldCache){
foreach($this->server->getLevels() as $level){
$level->clearCache(true);
}
}
if($this->chunkTrigger and $this->chunkCollect){
if($this->lowMemChunkGC){
foreach($this->server->getLevels() as $level){
$level->doChunkGarbageCollection();
}
@ -261,6 +266,27 @@ class MemoryManager{
* @param int $maxStringSize
*/
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
MainLogger::getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
self::dumpMemory($this->server, $this->server->getLoader(), $outputFolder, $maxNesting, $maxStringSize);
if($this->dumpWorkers){
$scheduler = $this->server->getScheduler();
for($i = 0, $size = $scheduler->getAsyncTaskPoolSize(); $i < $size; ++$i){
$scheduler->scheduleAsyncTaskToWorker(new DumpWorkerMemoryTask($outputFolder, $maxNesting, $maxStringSize), $i);
}
}
}
/**
* Static memory dumper accessible from any thread.
*
* @param mixed $startingObject
* @param \ClassLoader $loader
* @param string $outputFolder
* @param int $maxNesting
* @param int $maxStringSize
*/
public static function dumpMemory($startingObject, \ClassLoader $loader, string $outputFolder, int $maxNesting, int $maxStringSize){
$hardLimit = ini_get('memory_limit');
ini_set('memory_limit', '-1');
gc_disable();
@ -269,12 +295,8 @@ class MemoryManager{
mkdir($outputFolder, 0777, true);
}
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
$obData = fopen($outputFolder . "/objects.js", "wb+");
$staticProperties = [];
$data = [];
$objects = [];
@ -283,8 +305,10 @@ class MemoryManager{
$instanceCounts = [];
$staticProperties = [];
$staticCount = 0;
foreach($this->server->getLoader()->getClasses() as $className){
foreach($loader->getClasses() as $className){
$reflection = new \ReflectionClass($className);
$staticProperties[$className] = [];
foreach($reflection->getProperties() as $property){
@ -297,7 +321,7 @@ class MemoryManager{
}
$staticCount++;
$this->continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
self::continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($staticProperties[$className]) === 0){
@ -305,9 +329,39 @@ class MemoryManager{
}
}
echo "[Dump] Wrote $staticCount static properties\n";
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
MainLogger::getLogger()->info("[Dump] Wrote $staticCount static properties");
$this->continueDump($this->server, $data, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
if($GLOBALS !== null){ //This might be null if we're on a different thread
$globalVariables = [];
$globalCount = 0;
$ignoredGlobals = [
'GLOBALS' => true,
'_SERVER' => true,
'_REQUEST' => true,
'_POST' => true,
'_GET' => true,
'_FILES' => true,
'_ENV' => true,
'_COOKIE' => true,
'_SESSION' => true
];
foreach($GLOBALS as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}
$globalCount++;
self::continueDump($value, $globalVariables[$varName], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
MainLogger::getLogger()->info("[Dump] Wrote $globalCount global variables");
}
self::continueDump($startingObject, $data, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
do{
$continue = false;
@ -349,25 +403,26 @@ class MemoryManager{
if(!$property->isPublic()){
$property->setAccessible(true);
}
$this->continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
self::continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
}
echo "[Dump] Wrote " . count($objects) . " objects\n";
}while($continue);
MainLogger::getLogger()->info("[Dump] Wrote " . count($objects) . " objects");
fclose($obData);
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
arsort($instanceCounts, SORT_NUMERIC);
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
echo "[Dump] Finished!\n";
MainLogger::getLogger()->info("[Dump] Finished!");
ini_set('memory_limit', $hardLimit);
gc_enable();
@ -382,7 +437,7 @@ class MemoryManager{
* @param int $maxNesting
* @param int $maxStringSize
*/
private function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
if($maxNesting <= 0){
$data = "(error) NESTING LIMIT REACHED";
return;
@ -406,7 +461,7 @@ class MemoryManager{
}
$data = [];
foreach($from as $key => $value){
$this->continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
}
}elseif(is_string($from)){
$data = "(string) len(". strlen($from) .") " . substr(Utils::printable($from), 0, $maxStringSize);

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,7 @@ namespace {
}
namespace pocketmine {
use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
use pocketmine\utils\ServerKiller;
@ -78,9 +79,12 @@ namespace pocketmine {
use pocketmine\wizard\SetupWizard;
use raklib\RakLib;
const VERSION = "1.6.2dev";
const API_VERSION = "3.0.0-ALPHA7";
const CODENAME = "Unleashed";
const NAME = "PocketMine-MP";
const VERSION = "1.7dev";
const API_VERSION = "3.0.0-ALPHA9";
const CODENAME = "[REDACTED]";
const MIN_PHP_VERSION = "7.2.0RC3";
/*
* Startup code. Do not look at it, it may harm you.
@ -89,9 +93,9 @@ namespace pocketmine {
* Enjoy it as much as I did writing it. I don't want to do it again.
*/
if(version_compare("7.0", PHP_VERSION) > 0 or version_compare("7.1", PHP_VERSION) <= 0){
echo "[CRITICAL] You must use PHP 7.0" . PHP_EOL;
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
echo "[CRITICAL] " . \pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . "." . PHP_EOL;
echo "[CRITICAL] Please use the installer provided on the homepage, or update to a newer PHP version." . PHP_EOL;
exit(1);
}
@ -103,13 +107,15 @@ namespace pocketmine {
error_reporting(-1);
set_error_handler(function($severity, $message, $file, $line){
function error_handler($severity, $message, $file, $line){
if(error_reporting() & $severity){
throw new \ErrorException($message, 0, $severity, $file, $line);
}else{ //stfu operator
return true;
}
});
}
set_error_handler('\pocketmine\error_handler');
if(!extension_loaded("phar")){
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
@ -120,30 +126,40 @@ namespace pocketmine {
if(\Phar::running(true) !== ""){
define('pocketmine\PATH', \Phar::running(true) . "/");
}else{
define('pocketmine\PATH', realpath(getcwd()) . DIRECTORY_SEPARATOR);
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
}
$requiredSplVer = "0.0.1";
if(!is_file(\pocketmine\PATH . "src/spl/version.php") or version_compare($requiredSplVer, require(\pocketmine\PATH . "src/spl/version.php")) > 0){
if(!is_file(\pocketmine\PATH . "src/spl/version.php")){
echo "[CRITICAL] Cannot find PocketMine-SPL or incompatible version." . PHP_EOL;
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
exit(1);
}elseif(version_compare($requiredSplVer, require(\pocketmine\PATH . "src/spl/version.php")) > 0){
echo "[CRITICAL] Incompatible PocketMine-SPL submodule version ($requiredSplVer is required)." . PHP_EOL;
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
exit(1);
}
if(is_file(\pocketmine\PATH . "vendor/autoload.php")){
require_once(\pocketmine\PATH . "vendor/autoload.php");
}else{
echo "[CRITICAL] Composer autoloader not found" . PHP_EOL;
echo "[CRITICAL] Please initialize composer dependencies before running." . PHP_EOL;
exit(1);
}
if(!class_exists("ClassLoader", false)){
if(!is_file(\pocketmine\PATH . "src/spl/ClassLoader.php")){
echo "[CRITICAL] Unable to find the PocketMine-SPL library." . PHP_EOL;
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
exit(1);
}
require_once(\pocketmine\PATH . "src/spl/ClassLoader.php");
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
}
/*
* We now use the Composer autoloader, but this autoloader is still used by RakLib and for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->addPath(\pocketmine\PATH . "src");
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
$autoloader->register(true);
$autoloader->register(false);
if(!class_exists(RakLib::class)){
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
@ -186,40 +202,51 @@ namespace pocketmine {
$logger = new MainLogger(\pocketmine\DATA . "server.log");
$logger->registerStatic();
if(!ini_get("date.timezone")){
do{
$timezone = ini_get("date.timezone");
if($timezone !== ""){
/*
* 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.
*/
if(strpos($timezone, "/") === false){
$default_timezone = timezone_name_from_abbr($timezone);
if($default_timezone !== false){
ini_set("date.timezone", $default_timezone);
date_default_timezone_set($default_timezone);
break;
}else{
//Bad php.ini value, try another method to detect timezone
$logger->warning("Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection");
}
}else{
date_default_timezone_set($timezone);
break;
}
}
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.");
}
break;
}
}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.
*/
$timezone = ini_get("date.timezone");
if(strpos($timezone, "/") === false){
$default_timezone = timezone_name_from_abbr($timezone);
ini_set("date.timezone", $default_timezone);
date_default_timezone_set($default_timezone);
}else{
date_default_timezone_set($timezone);
if($response = Utils::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
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']);
break;
}
}
ini_set("date.timezone", "UTC");
date_default_timezone_set("UTC");
$logger->warning("Timezone could not be automatically determined or was set to an invalid value. 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.");
}while(false);
function detect_system_timezone(){
switch(Utils::getOS()){
@ -408,7 +435,7 @@ namespace pocketmine {
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
}, $args));
}
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . ($trace[$i]["line"] ?? "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
}
return $messages;
@ -424,13 +451,13 @@ namespace pocketmine {
$errors = 0;
if(PHP_INT_SIZE < 8){
$logger->critical("Running PocketMine-MP with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
$logger->critical("Running " . \pocketmine\NAME . " with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
$exitCode = 1;
break;
}
if(php_sapi_name() !== "cli"){
$logger->critical("You must run PocketMine-MP using the CLI.");
$logger->critical("You must run " . \pocketmine\NAME . " using the CLI.");
++$errors;
}
@ -438,8 +465,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "3.1.5") < 0){
$logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version.");
if(version_compare($pthreads_version, "3.1.7-dev") < 0){
$logger->critical("pthreads >= 3.1.7-dev is required, while you have $pthreads_version.");
++$errors;
}
@ -462,7 +489,7 @@ namespace pocketmine {
}
if(extension_loaded("xdebug")){
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running PocketMine with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
}
$extensions = [
@ -524,7 +551,7 @@ namespace pocketmine {
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production.");
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
}
ThreadManager::init();
@ -536,19 +563,7 @@ namespace pocketmine {
$killer->start();
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
$erroredThreads = 0;
foreach(ThreadManager::getInstance()->getAll() as $id => $thread){
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
try{
$thread->quit();
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
}catch(\ThreadException $e){
++$erroredThreads;
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
}
}
if($erroredThreads > 0){
if(ThreadManager::getInstance()->stopAll() > 0){
if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
}

View File

@ -36,6 +36,7 @@ use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Attribute;
use pocketmine\entity\Effect;
use pocketmine\entity\Entity;
use pocketmine\entity\Skin;
use pocketmine\event\HandlerList;
use pocketmine\event\level\LevelInitEvent;
use pocketmine\event\level\LevelLoadEvent;
@ -47,7 +48,6 @@ use pocketmine\event\Timings;
use pocketmine\event\TimingsHandler;
use pocketmine\event\TranslationContainer;
use pocketmine\inventory\CraftingManager;
use pocketmine\inventory\InventoryType;
use pocketmine\inventory\Recipe;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\ItemFactory;
@ -83,6 +83,7 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\RakLibInterface;
use pocketmine\network\Network;
use pocketmine\network\query\QueryHandler;
@ -194,6 +195,9 @@ class Server{
/** @var int */
private $maxPlayers;
/** @var bool */
private $onlineMode = true;
/** @var bool */
private $autoSave;
@ -273,7 +277,7 @@ class Server{
* @return string
*/
public function getName() : string{
return "PocketMine-MP";
return \pocketmine\NAME;
}
/**
@ -339,6 +343,24 @@ class Server{
return $this->maxPlayers;
}
/**
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
* are not logged into Xbox Live will be disconnected.
*
* @return bool
*/
public function getOnlineMode() : bool{
return $this->onlineMode;
}
/**
* Alias of {@link #getOnlineMode()}.
* @return bool
*/
public function requiresAuthentication() : bool{
return $this->getOnlineMode();
}
/**
* @return int
*/
@ -494,36 +516,17 @@ class Server{
}
/**
* @param string $str
* @deprecated Moved to {@link Level#getDifficultyFromString}
*
* @param string $str
* @return int
*/
public static function getDifficultyFromString(string $str) : int{
switch(strtolower(trim($str))){
case "0":
case "peaceful":
case "p":
return 0;
case "1":
case "easy":
case "e":
return 1;
case "2":
case "normal":
case "n":
return 2;
case "3":
case "hard":
case "h":
return 3;
}
return -1;
return Level::getDifficultyFromString($str);
}
/**
* Returns Server global difficulty. Note that this may be overridden in individual Levels.
* @return int
*/
public function getDifficulty() : int{
@ -569,7 +572,7 @@ class Server{
* @return string
*/
public function getMotd() : string{
return $this->getConfigString("motd", "Minecraft: PE Server");
return $this->getConfigString("motd", \pocketmine\NAME . " Server");
}
/**
@ -761,25 +764,25 @@ class Server{
new DoubleTag("", $spawn->x),
new DoubleTag("", $spawn->y),
new DoubleTag("", $spawn->z)
]),
], NBT::TAG_Double),
new StringTag("Level", $this->getDefaultLevel()->getName()),
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getName()),
//new IntTag("SpawnX", (int) $spawn->x),
//new IntTag("SpawnY", (int) $spawn->y),
//new IntTag("SpawnZ", (int) $spawn->z),
//new ByteTag("SpawnForced", 1), //TODO
new ListTag("Inventory", []),
new ListTag("Inventory", [], NBT::TAG_Compound),
new CompoundTag("Achievements", []),
new IntTag("playerGameType", $this->getGamemode()),
new ListTag("Motion", [
new DoubleTag("", 0.0),
new DoubleTag("", 0.0),
new DoubleTag("", 0.0)
]),
], NBT::TAG_Double),
new ListTag("Rotation", [
new FloatTag("", 0.0),
new FloatTag("", 0.0)
]),
], NBT::TAG_Float),
new FloatTag("FallDistance", 0.0),
new ShortTag("Fire", 0),
new ShortTag("Air", 300),
@ -787,10 +790,6 @@ class Server{
new ByteTag("Invulnerable", 0),
new StringTag("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);
return $nbt;
@ -915,7 +914,7 @@ class Server{
/**
* @return Level|null
*/
public function getDefaultLevel(){
public function getDefaultLevel() : ?Level{
return $this->levelDefault;
}
@ -926,7 +925,7 @@ class Server{
*
* @param Level|null $level
*/
public function setDefaultLevel($level){
public function setDefaultLevel(?Level $level) : void{
if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
$this->levelDefault = $level;
}
@ -946,12 +945,8 @@ class Server{
*
* @return Level|null
*/
public function getLevel(int $levelId){
if(isset($this->levels[$levelId])){
return $this->levels[$levelId];
}
return null;
public function getLevel(int $levelId) : ?Level{
return $this->levels[$levelId] ?? null;
}
/**
@ -961,7 +956,7 @@ class Server{
*
* @return Level|null
*/
public function getLevelByName(string $name){
public function getLevelByName(string $name) : ?Level{
foreach($this->getLevels() as $level){
if($level->getFolderName() === $name){
return $level;
@ -983,13 +978,16 @@ class Server{
if($level === $this->getDefaultLevel() and !$forceUnload){
throw new \InvalidStateException("The default level cannot be unloaded while running, please switch levels.");
}
if($level->unload($forceUnload) === true){
unset($this->levels[$level->getId()]);
return true;
}
return $level->unload($forceUnload);
}
return false;
/**
* @internal
* @param Level $level
*/
public function removeLevel(Level $level) : void{
unset($this->levels[$level->getId()]);
}
/**
@ -1463,7 +1461,7 @@ class Server{
$this->logger->info("Loading server properties...");
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
"motd" => "Minecraft: PE Server",
"motd" => \pocketmine\NAME . " Server",
"server-port" => 19132,
"white-list" => false,
"announce-player-achievements" => true,
@ -1485,10 +1483,11 @@ class Server{
"enable-rcon" => false,
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
"auto-save" => true,
"view-distance" => 8
"view-distance" => 8,
"xbox-auth" => true
]);
$this->forceLanguage = $this->getProperty("settings.force-language", false);
$this->forceLanguage = (bool) $this->getProperty("settings.force-language", false);
$this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
@ -1512,7 +1511,12 @@ class Server{
}else{
Network::$BATCH_THRESHOLD = -1;
}
$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
if($this->networkCompressionLevel < 1 or $this->networkCompressionLevel > 9){
$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 7");
$this->networkCompressionLevel = 7;
}
$this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
$this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
@ -1558,8 +1562,18 @@ class Server{
$this->maxPlayers = $this->getConfigInt("max-players", 20);
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
$this->setConfigInt("difficulty", 3);
$this->onlineMode = $this->getConfigBoolean("xbox-auth", true);
if($this->onlineMode){
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth", ["enabled", "will"]));
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty", ["disable", "false"]));
}else{
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth", ["disabled", "will not"]));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty", ["enable", "true"]));
}
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
}
if(\pocketmine\DEBUG >= 0){
@ -1585,6 +1599,7 @@ class Server{
]));
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
Timings::init();
$this->consoleSender = new ConsoleCommandSender();
@ -1592,7 +1607,6 @@ class Server{
Entity::init();
Tile::init();
InventoryType::init();
BlockFactory::init();
Enchantment::init();
ItemFactory::init();
@ -1638,23 +1652,23 @@ class Server{
Generator::addGenerator(Nether::class, "hell");
Generator::addGenerator(Nether::class, "nether");
foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){
foreach((array) $this->getProperty("worlds", []) as $name => $options){
if($this->loadLevel($name) === false){
$seed = $this->getProperty("worlds.$name.seed", time());
$seed = $options["seed"] ?? time();
if(is_string($seed) and !is_numeric($seed)){
$seed = Utils::javaStringHash($seed);
}elseif(!is_int($seed)){
$seed = (int) $seed;
}
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
$generator = Generator::getGenerator(array_shift($options));
if(count($options) > 0){
$options = [
"preset" => implode(":", $options)
];
if(isset($options["generator"])){
$generatorOptions = explode(":", $options["generator"]);
$generator = Generator::getGenerator(array_shift($generatorOptions));
if(count($options) > 0){
$options["preset"] = implode(":", $generatorOptions);
}
}else{
$options = [];
$generator = Generator::getGenerator("default");
}
$this->generateLevel($name, $seed, $generator, $options);
@ -1975,8 +1989,8 @@ class Server{
$this->properties->reload();
$this->maxPlayers = $this->getConfigInt("max-players", 20);
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
$this->setConfigInt("difficulty", 3);
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
}
$this->banByIP->load();
@ -2271,7 +2285,7 @@ class Server{
}
public function addOnlinePlayer(Player $player){
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData());
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
$this->playerList[$player->getRawUniqueId()] = $player;
}
@ -2280,32 +2294,44 @@ class Server{
if(isset($this->playerList[$player->getRawUniqueId()])){
unset($this->playerList[$player->getRawUniqueId()]);
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_REMOVE;
$pk->entries[] = [$player->getUniqueId()];
$this->broadcastPacket($this->playerList, $pk);
$this->removePlayerListData($player->getUniqueId());
}
}
public function updatePlayerListData(UUID $uuid, $entityId, $name, $skinId, $skinData, array $players = null){
/**
* @param UUID $uuid
* @param int $entityId
* @param string $name
* @param Skin $skin
* @param Player[]|null $players
*/
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, array $players = null){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries[] = [$uuid, $entityId, $name, $skinId, $skinData];
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin);
$this->broadcastPacket($players ?? $this->playerList, $pk);
}
/**
* @param UUID $uuid
* @param Player[]|null $players
*/
public function removePlayerListData(UUID $uuid, array $players = null){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_REMOVE;
$pk->entries[] = [$uuid];
$pk->entries[] = PlayerListEntry::createRemovalEntry($uuid);
$this->broadcastPacket($players ?? $this->playerList, $pk);
}
/**
* @param Player $p
*/
public function sendFullPlayerListData(Player $p){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
foreach($this->playerList as $player){
$pk->entries[] = [$player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData()];
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
}
$p->dataPacket($pk);
@ -2375,7 +2401,7 @@ class Server{
}
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
if($this->getProperty("anonymous-statistics.enabled", true)){
if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
$this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers));
}
$this->uniquePlayers = [];
@ -2426,8 +2452,6 @@ class Server{
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
" | Load " . $this->getTickUsageAverage() . "%\x07";
$this->network->resetStatistics();
Timings::$titleTickTimer->stopTiming();
}
@ -2488,25 +2512,26 @@ class Server{
$player->checkNetwork();
}
if(($this->tickCounter & 0b1111) === 0){
if(($this->tickCounter % 20) === 0){
if($this->doTitleTick and Terminal::hasFormattingCodes()){
$this->titleTick();
}
$this->currentTPS = 20;
$this->currentUse = 0;
if(($this->tickCounter & 0b111111111) === 0){
try{
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
if($this->queryHandler !== null){
$this->queryHandler->regenerateInfo();
}
}catch(\Throwable $e){
$this->logger->logException($e);
}
}
$this->network->updateName();
$this->network->resetStatistics();
}
$this->getNetwork()->updateName();
if(($this->tickCounter & 0b111111111) === 0){
try{
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
if($this->queryHandler !== null){
$this->queryHandler->regenerateInfo();
}
}catch(\Throwable $e){
$this->logger->logException($e);
}
}
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){

View File

@ -51,16 +51,17 @@ abstract class Thread extends \Thread{
* (unless you are using a custom autoloader).
*/
public function registerClassLoader(){
require(\pocketmine\PATH . "vendor/autoload.php");
if(!interface_exists("ClassLoader", false)){
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
}
if($this->classLoader !== null){
$this->classLoader->register(true);
$this->classLoader->register(false);
}
}
public function start(int $options = PTHREADS_INHERIT_ALL){
public function start(?int $options = \PTHREADS_INHERIT_ALL){
ThreadManager::getInstance()->add($this);
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine;
use pocketmine\utils\MainLogger;
class ThreadManager extends \Volatile{
/** @var ThreadManager */
@ -68,4 +70,23 @@ class ThreadManager extends \Volatile{
return $array;
}
public function stopAll() : int{
$logger = MainLogger::getLogger();
$erroredThreads = 0;
foreach($this->getAll() as $thread){
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
try{
$thread->quit();
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
}catch(\ThreadException $e){
++$erroredThreads;
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
}
}
return $erroredThreads;
}
}

View File

@ -52,16 +52,17 @@ abstract class Worker extends \Worker{
* (unless you are using a custom autoloader).
*/
public function registerClassLoader(){
require(\pocketmine\PATH . "vendor/autoload.php");
if(!interface_exists("ClassLoader", false)){
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
}
if($this->classLoader !== null){
$this->classLoader->register(true);
$this->classLoader->register(false);
}
}
public function start(int $options = PTHREADS_INHERIT_ALL){
public function start(?int $options = \PTHREADS_INHERIT_ALL){
ThreadManager::getInstance()->add($this);
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
/**
@ -54,7 +55,7 @@ class Air extends Transparent{
return true;
}
public function canBeReplaced(Block $with = null) : bool{
public function canBeReplaced() : bool{
return true;
}
@ -66,10 +67,14 @@ class Air extends Transparent{
return false;
}
public function getBoundingBox(){
public function getBoundingBox() : ?AxisAlignedBB{
return null;
}
public function getCollisionBoxes() : array{
return [];
}
public function getHardness() : float{
return -1;
}

View File

@ -27,6 +27,7 @@ use pocketmine\inventory\AnvilInventory;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -38,14 +39,14 @@ class Anvil extends Fallable{
protected $id = self::ANVIL;
public function isSolid() : bool{
return false;
}
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function isTransparent() : bool{
return true;
}
public function getHardness() : float{
return 5;
}
@ -67,6 +68,30 @@ class Anvil extends Fallable{
return Tool::TYPE_PICKAXE;
}
public function recalculateBoundingBox() : ?AxisAlignedBB{
$inset = 0.125;
if($this->meta & 0x01){ //east/west
return new AxisAlignedBB(
$this->x,
$this->y,
$this->z + $inset,
$this->x + 1,
$this->y + 1,
$this->z + 1 - $inset
);
}else{
return new AxisAlignedBB(
$this->x + $inset,
$this->y,
$this->z,
$this->x + 1 - $inset,
$this->y + 1,
$this->z + 1
);
}
}
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$player->addWindow(new AnvilInventory($this));

View File

@ -29,10 +29,6 @@ use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Bed as TileBed;
use pocketmine\tile\Tile;
@ -58,7 +54,7 @@ class Bed extends Transparent{
return "Bed Block";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,
$this->y,
@ -129,7 +125,7 @@ class Bed extends Transparent{
/**
* @return Bed|null
*/
public function getOtherHalf(){
public function getOtherHalf() : ?Bed{
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
return $other;
@ -184,20 +180,8 @@ class Bed extends Transparent{
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
$nbt = new CompoundTag("", [
new StringTag("id", Tile::BED),
new ByteTag("color", $item->getDamage() & 0x0f),
new IntTag("x", $blockReplace->x),
new IntTag("y", $blockReplace->y),
new IntTag("z", $blockReplace->z)
]);
$nbt2 = clone $nbt;
$nbt2["x"] = $next->x;
$nbt2["z"] = $next->z;
Tile::createTile(Tile::BED, $this->getLevel(), $nbt);
Tile::createTile(Tile::BED, $this->getLevel(), $nbt2);
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
return true;
}
@ -209,7 +193,7 @@ class Bed extends Transparent{
public function onBreak(Item $item, Player $player = null) : bool{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
if(($other = $this->getOtherHalf()) !== null){
$this->getLevel()->useBreakOn($other, $item, $player, $player !== null); //make sure tiles get removed
$this->getLevel()->useBreakOn($other, $item, null, $player !== null); //make sure tiles get removed
}
return true;

View File

@ -61,7 +61,7 @@ class Block extends Position implements BlockIds, Metadatable{
protected $id;
/** @var int */
protected $meta = 0;
/** @var string */
/** @var string|null */
protected $fallbackName;
/** @var int|null */
protected $itemId;
@ -69,13 +69,17 @@ class Block extends Position implements BlockIds, Metadatable{
/** @var AxisAlignedBB */
public $boundingBox = null;
/** @var AxisAlignedBB[]|null */
protected $collisionBoxes = null;
/**
* @param int $id The block type's ID, 0-255
* @param int $meta Meta value of the block type
* @param string $name English name of the block type (TODO: implement translations)
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
* @param int $id The block type's ID, 0-255
* @param int $meta Meta value of the block type
* @param string|null $name English name of the block type (TODO: implement translations)
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
*/
public function __construct(int $id, int $meta = 0, string $name = "Unknown", int $itemId = null){
public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
$this->id = $id;
$this->meta = $meta;
$this->fallbackName = $name;
@ -86,7 +90,7 @@ class Block extends Position implements BlockIds, Metadatable{
* @return string
*/
public function getName() : string{
return $this->fallbackName;
return $this->fallbackName ?? "Unknown";
}
/**
@ -116,7 +120,7 @@ class Block extends Position implements BlockIds, Metadatable{
/**
* @param int $meta
*/
final public function setDamage(int $meta){
final public function setDamage(int $meta) : void{
if($meta < 0 or $meta > 0xf){
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
}
@ -136,6 +140,34 @@ class Block extends Position implements BlockIds, Metadatable{
return -1;
}
/**
* Returns the block meta, stripped of non-variant flags.
* @return int
*/
public function getVariant() : int{
return $this->meta & $this->getVariantBitmask();
}
/**
* AKA: Block->isPlaceable
* @return bool
*/
public function canBePlaced() : bool{
return true;
}
/**
* @return bool
*/
public function canBeReplaced() : bool{
return false;
}
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
return $blockReplace->canBeReplaced();
}
/**
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
*
@ -163,6 +195,10 @@ class Block extends Position implements BlockIds, Metadatable{
return true;
}
public function canBeBrokenWith(Item $item) : bool{
return $this->getHardness() !== -1;
}
/**
* Do the actions needed so the block is broken with the Item
*
@ -175,6 +211,63 @@ class Block extends Position implements BlockIds, Metadatable{
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
}
/**
* Returns the seconds that this block takes to be broken using an specific Item
*
* @param Item $item
*
* @return float
*/
public function getBreakTime(Item $item) : float{
$base = $this->getHardness() * 1.5;
if($this->canBeBrokenWith($item)){
if($this->getToolType() === Tool::TYPE_SHEARS and $item->isShears()){
$base /= 15;
}elseif(
($this->getToolType() === Tool::TYPE_PICKAXE and ($tier = $item->isPickaxe()) !== false) or
($this->getToolType() === Tool::TYPE_AXE and ($tier = $item->isAxe()) !== false) or
($this->getToolType() === Tool::TYPE_SHOVEL and ($tier = $item->isShovel()) !== false)
){
switch($tier){
case Tool::TIER_WOODEN:
$base /= 2;
break;
case Tool::TIER_STONE:
$base /= 4;
break;
case Tool::TIER_IRON:
$base /= 6;
break;
case Tool::TIER_DIAMOND:
$base /= 8;
break;
case Tool::TIER_GOLD:
$base /= 12;
break;
}
}
}else{
$base *= 3.33;
}
if($item->isSword()){
$base *= 0.5;
}
return $base;
}
/**
* Returns whether random block updates will be done on this block.
*
* @return bool
*/
public function ticksRandomly() : bool{
return false;
}
/**
* Fires a block update on the Block
*
@ -266,32 +359,6 @@ class Block extends Position implements BlockIds, Metadatable{
return false;
}
/**
* Returns whether random block updates will be done on this block.
*
* @return bool
*/
public function ticksRandomly() : bool{
return false;
}
/**
* AKA: Block->isPlaceable
* @return bool
*/
public function canBePlaced() : bool{
return true;
}
/**
* @param Block|null $with
*
* @return bool
*/
public function canBeReplaced(Block $with = null) : bool{
return false;
}
/**
* @return bool
*/
@ -328,7 +395,7 @@ class Block extends Position implements BlockIds, Metadatable{
}
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
}
@ -337,7 +404,7 @@ class Block extends Position implements BlockIds, Metadatable{
*
* @param Position $v
*/
final public function position(Position $v){
final public function position(Position $v) : void{
$this->x = (int) $v->x;
$this->y = (int) $v->y;
$this->z = (int) $v->z;
@ -354,60 +421,10 @@ class Block extends Position implements BlockIds, Metadatable{
*/
public function getDrops(Item $item) : array{
return [
ItemFactory::get($this->getItemId(), $this->getDamage() & $this->getVariantBitmask(), 1)
ItemFactory::get($this->getItemId(), $this->getVariant(), 1)
];
}
/**
* Returns the seconds that this block takes to be broken using an specific Item
*
* @param Item $item
*
* @return float
*/
public function getBreakTime(Item $item) : float{
$base = $this->getHardness() * 1.5;
if($this->canBeBrokenWith($item)){
if($this->getToolType() === Tool::TYPE_SHEARS and $item->isShears()){
$base /= 15;
}elseif(
($this->getToolType() === Tool::TYPE_PICKAXE and ($tier = $item->isPickaxe()) !== false) or
($this->getToolType() === Tool::TYPE_AXE and ($tier = $item->isAxe()) !== false) or
($this->getToolType() === Tool::TYPE_SHOVEL and ($tier = $item->isShovel()) !== false)
){
switch($tier){
case Tool::TIER_WOODEN:
$base /= 2;
break;
case Tool::TIER_STONE:
$base /= 4;
break;
case Tool::TIER_IRON:
$base /= 6;
break;
case Tool::TIER_DIAMOND:
$base /= 8;
break;
case Tool::TIER_GOLD:
$base /= 12;
break;
}
}
}else{
$base *= 3.33;
}
if($item->isSword()){
$base *= 0.5;
}
return $base;
}
public function canBeBrokenWith(Item $item) : bool{
return $this->getHardness() !== -1;
}
/**
* Returns the time in ticks which the block will fuel a furnace for.
* @return int
@ -432,6 +449,35 @@ class Block extends Position implements BlockIds, Metadatable{
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
}
/**
* Returns the 4 blocks on the horizontal axes around the block (north, south, east, west)
*
* @return Block[]
*/
public function getHorizontalSides() : array{
return [
$this->getSide(Vector3::SIDE_NORTH),
$this->getSide(Vector3::SIDE_SOUTH),
$this->getSide(Vector3::SIDE_WEST),
$this->getSide(Vector3::SIDE_EAST)
];
}
/**
* Returns the six blocks around this block.
*
* @return Block[]
*/
public function getAllSides() : array{
return array_merge(
[
$this->getSide(Vector3::SIDE_DOWN),
$this->getSide(Vector3::SIDE_UP)
],
$this->getHorizontalSides()
);
}
/**
* @return string
*/
@ -447,22 +493,50 @@ class Block extends Position implements BlockIds, Metadatable{
* @return bool
*/
public function collidesWithBB(AxisAlignedBB $bb) : bool{
$bb2 = $this->getBoundingBox();
$bbs = $this->getCollisionBoxes();
return $bb2 !== null and $bb->intersectsWith($bb2);
foreach($bbs as $bb2){
if($bb->intersectsWith($bb2)){
return true;
}
}
return false;
}
/**
* @param Entity $entity
*/
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
}
/**
* @return AxisAlignedBB[]
*/
public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
$this->collisionBoxes = $this->recalculateCollisionBoxes();
}
return $this->collisionBoxes;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
if($bb = $this->recalculateBoundingBox()){
return [$bb];
}
return [];
}
/**
* @return AxisAlignedBB|null
*/
public function getBoundingBox(){
public function getBoundingBox() : ?AxisAlignedBB{
if($this->boundingBox === null){
$this->boundingBox = $this->recalculateBoundingBox();
}
@ -472,7 +546,7 @@ class Block extends Position implements BlockIds, Metadatable{
/**
* @return AxisAlignedBB|null
*/
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,
$this->y,
@ -483,92 +557,52 @@ class Block extends Position implements BlockIds, Metadatable{
);
}
/**
* Clears any cached precomputed bounding boxes. This is called on block neighbour update and when the block is set
* into the world to remove any outdated precomputed AABBs and force recalculation.
*/
public function clearBoundingBoxes() : void{
$this->boundingBox = null;
$this->collisionBoxes = null;
}
/**
* @param Vector3 $pos1
* @param Vector3 $pos2
*
* @return MovingObjectPosition|null
*/
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){
$bb = $this->getBoundingBox();
if($bb === null){
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{
$bbs = $this->getCollisionBoxes();
if(empty($bbs)){
return null;
}
$v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX);
$v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX);
$v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY);
$v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY);
$v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ);
$v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ);
/** @var MovingObjectPosition|null $currentHit */
$currentHit = null;
/** @var int|float $currentDistance */
$currentDistance = PHP_INT_MAX;
if($v1 !== null and !$bb->isVectorInYZ($v1)){
$v1 = null;
foreach($bbs as $bb){
$nextHit = $bb->calculateIntercept($pos1, $pos2);
if($nextHit === null){
continue;
}
$nextDistance = $nextHit->hitVector->distanceSquared($pos1);
if($nextDistance < $currentDistance){
$currentHit = $nextHit;
$currentDistance = $nextDistance;
}
}
if($v2 !== null and !$bb->isVectorInYZ($v2)){
$v2 = null;
if($currentHit !== null){
$currentHit->blockX = $this->x;
$currentHit->blockY = $this->y;
$currentHit->blockZ = $this->z;
}
if($v3 !== null and !$bb->isVectorInXZ($v3)){
$v3 = null;
}
if($v4 !== null and !$bb->isVectorInXZ($v4)){
$v4 = null;
}
if($v5 !== null and !$bb->isVectorInXY($v5)){
$v5 = null;
}
if($v6 !== null and !$bb->isVectorInXY($v6)){
$v6 = null;
}
$vector = $v1;
if($v2 !== null and ($vector === null or $pos1->distanceSquared($v2) < $pos1->distanceSquared($vector))){
$vector = $v2;
}
if($v3 !== null and ($vector === null or $pos1->distanceSquared($v3) < $pos1->distanceSquared($vector))){
$vector = $v3;
}
if($v4 !== null and ($vector === null or $pos1->distanceSquared($v4) < $pos1->distanceSquared($vector))){
$vector = $v4;
}
if($v5 !== null and ($vector === null or $pos1->distanceSquared($v5) < $pos1->distanceSquared($vector))){
$vector = $v5;
}
if($v6 !== null and ($vector === null or $pos1->distanceSquared($v6) < $pos1->distanceSquared($vector))){
$vector = $v6;
}
if($vector === null){
return null;
}
$f = -1;
if($vector === $v1){
$f = 4;
}elseif($vector === $v2){
$f = 5;
}elseif($vector === $v3){
$f = 0;
}elseif($vector === $v4){
$f = 1;
}elseif($vector === $v5){
$f = 2;
}elseif($vector === $v6){
$f = 3;
}
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
return $currentHit;
}
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){

View File

@ -56,7 +56,7 @@ class BlockFactory{
*
* @param bool $force
*/
public static function init(bool $force = false){
public static function init(bool $force = false) : void{
if(self::$list === null or $force){
self::$list = new \SplFixedArray(256);
self::$fullList = new \SplFixedArray(4096);
@ -133,7 +133,7 @@ class BlockFactory{
self::registerBlock(new Furnace());
self::registerBlock(new BurningFurnace());
self::registerBlock(new SignPost());
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door Block", Item::OAK_DOOR));
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door", Item::OAK_DOOR));
self::registerBlock(new Ladder());
self::registerBlock(new Rail());
self::registerBlock(new CobblestoneStairs());
@ -153,8 +153,8 @@ class BlockFactory{
self::registerBlock(new Cactus());
self::registerBlock(new Clay());
self::registerBlock(new Sugarcane());
self::registerBlock(new Fence());
//TODO: JUKEBOX
self::registerBlock(new WoodenFence());
self::registerBlock(new Pumpkin());
self::registerBlock(new Netherrack());
self::registerBlock(new SoulSand());
@ -168,8 +168,8 @@ class BlockFactory{
self::registerBlock(new Trapdoor());
//TODO: MONSTER_EGG
self::registerBlock(new StoneBricks());
//TODO: BROWN_MUSHROOM_BLOCK
//TODO: RED_MUSHROOM_BLOCK
self::registerBlock(new BrownMushroomBlock());
self::registerBlock(new RedMushroomBlock());
self::registerBlock(new IronBars());
self::registerBlock(new GlassPane());
self::registerBlock(new Melon());
@ -245,12 +245,13 @@ class BlockFactory{
self::registerBlock(new Coal());
self::registerBlock(new PackedIce());
self::registerBlock(new DoublePlant());
//TODO: STANDING_BANNER
//TODO: WALL_BANNER
//TODO: DAYLIGHT_DETECTOR_INVERTED
//TODO: RED_SANDSTONE
//TODO: RED_SANDSTONE_STAIRS
//TODO: DOUBLE_STONE_SLAB2
//TODO: STONE_SLAB2
self::registerBlock(new RedSandstone());
self::registerBlock(new RedSandstoneStairs());
self::registerBlock(new DoubleStoneSlab2());
self::registerBlock(new StoneSlab2());
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
@ -259,19 +260,20 @@ class BlockFactory{
//TODO: REPEATING_COMMAND_BLOCK
//TODO: CHAIN_COMMAND_BLOCK
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door Block", Item::SPRUCE_DOOR));
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door Block", Item::BIRCH_DOOR));
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door Block", Item::JUNGLE_DOOR));
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door Block", Item::ACACIA_DOOR));
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door Block", Item::DARK_OAK_DOOR));
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door", Item::SPRUCE_DOOR));
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door", Item::BIRCH_DOOR));
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door", Item::JUNGLE_DOOR));
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door", Item::ACACIA_DOOR));
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door", Item::DARK_OAK_DOOR));
self::registerBlock(new GrassPath());
self::registerBlock(new ItemFrame());
//TODO: CHORUS_FLOWER
//TODO: PURPUR_BLOCK
self::registerBlock(new Purpur());
//TODO: PURPUR_STAIRS
self::registerBlock(new PurpurStairs());
//TODO: END_BRICKS
//TODO: UNDYED_SHULKER_BOX
self::registerBlock(new EndStoneBricks());
//TODO: FROSTED_ICE
self::registerBlock(new EndRod());
//TODO: END_GATEWAY
@ -300,7 +302,7 @@ class BlockFactory{
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
self::registerBlock(new Concrete());
//TODO: CONCRETEPOWDER
self::registerBlock(new ConcretePowder());
//TODO: CHORUS_PLANT
self::registerBlock(new StainedGlass());
@ -314,6 +316,7 @@ class BlockFactory{
//TODO: INFO_UPDATE2
//TODO: MOVINGBLOCK
//TODO: OBSERVER
//TODO: STRUCTURE_BLOCK
//TODO: RESERVED6
@ -338,10 +341,10 @@ class BlockFactory{
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
* $override parameter.
*/
public static function registerBlock(Block $block, bool $override = false){
public static function registerBlock(Block $block, bool $override = false) : void{
$id = $block->getId();
if(self::$list[$id] !== null and !(self::$list[$id] instanceof UnknownBlock) and !$override){
if(!$override and self::isRegistered($id)){
throw new \RuntimeException("Trying to overwrite an already registered block");
}
@ -403,4 +406,15 @@ class BlockFactory{
public static function getBlockStatesArray() : \SplFixedArray{
return self::$fullList;
}
/**
* Returns whether a specified block ID is already registered in the block factory.
*
* @param int $id
* @return bool
*/
public static function isRegistered(int $id) : bool{
$b = self::$list[$id];
return $b !== null and !($b instanceof UnknownBlock);
}
}

View File

@ -109,7 +109,7 @@ interface BlockIds{
const CACTUS = 81;
const CLAY_BLOCK = 82;
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
const JUKEBOX = 84;
const FENCE = 85;
const PUMPKIN = 86;
const NETHERRACK = 87;
@ -201,7 +201,8 @@ interface BlockIds{
const COAL_BLOCK = 173;
const PACKED_ICE = 174;
const DOUBLE_PLANT = 175;
const STANDING_BANNER = 176;
const WALL_BANNER = 177;
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
const RED_SANDSTONE = 179;
const RED_SANDSTONE_STAIRS = 180;
@ -227,6 +228,7 @@ interface BlockIds{
const PURPUR_STAIRS = 203;
const UNDYED_SHULKER_BOX = 205;
const END_BRICKS = 206;
const FROSTED_ICE = 207;
const END_ROD = 208;
@ -270,6 +272,7 @@ interface BlockIds{
const INFO_UPDATE2 = 249;
const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
const OBSERVER = 251;
const STRUCTURE_BLOCK = 252;
const RESERVED6 = 255;

View File

@ -60,7 +60,7 @@ class BoneBlock extends Solid{
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item); // TODO: Change the autogenerated stub
return parent::getDrops($item);
}
return [];

View File

@ -21,18 +21,21 @@
declare(strict_types=1);
namespace pocketmine\item;
namespace pocketmine\block;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\item\Item;
class IronDoor extends Item{
public function __construct(int $meta = 0){
$this->block = BlockFactory::get(Block::IRON_DOOR_BLOCK);
parent::__construct(self::IRON_DOOR, $meta, "Iron Door");
class BrownMushroomBlock extends RedMushroomBlock{
protected $id = Block::BROWN_MUSHROOM_BLOCK;
public function getName() : string{
return "Brown Mushroom Block";
}
public function getMaxStackSize() : int{
return 1;
public function getDrops(Item $item) : array{
return [
Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
];
}
}

View File

@ -26,10 +26,6 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\math\Vector3;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Furnace as TileFurnace;
@ -68,26 +64,8 @@ class BurningFurnace extends Solid{
];
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
$this->getLevel()->setBlock($blockReplace, $this, true, true);
$nbt = new CompoundTag("", [
new ListTag("Items", []),
new StringTag("id", Tile::FURNACE),
new IntTag("x", $this->x),
new IntTag("y", $this->y),
new IntTag("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
if($item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile("Furnace", $this->getLevel(), $nbt);
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
return true;
}
@ -96,15 +74,7 @@ class BurningFurnace extends Solid{
if($player instanceof Player){
$furnace = $this->getLevel()->getTile($this);
if(!($furnace instanceof TileFurnace)){
$nbt = new CompoundTag("", [
new ListTag("Items", []),
new StringTag("id", Tile::FURNACE),
new IntTag("x", $this->x),
new IntTag("y", $this->y),
new IntTag("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
$furnace = Tile::createTile("Furnace", $this->getLevel(), $nbt);
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
}
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){

View File

@ -21,14 +21,31 @@
declare(strict_types=1);
namespace pocketmine\item;
namespace pocketmine\block;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;
abstract class Button extends Flowable{
class Skull extends Item{
public function __construct(int $meta = 0){
$this->block = BlockFactory::get(Block::SKULL_BLOCK);
parent::__construct(self::SKULL, $meta, "Mob Head");
$this->meta = $meta;
}
public function getVariantBitmask() : int{
return 0;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
//TODO: check valid target block
$this->meta = $face;
return $this->level->setBlock($this, $this, true, true);
}
public function onActivate(Item $item, Player $player = null) : bool{
//TODO
return true;
}
}

View File

@ -54,7 +54,7 @@ class Cactus extends Transparent{
return "Cactus";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x + 0.0625,
@ -70,7 +70,7 @@ class Cactus extends Transparent{
return true;
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
$entity->attack($ev);
}
@ -92,7 +92,7 @@ class Cactus extends Transparent{
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
if($this->meta === 0x0f){
for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
if(!$ev->isCancelled()){

View File

@ -48,7 +48,7 @@ class Cake extends Transparent implements FoodSource{
return "Cake Block";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$f = $this->getDamage() * 0.125; //1 slice width

View File

@ -50,7 +50,7 @@ class Carpet extends Flowable{
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,

View File

@ -27,10 +27,6 @@ use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Chest as TileChest;
@ -56,7 +52,7 @@ class Chest extends Transparent{
return Tool::TYPE_AXE;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x + 0.0625,
$this->y,
@ -95,26 +91,7 @@ class Chest extends Transparent{
}
$this->getLevel()->setBlock($blockReplace, $this, true, true);
$nbt = new CompoundTag("", [
new ListTag("Items", []),
new StringTag("id", Tile::CHEST),
new IntTag("x", $this->x),
new IntTag("y", $this->y),
new IntTag("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
if($item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
$tile = Tile::createTile("Chest", $this->getLevel(), $nbt);
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
if($chest instanceof TileChest and $tile instanceof TileChest){
$chest->pairWith($tile);
@ -142,15 +119,7 @@ class Chest extends Transparent{
if($t instanceof TileChest){
$chest = $t;
}else{
$nbt = new CompoundTag("", [
new ListTag("Items", []),
new StringTag("id", Tile::CHEST),
new IntTag("x", $this->x),
new IntTag("y", $this->y),
new IntTag("z", $this->z)
]);
$nbt->Items->setTagType(NBT::TAG_Compound);
$chest = Tile::createTile("Chest", $this->getLevel(), $nbt);
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
}
if(

View File

@ -37,10 +37,6 @@ class CobblestoneWall extends Transparent{
$this->meta = $meta;
}
public function isSolid() : bool{
return false;
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
}
@ -57,38 +53,38 @@ class CobblestoneWall extends Transparent{
return "Cobblestone Wall";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
//walls don't have any special collision boxes like fences do
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
$n = $north ? 0 : 0.25;
$s = $south ? 1 : 0.75;
$w = $west ? 0 : 0.25;
$e = $east ? 1 : 0.75;
if($north and $south and !$west and !$east){
$w = 0.3125;
$e = 0.6875;
}elseif(!$north and !$south and $west and $east){
$n = 0.3125;
$s = 0.6875;
$inset = 0.25;
if(
$this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
(
($north and $south and !$west and !$east) or
(!$north and !$south and $west and $east)
)
){
//If connected to two sides on the same axis but not any others, AND there is not a block on top, there is no post and the wall is thinner
$inset = 0.3125;
}
return new AxisAlignedBB(
$this->x + $w,
$this->x + ($west ? 0 : $inset),
$this->y,
$this->z + $n,
$this->x + $e,
$this->z + ($north ? 0 : $inset),
$this->x + 1 - ($east ? 0 : $inset),
$this->y + 1.5,
$this->z + $s
$this->z + 1 - ($south ? 0 : $inset)
);
}
public function canConnect(Block $block){
return ($block->getId() !== self::COBBLESTONE_WALL and $block->getId() !== self::FENCE_GATE) ? $block->isSolid() and !$block->isTransparent() : true;
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
}
}

View File

@ -51,7 +51,7 @@ class Cobweb extends Flowable{
return Tool::TYPE_SWORD;
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
$entity->resetFallDistance();
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
class CocoaBlock extends Solid{
class CocoaBlock extends Transparent{
protected $id = self::COCOA_BLOCK;

View File

@ -0,0 +1,78 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Tool;
use pocketmine\level\Level;
class ConcretePowder extends Fallable{
protected $id = self::CONCRETE_POWDER;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getName() : string{
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Concrete Powder";
}
public function getHardness() : float{
return 0.5;
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL and ($block = $this->checkAdjacentWater()) !== null){
$this->level->setBlock($this, $block);
return $type;
}
return parent::onUpdate($type);
}
/**
* @return null|Block
*/
public function tickFalling() : ?Block{
return $this->checkAdjacentWater();
}
/**
* @return null|Block
*/
private function checkAdjacentWater() : ?Block{
for($i = 1; $i < 6; ++$i){ //Do not check underneath
if($this->getSide($i) instanceof Water){
return Block::get(Block::CONCRETE, $this->meta);
}
}
return null;
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\inventory\BigCraftingGrid;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\Player;
@ -49,6 +50,7 @@ class CraftingTable extends Solid{
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$player->setCraftingGrid(new BigCraftingGrid($player));
$player->craftingType = 1;
}

View File

@ -23,6 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
@ -38,7 +41,6 @@ class DeadBush extends Flowable{
return "Dead Bush";
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
@ -51,4 +53,17 @@ class DeadBush extends Flowable{
return false;
}
public function getToolType() : int{
return Tool::TYPE_SHEARS;
}
public function getDrops(Item $item) : array{
if($item->isShears()){
return parent::getDrops($item);
}
return [
ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
];
}
}

View File

@ -44,13 +44,20 @@ class Dirt extends Solid{
}
public function getName() : string{
if($this->meta === 1){
return "Coarse Dirt";
}
return "Dirt";
}
public function onActivate(Item $item, Player $player = null) : bool{
if($item->isHoe()){
$item->useOn($this);
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND, 0), true);
if($this->meta === 1){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
}else{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
}
return true;
}

View File

@ -54,7 +54,7 @@ abstract class Door extends Transparent{
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$f = 0.1875;
$damage = $this->getFullDamage();

View File

@ -38,7 +38,7 @@ class DoublePlant extends Flowable{
$this->meta = $meta;
}
public function canBeReplaced(Block $with = null) : bool{
public function canBeReplaced() : bool{
return $this->meta === 2 or $this->meta === 3; //grass or fern
}
@ -51,7 +51,7 @@ class DoublePlant extends Flowable{
4 => "Rose Bush",
5 => "Peony"
];
return $names[$this->meta & 0x07] ?? "";
return $names[$this->getVariant()] ?? "";
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
@ -79,7 +79,7 @@ class DoublePlant extends Flowable{
return (
$other->getId() === $this->getId() and
($other->getDamage() & 0x07) === ($this->getDamage() & 0x07) and
$other->getVariant() === $this->getVariant() and
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
);
}

View File

@ -21,14 +21,27 @@
declare(strict_types=1);
namespace pocketmine\item;
namespace pocketmine\block;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
abstract class DoubleSlab extends Solid{
class ItemFrame extends Item{
public function __construct(int $meta = 0){
$this->block = BlockFactory::get(Block::ITEM_FRAME_BLOCK);
parent::__construct(self::ITEM_FRAME, $meta, "Item Frame");
$this->meta = $meta;
}
abstract public function getSlabId() : int;
public function getName() : string{
return "Double " . BlockFactory::get($this->getSlabId(), $this->getVariant())->getName() . " Slab";
}
public function getDrops(Item $item) : array{
return [
ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
];
}
}

View File

@ -24,15 +24,14 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class DoubleStoneSlab extends Solid{
class DoubleStoneSlab extends DoubleSlab{
protected $id = self::DOUBLE_STONE_SLAB;
public function __construct(int $meta = 0){
$this->meta = $meta;
public function getSlabId() : int{
return self::STONE_SLAB;
}
public function getHardness() : float{
@ -43,25 +42,9 @@ class DoubleStoneSlab extends Solid{
return Tool::TYPE_PICKAXE;
}
public function getName() : string{
static $names = [
0 => "Stone",
1 => "Sandstone",
2 => "Wooden",
3 => "Cobblestone",
4 => "Brick",
5 => "Stone Brick",
6 => "Quartz",
7 => "Nether Brick"
];
return "Double " . $names[$this->meta & 0x07] . " Slab";
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return [
ItemFactory::get(Item::STONE_SLAB, $this->getDamage() & 0x07, 2)
];
return parent::getDrops($item);
}
return [];

View File

@ -0,0 +1,34 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
class DoubleStoneSlab2 extends DoubleStoneSlab{
protected $id = self::DOUBLE_STONE_SLAB2;
public function getSlabId() : int{
return self::STONE_SLAB2;
}
}

View File

@ -23,16 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class DoubleWoodenSlab extends Solid{
class DoubleWoodenSlab extends DoubleSlab{
protected $id = self::DOUBLE_WOODEN_SLAB;
public function __construct(int $meta = 0){
$this->meta = $meta;
public function getSlabId() : int{
return self::WOODEN_SLAB;
}
public function getHardness() : float{
@ -42,23 +40,4 @@ class DoubleWoodenSlab extends Solid{
public function getToolType() : int{
return Tool::TYPE_AXE;
}
public function getName() : string{
static $names = [
0 => "Oak",
1 => "Spruce",
2 => "Birch",
3 => "Jungle",
4 => "Acacia",
5 => "Dark Oak"
];
return "Double " . ($names[$this->meta & 0x07] ?? "") . " Wooden Slab";
}
public function getDrops(Item $item) : array{
return [
ItemFactory::get(Item::WOODEN_SLAB, $this->getDamage() & 0x07, 2)
];
}
}

View File

@ -27,10 +27,8 @@ use pocketmine\inventory\EnchantInventory;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\EnchantTable as TileEnchantTable;
use pocketmine\tile\Tile;
class EnchantingTable extends Transparent{
@ -43,24 +41,8 @@ class EnchantingTable extends Transparent{
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
$this->getLevel()->setBlock($blockReplace, $this, true, true);
$nbt = new CompoundTag("", [
new StringTag("id", Tile::ENCHANT_TABLE),
new IntTag("x", $this->x),
new IntTag("y", $this->y),
new IntTag("z", $this->z)
]);
if($item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), $nbt);
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
return true;
}

View File

@ -54,7 +54,7 @@ class EndPortalFrame extends Solid{
return false;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,

View File

@ -61,7 +61,7 @@ class EndRod extends Flowable{
return 14;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$m = $this->meta & ~0x01;
$width = 0.375;

View File

@ -0,0 +1,57 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
class EndStoneBricks extends Solid{
protected $id = self::END_BRICKS;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getName() : string{
return "End Stone Bricks";
}
public function getHardness() : float{
return 0.8;
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}

View File

@ -26,41 +26,32 @@ namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
abstract class Fallable extends Solid{
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(Vector3::SIDE_DOWN);
if($down->getId() === self::AIR or ($down instanceof Liquid)){
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
$fall = Entity::createEntity("FallingSand", $this->getLevel(), new CompoundTag("", [
new ListTag("Pos", [
new DoubleTag("", $this->x + 0.5),
new DoubleTag("", $this->y),
new DoubleTag("", $this->z + 0.5)
]),
new ListTag("Motion", [
new DoubleTag("", 0),
new DoubleTag("", 0),
new DoubleTag("", 0)
]),
new ListTag("Rotation", [
new FloatTag("", 0),
new FloatTag("", 0)
]),
new IntTag("TileID", $this->getId()),
new ByteTag("Data", $this->getDamage())
]));
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
$fall->spawnToAll();
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
$nbt->setInt("TileID", $this->getId());
$nbt->setByte("Data", $this->getDamage());
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
if($fall !== null){
$fall->spawnToAll();
}
}
}
}
/**
* @return null|Block
*/
public function tickFalling() : ?Block{
return null;
}
}

View File

@ -28,6 +28,7 @@ use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
class Farmland extends Transparent{
@ -53,7 +54,7 @@ class Farmland extends Transparent{
return true;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,
$this->y,
@ -65,8 +66,43 @@ class Farmland extends Transparent{
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_RANDOM){
//TODO: hydration
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
return $type;
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(!$this->canHydrate()){
if($this->meta > 0){
$this->meta--;
$this->level->setBlock($this, $this, false, false);
}else{
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), false, true);
}
return $type;
}elseif($this->meta < 7){
$this->meta = 7;
$this->level->setBlock($this, $this, false, false);
return $type;
}
}
return false;
}
protected function canHydrate() : bool{
//TODO: check rain
$start = $this->add(-4, 0, -4);
$end = $this->add(4, 1, 4);
for($y = $start->y; $y <= $end->y; ++$y){
for($z = $start->z; $z <= $end->z; ++$z){
for($x = $start->x; $x <= $end->x; ++$x){
$id = $this->level->getBlockIdAt($x, $y, $z);
if($id === Block::STILL_WATER or $id === Block::FLOWING_WATER){
return true;
}
}
}
}
return false;

View File

@ -23,73 +23,87 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
class Fence extends Transparent{
const FENCE_OAK = 0;
const FENCE_SPRUCE = 1;
const FENCE_BIRCH = 2;
const FENCE_JUNGLE = 3;
const FENCE_ACACIA = 4;
const FENCE_DARKOAK = 5;
protected $id = self::FENCE;
abstract class Fence extends Transparent{
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getHardness() : float{
return 2;
public function getThickness() : float{
return 0.25;
}
public function getToolType() : int{
return Tool::TYPE_AXE;
}
public function getName() : string{
static $names = [
self::FENCE_OAK => "Oak Fence",
self::FENCE_SPRUCE => "Spruce Fence",
self::FENCE_BIRCH => "Birch Fence",
self::FENCE_JUNGLE => "Jungle Fence",
self::FENCE_ACACIA => "Acacia Fence",
self::FENCE_DARKOAK => "Dark Oak Fence"
];
return $names[$this->meta & 0x07] ?? "Unknown";
}
protected function recalculateBoundingBox(){
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
$n = $north ? 0 : 0.375;
$s = $south ? 1 : 0.625;
$w = $west ? 0 : 0.375;
$e = $east ? 1 : 0.625;
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$width = 0.5 - $this->getThickness() / 2;
return new AxisAlignedBB(
$this->x + $w,
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
$this->y,
$this->z + $n,
$this->x + $e,
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
$this->y + 1.5,
$this->z + $s
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
);
}
public function canConnect(Block $block){
return ($block instanceof Fence or $block instanceof FenceGate) ? true : $block->isSolid() and !$block->isTransparent();
protected function recalculateCollisionBoxes() : array{
$inset = 0.5 - $this->getThickness() / 2;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
if($connectWest or $connectEast){
//X axis (west/east)
$bbs[] = new AxisAlignedBB(
$this->x + ($connectWest ? 0 : $inset),
$this->y,
$this->z + $inset,
$this->x + 1 - ($connectEast ? 0 : $inset),
$this->y + 1.5,
$this->z + 1 - $inset
);
}
$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
if($connectNorth or $connectSouth){
//Z axis (north/south)
$bbs[] = new AxisAlignedBB(
$this->x + $inset,
$this->y,
$this->z + ($connectNorth ? 0 : $inset),
$this->x + 1 - $inset,
$this->y + 1.5,
$this->z + 1 - ($connectSouth ? 0 : $inset)
);
}
if(empty($bbs)){
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
return [
new AxisAlignedBB(
$this->x + $inset,
$this->y,
$this->z + $inset,
$this->x + 1 - $inset,
$this->y + 1.5,
$this->z + 1 - $inset
)
];
}
return $bbs;
}
public function getFuelTime() : int{
return 300;
public function canConnect(Block $block){
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
}
}

View File

@ -41,7 +41,7 @@ class FenceGate extends Transparent{
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
if(($this->getDamage() & 0x04) > 0){
return null;

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Arrow;
use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
@ -57,7 +57,7 @@ class Fire extends Flowable{
return false;
}
public function canBeReplaced(Block $with = null) : bool{
public function canBeReplaced() : bool{
return true;
}
@ -65,7 +65,7 @@ class Fire extends Flowable{
return true;
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
$entity->attack($ev);

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\math\AxisAlignedBB;
abstract class Flowable extends Transparent{
public function canBeFlowedInto() : bool{
@ -33,15 +35,11 @@ abstract class Flowable extends Transparent{
return 0;
}
public function getBlastResistance() : float{
return 0;
}
public function isSolid() : bool{
return false;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return null;
}
}

View File

@ -24,14 +24,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\FlowerPot as TileFlowerPot;
use pocketmine\tile\Tile;
@ -49,10 +44,10 @@ class FlowerPot extends Flowable{
}
public function getName() : string{
return "Flower Pot Block";
return "Flower Pot";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x + 0.3125,
$this->y,
@ -69,23 +64,7 @@ class FlowerPot extends Flowable{
}
$this->getLevel()->setBlock($blockReplace, $this, true, true);
$nbt = new CompoundTag("", [
new StringTag("id", Tile::FLOWER_POT),
new IntTag("x", $blockReplace->x),
new IntTag("y", $blockReplace->y),
new IntTag("z", $blockReplace->z),
new ShortTag("item", 0),
new IntTag("mData", 0)
]);
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), $nbt);
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
return true;
}
@ -112,14 +91,8 @@ class FlowerPot extends Flowable{
$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
$this->getLevel()->setBlock($this, $this, true, false);
$pot->setItem($item);
$pot->setItem($item->pop());
if($player instanceof Player){
if($player->isSurvival()){
$item->setCount($item->getCount() - 1);
$player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : ItemFactory::get(Item::AIR));
}
}
return true;
}

View File

@ -76,22 +76,22 @@ class Grass extends Solid{
return Level::BLOCK_UPDATE_RANDOM;
}elseif($lightAbove >= 9){
//try grass spread
$vector = $this->asVector3();
for($i = 0; $i < 4; ++$i){
$vector->x = mt_rand($this->x - 1, $this->x + 1);
$vector->y = mt_rand($this->y - 3, $this->y + 1);
$vector->z = mt_rand($this->z - 1, $this->z + 1);
$x = mt_rand($this->x - 1, $this->x + 1);
$y = mt_rand($this->y - 3, $this->y + 1);
$z = mt_rand($this->z - 1, $this->z + 1);
if(
$this->level->getBlockIdAt($vector->x, $vector->y, $vector->z) !== Block::DIRT or
$this->level->getFullLightAt($vector->x, $vector->y + 1, $vector->z) < 4 or
BlockFactory::$lightFilter[$this->level->getBlockIdAt($vector->x, $vector->y + 1, $vector->z)] >= 3
$this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
$this->level->getBlockDataAt($x, $y, $z) === 1 or
$this->level->getFullLightAt($x, $y + 1, $z) < 4 or
BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
){
continue;
}
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this->level->getBlock($vector), $this, BlockFactory::get(Block::GRASS)));
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
if(!$ev->isCancelled()){
$this->level->setBlock($vector, $ev->getNewState(), false, false);
$this->level->setBlock($b, $ev->getNewState(), false, false);
}
}

View File

@ -26,7 +26,9 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
class GrassPath extends Transparent{
@ -44,7 +46,7 @@ class GrassPath extends Transparent{
return Tool::TYPE_SHOVEL;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,
$this->y,
@ -59,6 +61,15 @@ class GrassPath extends Transparent{
return 0.6;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
return $type;
}
return false;
}
public function getDrops(Item $item) : array{
return [
ItemFactory::get(Item::DIRT, 0, 1)

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\PillarRotationHelper;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -44,16 +45,7 @@ class HayBale extends Solid{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
$faces = [
0 => 0,
1 => 0,
2 => 0b1000,
3 => 0b1000,
4 => 0b0100,
5 => 0b0100
];
$this->meta = ($this->meta & 0x03) | $faces[$face];
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
$this->getLevel()->setBlock($blockReplace, $this, true, true);
return true;

View File

@ -37,7 +37,7 @@ class IronDoor extends Door{
}
public function getName() : string{
return "Iron Door Block";
return "Iron Door";
}
public function getToolType() : int{

View File

@ -24,12 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\{
ByteTag, CompoundTag, FloatTag, IntTag, StringTag
};
use pocketmine\Player;
use pocketmine\tile\ItemFrame as TileItemFrame;
use pocketmine\tile\Tile;
@ -50,29 +46,13 @@ class ItemFrame extends Flowable{
public function onActivate(Item $item, Player $player = null) : bool{
$tile = $this->level->getTile($this);
if(!($tile instanceof TileItemFrame)){
$nbt = new CompoundTag("", [
new StringTag("id", Tile::ITEM_FRAME),
new IntTag("x", $this->x),
new IntTag("y", $this->y),
new IntTag("z", $this->z),
new FloatTag("ItemDropChance", 1.0),
new ByteTag("ItemRotation", 0)
]);
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), $nbt);
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
}
if($tile->hasItem()){
$tile->setItemRotation(($tile->getItemRotation() + 1) % 8);
}else{
if($item->getCount() > 0){
$frameItem = clone $item;
$frameItem->setCount(1);
$item->setCount($item->getCount() - 1);
$tile->setItem($frameItem);
if($player instanceof Player and $player->isSurvival()){
$player->getInventory()->setItemInHand($item->getCount() <= 0 ? ItemFactory::get(Item::AIR) : $item);
}
}
}elseif(!$item->isNull()){
$tile->setItem($item->pop());
}
return true;
@ -92,10 +72,10 @@ class ItemFrame extends Flowable{
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$sides = [
0 => 4,
1 => 5,
2 => 2,
3 => 3
0 => Vector3::SIDE_WEST,
1 => Vector3::SIDE_EAST,
2 => Vector3::SIDE_NORTH,
3 => Vector3::SIDE_SOUTH
];
if(!$this->getSide($sides[$this->meta])->isSolid()){
$this->level->useBreakOn($this);
@ -120,22 +100,7 @@ class ItemFrame extends Flowable{
$this->meta = $faces[$face];
$this->level->setBlock($blockReplace, $this, true, true);
$nbt = new CompoundTag("", [
new StringTag("id", Tile::ITEM_FRAME),
new IntTag("x", $blockReplace->x),
new IntTag("y", $blockReplace->y),
new IntTag("z", $blockReplace->z),
new FloatTag("ItemDropChance", 1.0),
new ByteTag("ItemRotation", 0)
]);
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), $nbt);
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
return true;

View File

@ -59,54 +59,35 @@ class Ladder extends Transparent{
return true;
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
$entity->resetFallDistance();
$entity->onGround = true;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$f = 0.1875;
$minX = $minZ = 0;
$maxX = $maxZ = 1;
if($this->meta === 2){
return new AxisAlignedBB(
$this->x,
$this->y,
$this->z + 1 - $f,
$this->x + 1,
$this->y + 1,
$this->z + 1
);
$minZ = 1 - $f;
}elseif($this->meta === 3){
return new AxisAlignedBB(
$this->x,
$this->y,
$this->z,
$this->x + 1,
$this->y + 1,
$this->z + $f
);
$maxZ = $f;
}elseif($this->meta === 4){
return new AxisAlignedBB(
$this->x + 1 - $f,
$this->y,
$this->z,
$this->x + 1,
$this->y + 1,
$this->z + 1
);
$minX = 1 - $f;
}elseif($this->meta === 5){
return new AxisAlignedBB(
$this->x,
$this->y,
$this->z,
$this->x + $f,
$this->y + 1,
$this->z + 1
);
$maxX = $f;
}
return null;
return new AxisAlignedBB(
$this->x + $minX,
$this->y,
$this->z + $minZ,
$this->x + $maxX,
$this->y + 1,
$this->z + $maxZ
);
}
@ -131,13 +112,7 @@ class Ladder extends Transparent{
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$sides = [
2 => 3,
3 => 2,
4 => 5,
5 => 4
];
if(!$this->getSide($sides[$this->meta])->isSolid()){ //Replace with common break method
if(!$this->getSide($this->meta ^ 0x01)->isSolid()){ //Replace with common break method
$this->level->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}

View File

@ -48,7 +48,7 @@ class Lava extends Liquid{
return "Lava";
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
$entity->fallDistance *= 0.5;
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);

View File

@ -61,7 +61,7 @@ class Leaves extends Transparent{
self::BIRCH => "Birch Leaves",
self::JUNGLE => "Jungle Leaves"
];
return $names[$this->meta & 0x03];
return $names[$this->getVariant()];
}
public function diffusesSkyLight() : bool{
@ -169,10 +169,14 @@ class Leaves extends Transparent{
return $this->getLevel()->setBlock($this, $this, true);
}
public function getVariantBitmask() : int{
return 0x03;
}
public function getDrops(Item $item) : array{
$drops = [];
$variantMeta = $this->getDamage() & 0x03;
$variantMeta = $this->getVariant();
if($item->isShears()){
$drops[] = ItemFactory::get($this->getItemId(), $variantMeta, 1);

View File

@ -36,11 +36,11 @@ class Leaves2 extends Leaves{
self::ACACIA => "Acacia Leaves",
self::DARK_OAK => "Dark Oak Leaves"
];
return $names[$this->meta & 0x03] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function getDrops(Item $item) : array{
$variantMeta = $this->getDamage() & 0x03;
$variantMeta = $this->getVariant();
if($item->isShears()){
return [

View File

@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
abstract class Liquid extends Transparent{
@ -41,7 +42,7 @@ abstract class Liquid extends Transparent{
return false;
}
public function canBeReplaced(Block $with = null) : bool{
public function canBeReplaced() : bool{
return true;
}
@ -116,7 +117,7 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){
++$z;
}
$sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
$sideBlock = $this->getLevel()->getBlockAt($x, $y, $z);
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
if($blockDecay < 0){
@ -124,7 +125,7 @@ abstract class Liquid extends Transparent{
continue;
}
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z)));
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlockAt($x, $y - 1, $z));
if($blockDecay >= 0){
$realDecay = $blockDecay - ($decay - 8);
@ -145,21 +146,21 @@ abstract class Liquid extends Transparent{
if($this->getDamage() >= 8){
$falling = false;
if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){
if(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z - 1)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z + 1)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y, $this->z)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y, $this->z)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z - 1)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z + 1)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y + 1, $this->z)->canBeFlowedInto()){
$falling = true;
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){
}elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y + 1, $this->z)->canBeFlowedInto()){
$falling = true;
}
@ -171,7 +172,7 @@ abstract class Liquid extends Transparent{
return $vector->normalize();
}
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
$flow = $this->getFlowVector();
$vector->x += $flow->x;
$vector->y += $flow->y;
@ -205,10 +206,10 @@ abstract class Liquid extends Transparent{
if($decay > 0){
$smallestFlowDecay = -100;
$this->adjacentSources = 0;
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $smallestFlowDecay);
$k = $smallestFlowDecay + $multiplier;
@ -216,7 +217,7 @@ abstract class Liquid extends Transparent{
$k = -1;
}
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z)))) >= 0){
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z))) >= 0){
if($topFlowDecay >= 8){
$k = $topFlowDecay;
}else{
@ -225,7 +226,7 @@ abstract class Liquid extends Transparent{
}
if($this->adjacentSources >= 2 and $this instanceof Water){
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
if($bottomBlock->isSolid()){
$k = 0;
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
@ -255,7 +256,7 @@ abstract class Liquid extends Transparent{
}
if($decay >= 0){
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
if($this instanceof Lava and $bottomBlock instanceof Water){
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
@ -280,19 +281,19 @@ abstract class Liquid extends Transparent{
}
if($flags[0]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
$this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $l);
}
if($flags[1]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l);
$this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $l);
}
if($flags[2]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l);
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $l);
}
if($flags[3]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $l);
}
}
@ -335,13 +336,13 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){
++$z;
}
$blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
$blockSide = $this->getLevel()->getBlockAt($x, $y, $z);
if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
continue;
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
continue;
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
}elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
return $accumulatedCost;
}
@ -385,13 +386,13 @@ abstract class Liquid extends Transparent{
}elseif($j === 3){
++$z;
}
$block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
$block = $this->getLevel()->getBlockAt($x, $y, $z);
if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){
continue;
}elseif($block instanceof Liquid and $block->getDamage() === 0){
continue;
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
}elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
$this->flowCost[$j] = 0;
}else{
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
@ -444,7 +445,7 @@ abstract class Liquid extends Transparent{
}
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return null;
}

View File

@ -57,7 +57,7 @@ class Magma extends Solid{
return true;
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
if(!$entity->isSneaking()){
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
$entity->attack($ev);

View File

@ -26,7 +26,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
class MonsterSpawner extends Solid{
class MonsterSpawner extends Transparent{
protected $id = self::MONSTER_SPAWNER;

View File

@ -67,7 +67,7 @@ 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()->getBlock(new Vector3($x, $y, $z));
$block = $this->getLevel()->getBlockAt($x, $y, $z);
if($block->getId() === Block::DIRT){
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM)));

View File

@ -26,14 +26,10 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
class NetherBrickFence extends Transparent{
class NetherBrickFence extends Fence{
protected $id = self::NETHER_BRICK_FENCE;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getHardness() : float{
return 2;
}
@ -46,10 +42,6 @@ class NetherBrickFence extends Transparent{
return "Nether Brick Fence";
}
public function canConnect(Block $block){
return ($block instanceof NetherBrickFence) or ($block->isSolid() and !$block->isTransparent());
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
@ -57,6 +49,4 @@ class NetherBrickFence extends Transparent{
return [];
}
//TODO: fix bounding boxes
}

View File

@ -40,6 +40,10 @@ class NetherWartPlant extends Flowable{
$this->meta = $meta;
}
public function getName() : string{
return "Nether Wart";
}
public function ticksRandomly() : bool{
return true;
}

View File

@ -56,7 +56,7 @@ class Planks extends Solid{
self::ACACIA => "Acacia Wood Planks",
self::DARK_OAK => "Dark Oak Wood Planks"
];
return $names[$this->meta & 0x07] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function getFuelTime() : int{

View File

@ -48,7 +48,7 @@ class Prismarine extends Solid{
self::DARK => "Dark Prismarine",
self::BRICKS => "Prismarine Bricks"
];
return $names[$this->meta & 0x03] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function getToolType() : int{

View File

@ -21,34 +21,27 @@
declare(strict_types=1);
namespace pocketmine\inventory;
namespace pocketmine\block;
use pocketmine\item\Item;
class Purpur extends Quartz{
interface Transaction{
protected $id = self::PURPUR_BLOCK;
/**
* @return Inventory
*/
public function getInventory() : Inventory;
public function getName() : string{
static $names = [
self::NORMAL => "Purpur Block",
self::CHISELED => "Chiseled Purpur", //wtf?
self::PILLAR => "Purpur Pillar"
];
/**
* @return int
*/
public function getSlot() : int;
return $names[$this->getVariant()] ?? "Unknown";
}
/**
* @return Item
*/
public function getSourceItem() : Item;
public function getHardness() : float{
return 1.5;
}
/**
* @return Item
*/
public function getTargetItem() : Item;
/**
* @return float
*/
public function getCreationTime() : float;
public function getBlastResistance() : float{
return 30;
}
}

View File

@ -21,18 +21,31 @@
declare(strict_types=1);
namespace pocketmine\item;
namespace pocketmine\block;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
use pocketmine\item\Tool;
class PurpurStairs extends Stair{
protected $id = self::PURPUR_STAIRS;
class WoodenDoor extends Item{
public function __construct(int $meta = 0){
$this->block = BlockFactory::get(Block::WOODEN_DOOR_BLOCK);
parent::__construct(self::WOODEN_DOOR, $meta, "Wooden Door");
$this->meta = $meta;
}
public function getMaxStackSize() : int{
return 1;
public function getName() : string{
return "Purpur Stairs";
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
}
public function getHardness() : float{
return 1.5;
}
public function getBlastResistance() : float{
return 30;
}
}

View File

@ -31,9 +31,9 @@ use pocketmine\Player;
class Quartz extends Solid{
const QUARTZ_NORMAL = 0;
const QUARTZ_CHISELED = 1;
const QUARTZ_PILLAR = 2;
const NORMAL = 0;
const CHISELED = 1;
const PILLAR = 2;
protected $id = self::QUARTZ_BLOCK;
@ -47,15 +47,15 @@ class Quartz extends Solid{
public function getName() : string{
static $names = [
self::QUARTZ_NORMAL => "Quartz Block",
self::QUARTZ_CHISELED => "Chiseled Quartz Block",
self::QUARTZ_PILLAR => "Quartz Pillar"
self::NORMAL => "Quartz Block",
self::CHISELED => "Chiseled Quartz Block",
self::PILLAR => "Quartz Pillar"
];
return $names[$this->meta & 0x03] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
if($this->meta !== self::QUARTZ_NORMAL){
if($this->meta !== self::NORMAL){
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
}
return $this->getLevel()->setBlock($blockReplace, $this, true, true);

View File

@ -0,0 +1,55 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
class RedMushroomBlock extends Solid{
protected $id = Block::RED_MUSHROOM_BLOCK;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getName() : string{
return "Red Mushroom Block";
}
public function getHardness() : float{
return 0.2;
}
public function getToolType() : int{
return Tool::TYPE_AXE;
}
public function getDrops(Item $item) : array{
return [
Item::get(Item::RED_MUSHROOM, 0, mt_rand(0, 2))
];
}
}

View File

@ -21,14 +21,17 @@
declare(strict_types=1);
namespace pocketmine\item;
namespace pocketmine\block;
use pocketmine\block\Block;
use pocketmine\block\BlockFactory;
class RedSandstone extends Sandstone{
protected $id = self::RED_SANDSTONE;
class FlowerPot extends Item{
public function __construct(int $meta = 0){
$this->block = BlockFactory::get(Block::FLOWER_POT_BLOCK);
parent::__construct(self::FLOWER_POT, $meta, "Flower Pot");
public function getName() : string{
static $names = [
self::NORMAL => "Red Sandstone",
self::CHISELED => "Chiseled Red Sandstone",
self::SMOOTH => "Smooth Red Sandstone"
];
return $names[$this->getVariant()] ?? "Unknown";
}
}

View File

@ -0,0 +1,34 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
class RedSandstoneStairs extends SandstoneStairs{
protected $id = self::RED_SANDSTONE_STAIRS;
public function getName() : string{
return "Red " . parent::getName();
}
}

View File

@ -48,7 +48,7 @@ class Sandstone extends Solid{
self::CHISELED => "Chiseled Sandstone",
self::SMOOTH => "Smooth Sandstone"
];
return $names[$this->meta & 0x03] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function getToolType() : int{

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\generator\object\Tree;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
@ -54,7 +53,7 @@ class Sapling extends Flowable{
4 => "Acacia Sapling",
5 => "Dark Oak Sapling"
];
return $names[$this->meta & 0x07] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function ticksRandomly() : bool{
@ -75,7 +74,7 @@ class Sapling extends Flowable{
public function onActivate(Item $item, Player $player = null) : bool{
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
//TODO: change log type
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
$item->count--;
@ -95,7 +94,7 @@ class Sapling extends Flowable{
}elseif($type === Level::BLOCK_UPDATE_RANDOM){ //Growth
if(mt_rand(1, 7) === 1){
if(($this->meta & 0x08) === 0x08){
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
}else{
$this->meta |= 0x08;
$this->getLevel()->setBlock($this, $this, true);
@ -110,10 +109,8 @@ class Sapling extends Flowable{
return false;
}
public function getDrops(Item $item) : array{
return [
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x07, 1)
];
public function getVariantBitmask() : int{
return 0x07;
}
public function getFuelTime() : int{

View File

@ -26,11 +26,10 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Sign as TileSign;
use pocketmine\tile\Tile;
class SignPost extends Transparent{
@ -55,43 +54,23 @@ class SignPost extends Transparent{
return "Sign Post";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return null;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
if($face !== Vector3::SIDE_DOWN){
$nbt = new CompoundTag("", [
new StringTag("id", Tile::SIGN),
new IntTag("x", $blockReplace->x),
new IntTag("y", $blockReplace->y),
new IntTag("z", $blockReplace->z),
new StringTag("Text1", ""),
new StringTag("Text2", ""),
new StringTag("Text3", ""),
new StringTag("Text4", "")
]);
if($player !== null){
$nbt->Creator = new StringTag("Creator", $player->getRawUniqueId());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
if($face === Vector3::SIDE_UP){
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
$this->getLevel()->setBlock($blockReplace, $this, true);
}else{
$this->meta = $face;
$this->getLevel()->setBlock($blockReplace, new WallSign($this->meta), true);
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
}
Tile::createTile(Tile::SIGN, $this->getLevel(), $nbt);
Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player));
return true;
}

View File

@ -27,13 +27,8 @@ use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
use pocketmine\tile\Skull as SkullTile;
use pocketmine\tile\Spawnable;
use pocketmine\tile\Skull as TileSkull;
use pocketmine\tile\Tile;
class Skull extends Flowable{
@ -49,10 +44,10 @@ class Skull extends Flowable{
}
public function getName() : string{
return "Mob Head Block";
return "Mob Head";
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
//TODO: different bounds depending on attached face (meta)
return new AxisAlignedBB(
$this->x + 0.25,
@ -65,35 +60,20 @@ class Skull extends Flowable{
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
if($face !== Vector3::SIDE_DOWN){
$this->meta = $face;
if($face === Vector3::SIDE_UP){
$rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F;
}else{
$rot = $face;
}
$this->getLevel()->setBlock($blockReplace, $this, true);
$nbt = new CompoundTag("", [
new StringTag("id", Tile::SKULL),
new ByteTag("SkullType", $item->getDamage()),
new ByteTag("Rot", $rot),
new IntTag("x", (int) $this->x),
new IntTag("y", (int) $this->y),
new IntTag("z", (int) $this->z)
]);
if($item->hasCustomName()){
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
}
/** @var Spawnable $tile */
Tile::createTile("Skull", $this->getLevel(), $nbt);
return true;
if($face === Vector3::SIDE_DOWN){
return false;
}
return false;
$this->meta = $face;
$this->getLevel()->setBlock($blockReplace, $this, true);
Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player));
return true;
}
public function getDrops(Item $item) : array{
$tile = $this->level->getTile($this);
if($tile instanceof SkullTile){
if($tile instanceof TileSkull){
return [
ItemFactory::get(Item::SKULL, $tile->getType(), 1)
];

View File

@ -0,0 +1,129 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
abstract class Slab extends Transparent{
public function __construct(int $meta = 0){
$this->meta = $meta;
}
abstract public function getDoubleSlabId() : int;
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
if(parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock)){
return true;
}
if($blockReplace->getId() === $this->getId() and $blockReplace->getVariant() === $this->getVariant()){
if(($blockReplace->getDamage() & 0x08) !== 0){ //Trying to combine with top slab
return $clickVector->y <= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_UP);
}else{
return $clickVector->y >= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_DOWN);
}
}
return false;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
$this->meta &= 0x07;
if($face === Vector3::SIDE_DOWN){
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
return true;
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
return true;
}else{
$this->meta |= 0x08;
}
}elseif($face === Vector3::SIDE_UP){
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
return true;
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
return true;
}
}else{ //TODO: collision
if($blockReplace->getId() === $this->id){
if($blockReplace->getVariant() === $this->meta){
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
return true;
}
return false;
}else{
if($facePos->y > 0.5){
$this->meta |= 0x08;
}
}
}
if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){
return false;
}
$this->getLevel()->setBlock($blockReplace, $this, true, true);
return true;
}
public function getVariantBitmask() : int{
return 0x07;
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
if(($this->meta & 0x08) > 0){
return new AxisAlignedBB(
$this->x,
$this->y + 0.5,
$this->z,
$this->x + 1,
$this->y + 1,
$this->z + 1
);
}else{
return new AxisAlignedBB(
$this->x,
$this->y,
$this->z,
$this->x + 1,
$this->y + 0.5,
$this->z + 1
);
}
}
}

View File

@ -42,7 +42,7 @@ class SnowLayer extends Flowable{
return "Snow Layer";
}
public function canBeReplaced(Block $with = null) : bool{
public function canBeReplaced() : bool{
return true;
}

View File

@ -46,7 +46,7 @@ class SoulSand extends Solid{
return Tool::TYPE_SHOVEL;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x,

View File

@ -31,103 +31,56 @@ use pocketmine\Player;
abstract class Stair extends Transparent{
/*
public function collidesWithBB(AxisAlignedBB $bb, &$list = []){
$damage = $this->getDamage();
$j = $damage & 0x03;
protected function recalculateCollisionBoxes() : array{
//TODO: handle corners
$f = 0;
$f1 = 0.5;
$f2 = 0.5;
$f3 = 1;
$minYSlab = ($this->meta & 0x04) === 0 ? 0 : 0.5;
$maxYSlab = $minYSlab + 0.5;
if(($damage & 0x04) > 0){
$f = 0.5;
$f1 = 1;
$f2 = 0;
$f3 = 0.5;
$bbs = [
new AxisAlignedBB(
$this->x,
$this->y + $minYSlab,
$this->z,
$this->x + 1,
$this->y + $maxYSlab,
$this->z + 1
)
];
$minY = ($this->meta & 0x04) === 0 ? 0.5 : 0;
$maxY = $minY + 0.5;
$rotationMeta = $this->meta & 0x03;
$minX = $minZ = 0;
$maxX = $maxZ = 1;
switch($rotationMeta){
case 0:
$minX = 0.5;
break;
case 1:
$maxX = 0.5;
break;
case 2:
$minZ = 0.5;
break;
case 3:
$maxZ = 0.5;
break;
}
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f,
$this->z,
$this->x + 1,
$this->y + $f1,
$this->z + 1
))){
$list[] = $bb2;
}
$bbs[] = new AxisAlignedBB(
$this->x + $minX,
$this->y + $minY,
$this->z + $minZ,
$this->x + $maxX,
$this->y + $maxY,
$this->z + $maxZ
);
if($j === 0){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x + 0.5,
$this->y + $f2,
$this->z,
$this->x + 1,
$this->y + $f3,
$this->z + 1
))){
$list[] = $bb2;
}
}elseif($j === 1){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z,
$this->x + 0.5,
$this->y + $f3,
$this->z + 1
))){
$list[] = $bb2;
}
}elseif($j === 2){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z + 0.5,
$this->x + 1,
$this->y + $f3,
$this->z + 1
))){
$list[] = $bb2;
}
}elseif($j === 3){
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
$this->x,
$this->y + $f2,
$this->z,
$this->x + 1,
$this->y + $f3,
$this->z + 0.5
))){
$list[] = $bb2;
}
}
}
*/
protected function recalculateBoundingBox(){
if(($this->getDamage() & 0x04) > 0){
return new AxisAlignedBB(
$this->x,
$this->y + 0.5,
$this->z,
$this->x + 1,
$this->y + 1,
$this->z + 1
);
}else{
return new AxisAlignedBB(
$this->x,
$this->y,
$this->z,
$this->x + 1,
$this->y + 0.5,
$this->z + 1
);
}
return $bbs;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{

View File

@ -60,7 +60,7 @@ class Stone extends Solid{
self::ANDESITE => "Andesite",
self::POLISHED_ANDESITE => "Polished Andesite"
];
return $names[$this->meta & 0x07] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function getDrops(Item $item) : array{

View File

@ -53,7 +53,7 @@ class StoneBricks extends Solid{
self::CRACKED => "Cracked Stone Bricks",
self::CHISELED => "Chiseled Stone Bricks"
];
return $names[$this->meta & 0x03];
return $names[$this->getVariant()] ?? "Unknown";
}
public function getDrops(Item $item) : array{

View File

@ -23,14 +23,12 @@ declare(strict_types=1);
namespace pocketmine\block;
class StoneButton extends Flowable{
use pocketmine\item\Tool;
class StoneButton extends Button{
protected $id = self::STONE_BUTTON;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
public function getName() : string{
return "Stone Button";
}
@ -39,7 +37,7 @@ class StoneButton extends Flowable{
return 0.5;
}
public function getVariantBitmask() : int{
return 0;
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
}
}

View File

@ -26,7 +26,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
class StoneSlab extends WoodenSlab{
class StoneSlab extends Slab{
const STONE = 0;
const SANDSTONE = 1;
const WOODEN = 2;
@ -38,7 +38,9 @@ class StoneSlab extends WoodenSlab{
protected $id = self::STONE_SLAB;
protected $doubleId = self::DOUBLE_STONE_SLAB;
public function getDoubleSlabId() : int{
return self::DOUBLE_STONE_SLAB;
}
public function getHardness() : float{
return 2;
@ -55,7 +57,7 @@ class StoneSlab extends WoodenSlab{
self::QUARTZ => "Quartz",
self::NETHER_BRICK => "Nether Brick"
];
return (($this->meta & 0x08) > 0 ? "Upper " : "") . $names[$this->meta & 0x07] . " Slab";
return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
}
public function getToolType() : int{
@ -69,8 +71,4 @@ class StoneSlab extends WoodenSlab{
return [];
}
public function getFuelTime() : int{
return 0;
}
}

View File

@ -0,0 +1,44 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
class StoneSlab2 extends StoneSlab{
const TYPE_RED_SANDSTONE = 0;
const TYPE_PURPUR = 1;
protected $id = self::STONE_SLAB2;
public function getDoubleSlabId() : int{
return self::DOUBLE_STONE_SLAB2;
}
public function getName() : string{
static $names = [
self::TYPE_RED_SANDSTONE => "Red Sandstone",
self::TYPE_PURPUR => "Purpur"
];
return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
}
}

View File

@ -52,7 +52,7 @@ class Sugarcane extends Flowable{
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK)));
if(!$ev->isCancelled()){
@ -85,7 +85,7 @@ class Sugarcane extends Flowable{
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
if($this->meta === 0x0F){
for($y = 1; $y < 3; ++$y){
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
if($b->getId() === self::AIR){
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
break;

View File

@ -25,11 +25,7 @@ namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Random;
@ -63,24 +59,13 @@ class TNT extends Solid{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), new CompoundTag("", [
new ListTag("Pos", [
new DoubleTag("", $this->x + 0.5),
new DoubleTag("", $this->y),
new DoubleTag("", $this->z + 0.5)
]),
new ListTag("Motion", [
new DoubleTag("", -sin($mot) * 0.02),
new DoubleTag("", 0.2),
new DoubleTag("", -cos($mot) * 0.02)
]),
new ListTag("Rotation", [
new FloatTag("", 0),
new FloatTag("", 0)
]),
new ByteTag("Fuse", $fuse)
]));
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
$nbt->setByte("Fuse", $fuse);
$tnt->spawnToAll();
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), $nbt);
if($tnt !== null){
$tnt->spawnToAll();
}
}
}

View File

@ -37,7 +37,7 @@ class TallGrass extends Flowable{
$this->meta = $meta;
}
public function canBeReplaced(Block $with = null) : bool{
public function canBeReplaced() : bool{
return true;
}
@ -47,7 +47,7 @@ class TallGrass extends Flowable{
1 => "Tall Grass",
2 => "Fern"
];
return $names[$this->meta & 0x03] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{

View File

@ -28,57 +28,83 @@ use pocketmine\math\Vector3;
abstract class Thin extends Transparent{
public function isSolid() : bool{
return false;
}
protected function recalculateBoundingBox(){
$f = 0.4375;
$f1 = 0.5625;
$f2 = 0.4375;
$f3 = 0.5625;
$flag = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
$flag1 = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
$flag2 = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
$flag3 = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
if((!$flag2 or !$flag3) and ($flag2 or $flag3 or $flag or $flag1)){
if($flag2 and !$flag3){
$f = 0;
}elseif(!$flag2 and $flag3){
$f1 = 1;
}
}else{
$f = 0;
$f1 = 1;
}
if((!$flag or !$flag1) and ($flag2 or $flag3 or $flag or $flag1)){
if($flag and !$flag1){
$f2 = 0;
}elseif(!$flag and $flag1){
$f3 = 1;
}
}else{
$f2 = 0;
$f3 = 1;
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$width = 0.5 - 0.125 / 2;
return new AxisAlignedBB(
$this->x + $f,
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
$this->y,
$this->z + $f2,
$this->x + $f1,
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
$this->y + 1,
$this->z + $f3
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
);
}
protected function recalculateCollisionBoxes() : array{
$inset = 0.5 - 0.125 / 2;
public function canConnect(Block $block){
return $block->isSolid() or $block->getId() === $this->getId() or $block->getId() === self::GLASS_PANE or $block->getId() === self::GLASS;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
if($connectWest or $connectEast){
//X axis (west/east)
$bbs[] = new AxisAlignedBB(
$this->x + ($connectWest ? 0 : $inset),
$this->y,
$this->z + $inset,
$this->x + 1 - ($connectEast ? 0 : $inset),
$this->y + 1,
$this->z + 1 - $inset
);
}
$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
if($connectNorth or $connectSouth){
//Z axis (north/south)
$bbs[] = new AxisAlignedBB(
$this->x + $inset,
$this->y,
$this->z + ($connectNorth ? 0 : $inset),
$this->x + 1 - $inset,
$this->y + 1,
$this->z + 1 - ($connectSouth ? 0 : $inset)
);
}
if(empty($bbs)){
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
return [
new AxisAlignedBB(
$this->x + $inset,
$this->y,
$this->z + $inset,
$this->x + 1 - $inset,
$this->y + 1,
$this->z + 1 - $inset
)
];
}
return $bbs;
}
public function canConnect(Block $block) : bool{
if($block instanceof Thin){
return true;
}
//FIXME: currently there's no proper way to tell if a block is a full-block, so we check the bounding box size
$bbs = $block->getCollisionBoxes();
if(count($bbs) === 1){
return $bbs[0]->getAverageEdgeLength() >= 1;
}
return false;
}
}

View File

@ -50,15 +50,15 @@ class Torch extends Flowable{
$below = $this->getSide(Vector3::SIDE_DOWN);
$side = $this->getDamage();
$faces = [
0 => 0,
1 => 4,
2 => 5,
3 => 2,
4 => 3,
5 => 0
0 => Vector3::SIDE_DOWN,
1 => Vector3::SIDE_WEST,
2 => Vector3::SIDE_EAST,
3 => Vector3::SIDE_NORTH,
4 => Vector3::SIDE_SOUTH,
5 => Vector3::SIDE_DOWN
];
if($this->getSide($faces[$side])->isTransparent() === true and !($side === 0 and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
if($this->getSide($faces[$side])->isTransparent() === true and !($side === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;

View File

@ -53,7 +53,7 @@ class Trapdoor extends Transparent{
return 3;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$damage = $this->getDamage();

View File

@ -31,7 +31,7 @@ use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
class Vine extends Transparent{
class Vine extends Flowable{
const FLAG_SOUTH = 0x01;
const FLAG_WEST = 0x02;
const FLAG_NORTH = 0x04;
@ -43,10 +43,6 @@ class Vine extends Transparent{
$this->meta = $meta;
}
public function isSolid() : bool{
return false;
}
public function getName() : string{
return "Vines";
}
@ -71,106 +67,126 @@ class Vine extends Transparent{
return true;
}
public function onEntityCollide(Entity $entity){
public function canBeReplaced() : bool{
return true;
}
public function onEntityCollide(Entity $entity) : void{
$entity->resetFallDistance();
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
$f1 = 1;
$f2 = 1;
$f3 = 1;
$f4 = 0;
$f5 = 0;
$f6 = 0;
$minX = 1;
$minY = 1;
$minZ = 1;
$maxX = 0;
$maxY = 0;
$maxZ = 0;
$flag = $this->meta > 0;
if(($this->meta & self::FLAG_WEST) > 0){
$f4 = max($f4, 0.0625);
$f1 = 0;
$f2 = 0;
$f5 = 1;
$f3 = 0;
$f6 = 1;
$maxX = max($maxX, 0.0625);
$minX = 0;
$minY = 0;
$maxY = 1;
$minZ = 0;
$maxZ = 1;
$flag = true;
}
if(($this->meta & self::FLAG_EAST) > 0){
$f1 = min($f1, 0.9375);
$f4 = 1;
$f2 = 0;
$f5 = 1;
$f3 = 0;
$f6 = 1;
$minX = min($minX, 0.9375);
$maxX = 1;
$minY = 0;
$maxY = 1;
$minZ = 0;
$maxZ = 1;
$flag = true;
}
if(($this->meta & self::FLAG_SOUTH) > 0){
$f3 = min($f3, 0.9375);
$f6 = 1;
$f1 = 0;
$f4 = 1;
$f2 = 0;
$f5 = 1;
$minZ = min($minZ, 0.9375);
$maxZ = 1;
$minX = 0;
$maxX = 1;
$minY = 0;
$maxY = 1;
$flag = true;
}
//TODO: Missing NORTH check
if(!$flag and $this->getSide(Vector3::SIDE_UP)->isSolid()){
$f2 = min($f2, 0.9375);
$f5 = 1;
$f1 = 0;
$f4 = 1;
$f3 = 0;
$f6 = 1;
$minY = min($minY, 0.9375);
$maxY = 1;
$minX = 0;
$maxX = 1;
$minZ = 0;
$maxZ = 1;
}
return new AxisAlignedBB(
$this->x + $f1,
$this->y + $f2,
$this->z + $f3,
$this->x + $f4,
$this->y + $f5,
$this->z + $f6
$this->x + $minX,
$this->y + $minY,
$this->z + $minZ,
$this->x + $maxX,
$this->y + $maxY,
$this->z + $maxZ
);
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
//TODO: multiple sides
if($blockClicked->isSolid()){
$faces = [
2 => self::FLAG_SOUTH,
3 => self::FLAG_NORTH,
4 => self::FLAG_EAST,
5 => self::FLAG_WEST
];
if(isset($faces[$face])){
$this->meta = $faces[$face];
$this->getLevel()->setBlock($blockReplace, $this, true, true);
return true;
}
if(!$blockClicked->isSolid() or $face === Vector3::SIDE_UP or $face === Vector3::SIDE_DOWN){
return false;
}
return false;
$faces = [
Vector3::SIDE_NORTH => self::FLAG_SOUTH,
Vector3::SIDE_SOUTH => self::FLAG_NORTH,
Vector3::SIDE_WEST => self::FLAG_EAST,
Vector3::SIDE_EAST => self::FLAG_WEST
];
$this->meta = $faces[$face] ?? 0;
if($blockReplace->getId() === $this->getId()){
$this->meta |= $blockReplace->meta;
}
$this->getLevel()->setBlock($blockReplace, $this, true, true);
return true;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$sides = [
1 => 3,
2 => 4,
4 => 2,
8 => 5
self::FLAG_SOUTH => Vector3::SIDE_SOUTH,
self::FLAG_WEST => Vector3::SIDE_WEST,
self::FLAG_NORTH => Vector3::SIDE_NORTH,
self::FLAG_EAST => Vector3::SIDE_EAST
];
if(!isset($sides[$this->meta])){
return false; //TODO: remove this once placing on multiple sides is supported (these are bitflags, not actual meta values
$meta = $this->meta;
foreach($sides as $flag => $side){
if(($meta & $flag) === 0){
continue;
}
if(!$this->getSide($side)->isSolid()){
$meta &= ~$flag;
}
}
if(!$this->getSide($sides[$this->meta])->isSolid()){ //Replace with common break method
$this->level->useBreakOn($this);
if($meta !== $this->meta){
if($meta === 0){
$this->level->useBreakOn($this);
}else{
$this->meta = $meta;
$this->level->setBlock($this, $this);
}
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){

View File

@ -34,19 +34,11 @@ class WallSign extends SignPost{
}
public function onUpdate(int $type){
$faces = [
2 => 3,
3 => 2,
4 => 5,
5 => 4
];
if($type === Level::BLOCK_UPDATE_NORMAL){
if(isset($faces[$this->meta])){
if($this->getSide($faces[$this->meta])->getId() === self::AIR){
$this->getLevel()->useBreakOn($this);
}
return Level::BLOCK_UPDATE_NORMAL;
if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
$this->getLevel()->useBreakOn($this);
}
return Level::BLOCK_UPDATE_NORMAL;
}
return false;
}

View File

@ -44,7 +44,7 @@ class Water extends Liquid{
return 2;
}
public function onEntityCollide(Entity $entity){
public function onEntityCollide(Entity $entity) : void{
$entity->resetFallDistance();
if($entity->fireTicks > 0){
$entity->extinguish();

View File

@ -45,7 +45,7 @@ class WaterLily extends Flowable{
return 0.6;
}
protected function recalculateBoundingBox(){
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
$this->x + 0.0625,
$this->y,

View File

@ -52,7 +52,7 @@ class Wood extends Solid{
self::BIRCH => "Birch Wood",
self::JUNGLE => "Jungle Wood"
];
return $names[$this->meta & 0x03];
return $names[$this->getVariant()] ?? "Unknown";
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{

View File

@ -36,6 +36,6 @@ class Wood2 extends Wood{
0 => "Acacia Wood",
1 => "Dark Oak Wood"
];
return $names[$this->meta & 0x03] ?? "Unknown";
return $names[$this->getVariant()] ?? "Unknown";
}
}

View File

@ -23,11 +23,21 @@ declare(strict_types=1);
namespace pocketmine\block;
class WoodenButton extends StoneButton{
use pocketmine\item\Tool;
class WoodenButton extends Button{
protected $id = self::WOODEN_BUTTON;
public function getName() : string{
return "Wooden Button";
}
public function getHardness() : float{
return 0.5;
}
public function getToolType() : int{
return Tool::TYPE_AXE;
}
}

View File

@ -0,0 +1,61 @@
<?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/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
class WoodenFence extends Fence{
const FENCE_OAK = 0;
const FENCE_SPRUCE = 1;
const FENCE_BIRCH = 2;
const FENCE_JUNGLE = 3;
const FENCE_ACACIA = 4;
const FENCE_DARKOAK = 5;
protected $id = self::FENCE;
public function getHardness() : float{
return 2;
}
public function getToolType() : int{
return Tool::TYPE_AXE;
}
public function getName() : string{
static $names = [
self::FENCE_OAK => "Oak Fence",
self::FENCE_SPRUCE => "Spruce Fence",
self::FENCE_BIRCH => "Birch Fence",
self::FENCE_JUNGLE => "Jungle Fence",
self::FENCE_ACACIA => "Acacia Fence",
self::FENCE_DARKOAK => "Dark Oak Fence"
];
return $names[$this->getVariant()] ?? "Unknown";
}
public function getFuelTime() : int{
return 300;
}
}

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