Compare commits

...

610 Commits

Author SHA1 Message Date
2034caf71c Merge branch 'mcpe-1.4.0-alpha12' into release/alpha12 2018-05-17 18:38:58 +01:00
89ccac7a8c updated blockIDs table 2018-05-17 16:17:26 +01:00
f6e71d8296 Protocol changes for 1.4.0 release
this is nearly the same as 1.5.0.0, except the skin packet premium boolean has been dropped.

This isn't production ready yet because the blockID table needs updating (waiting on MrARM to fix his script for that).
2018-05-17 10:36:16 +01:00
b333a0e24c PlayStatusPacket: add new constant 2018-05-17 10:33:18 +01:00
5b6762d0d5 Fixed lang submodule version 2018-05-09 14:53:22 +01:00
68638f9779 Fixed translations
Apparently the translation type doesn't translate unless this flag is set now...
2018-05-04 22:14:02 +01:00
8228774ad4 Remove extra data, this time without API breaks
this is necessary because the next MCPE release will probably be made before the next PM release.
2018-05-02 12:08:44 +01:00
2a54726905 Updated runtimeIDs table
from https://github.com/MCMrARM/minecraft-block-ids/blob/master/blocks_270.json
2018-05-02 12:03:29 +01:00
8b225fc4ef New entity metadata flags and properties 2018-05-02 12:03:29 +01:00
a014b44b69 New PlayerActionPacket constants
anyone know what these are for? something to do with riptide but I didn't manage to find out what...
2018-05-02 12:03:29 +01:00
c7544c1d25 AvailableCommandsPacket: update arg types 2018-05-02 12:03:29 +01:00
eb28622823 Protocol changes for 1.5.0.0
this feels so strange to type... can we ditch the versioning system already?
2018-05-02 12:03:29 +01:00
68494f1c0d CraftingDataPacket: decode chemistry recipes correctly 2018-05-02 12:03:29 +01:00
27ea0d360f updated block IDs table
minified, from https://github.com/MCMrARM/minecraft-block-ids/blob/master/blocks_260.json
2018-05-02 12:03:29 +01:00
d384df1f2e fixed some mistakes in the protocol 2018-05-02 12:03:29 +01:00
fe8102c062 Silence another stupid spam bug 2018-05-02 12:03:29 +01:00
8b15d85469 bump versions for 1.2.20.1 beta 2018-05-02 12:03:29 +01:00
a5ba716232 Updated block ID mappings for 1.2.14 (thanks again MrARM) 2018-05-02 12:03:29 +01:00
db432bb024 Found some things in new packets 2018-05-02 12:03:29 +01:00
91486a23a5 some changes for 1.2.14.2 beta 2018-05-02 12:03:29 +01:00
c276ef2b7f Updated dependency versions 2018-04-13 20:09:18 +01:00
5138bdc4bd Updated DevTools submodule 2018-04-13 17:38:51 +01:00
a30a157d8c API bump to 3.0.0-ALPHA12
Yes, I am not happy about this either. new-versioning has issues, and there hasn't been enough development and testing on it.
I didn't want to delay release to cram in a half-baked new versioning system, and it's ended up delayed anyway and new-versioning is still half-baked.
we're overdue a new release, so here it is.
2018-04-13 13:31:15 +01:00
e565cdeea4 Tile: remove unnecessary createAdditionalNBT() things
these things are filled in by the tiles' constructors anyway.
2018-04-13 11:50:04 +01:00
556a465c05 Container tiles: remove unnecessary ListTag Items creation
the existence of this tag is checked for anyway.
2018-04-13 11:27:11 +01:00
280f2b7259 always loose imports... 2018-04-13 11:25:52 +01:00
933b0e8b41 Furnace: cleanup, stop abusing NBT, stop spamming packets 2018-04-13 11:22:47 +01:00
58279d4cfe NetworkBinaryStream: fixed not decoding items with negative IDs correctly
negative IDs are used for new block-items.
2018-04-11 13:01:41 +01:00
1e21066c1c Server: remove redundant == true from setConfigBool() 2018-04-10 12:22:21 +01:00
76854da7ba Command: remove dead field 2018-04-10 12:11:27 +01:00
46cbcb0c42 Fixed fire with no nearby flammable blocks burning for too long 2018-04-10 10:07:14 +01:00
af9b0b019d Added BlockBurnEvent 2018-04-10 10:04:11 +01:00
7db8845375 Fire has a 1/3 chance of aging on a random or scheduled tick 2018-04-10 09:59:54 +01:00
f47f593555 Level: Removed fire hack from destroyBlockInternal()
this was causing unexpected behaviour particularly on burning trees, whereby fire would be unconditionally extinguished if the block below it was removed.
2018-04-10 09:59:40 +01:00
691df5c11d FlintSteel: remove instanceof Solid check
This makes the behaviour match vanilla. This will now allow Fire block itself to handle deletion of itself when the area is not suitable (now that the logic is implemented in Fire for this).

This allows attempting to place in invalid conditions, which is as expected. This will produce the sound and flash as per vanilla, as the fire extinguishes itself.
2018-04-10 09:59:27 +01:00
9a1d3aec6b Flammable blocks adjacent to fire now burn away
There are some strange bugs with blockupdating causing invisible client-side-only fires that need to be investigated.
2018-04-10 09:59:10 +01:00
670a53ba3b Fire: fixed logic of extinguishing 2018-04-10 09:58:58 +01:00
f22ad14c67 Block: added isFlammable() 2018-04-10 09:58:35 +01:00
64540f36be Block: added burnsForever() 2018-04-10 09:58:21 +01:00
e66b1953de Block: added flame encouragement and flammability properties 2018-04-10 09:58:08 +01:00
aa6666872a BlockFactory: added a hack for weird air blocks with non-zero damage values
I don't know what causes this to occur, but they should never have non-zero damage values, so we discard the metadata.
2018-04-09 16:35:31 +01:00
646455f6e8 fixed painting particles, removed DestroyParticle
it didn't last long because they changed how this works... yuk
2018-04-09 16:26:15 +01:00
05a1e61e5b Painting: polyfill height and width 2018-04-09 16:20:46 +01:00
5f52e00213 Fixed plugin loaders trying to load plugins they aren't able to load
closes #2125

This is an API break for things implementing the PluginLoader interface.
2018-04-09 15:54:20 +01:00
476ac39988 update PHP version requirements in composer files 2018-04-09 15:50:55 +01:00
5f1ae1059e Move min required PHP version to 7.2.0 2018-04-09 15:37:56 +01:00
08d8adae5b fixup some ResourcePack TODOs 2018-04-07 13:09:44 +01:00
8d988af7db EntityLink: added type constants 2018-04-07 11:35:36 +01:00
db5890fddb Rename more unknown things in the protocol 2018-04-07 11:35:35 +01:00
5b532fdcf5 Clean up on AddHangingEntityPacket and AddPaintingPacket
AddPainting is a subclass of AddHangingEntity in vanilla.
2018-04-07 11:35:35 +01:00
e85fc54037 LevelSoundEventPacket: found unknown field
wtf mojang
2018-04-07 11:35:35 +01:00
7fb237938c EntityLink: rename unknown field
close #1465
2018-04-07 11:35:35 +01:00
9a5f9c8586 PlayerListPacket: fixup on platformChatId stuff 2018-04-07 11:35:35 +01:00
4b16be7e0b PlayerListEntry: remove leftover TODO 2018-04-07 11:35:35 +01:00
47faf5a994 Human: Add support for 128x128 skins in isValidSkin() (#2140) 2018-04-07 09:00:08 +01:00
3f31f6d310 TimeCommand: Use Level constant instead of hardcoded value 2018-04-05 15:41:59 +01:00
c06c1c7ce0 Human: Added a hack for nametags
Apparently NAMETAG metadata is useless in AddPlayerPacket now, so it has to be sent separately.
2018-04-05 11:56:44 +01:00
a889a0e517 Workaround for player hitbox bug on respawn
this happens when a player respawns before their death animation ends. I don't know why, but their bounding box height suddenly becomes zero. This solves the bug by simply resending the height and width properties to viewers on respawn.

Closes #2135.
2018-04-04 20:11:16 +01:00
9ed0d9d36f added some data properties 2018-04-04 19:40:12 +01:00
3134fa2744 Fixed FloatingTextParticle YET AGAIN
how many fucking ways can you break nametags Mojang???
2018-04-04 16:59:39 +01:00
2660448601 Crafting: Match recipe based only on transaction inputs/outputs
As of 1.2.13 release, the client now skips the crafting grid step when it crafts with right-click on the recipe book. This means that we can't validate crafting based on the crafting grid contents anymore. The only way to do it now is to use the inputs and outputs calculated by the transaction balance.
2018-04-04 12:48:17 +01:00
eb354916d4 CraftingTransaction: simplifiy repetition calculation handling 2018-04-04 12:18:24 +01:00
033b44df5a CraftingTransaction: Start from pre-computed iteration count for input matching
This will be faster to bail out on failures.
2018-04-04 12:15:46 +01:00
ef2dd1de92 Inventory: Use exceptions to report back why a transaction failed
Returning false all the time could mean any one of a range of things. Throwing exceptions is better in that it allows us to catch them and see what actually broke.
2018-04-04 12:11:24 +01:00
5b7b2dd0e2 Merge changes from ALPHA11 for 1.2.13 2018-04-04 11:31:39 +01:00
3a10df634b Protocol bump for release 2018-04-04 11:13:36 +01:00
f1aecc3a71 Updated block IDs json from release (thanks MrARM) 2018-04-04 11:09:12 +01:00
42d04a4418 Allow use of 128x128 skins for last beta build (#2123) 2018-04-04 11:03:51 +01:00
3fe4ebc301 Found more unknown things 2018-04-04 11:03:36 +01:00
d97abfaa7b Found some unknown things 2018-04-04 11:03:25 +01:00
526f05631e fix metadata properties for new beta
there are more things than this, but I don't have time to figure them all out.
2018-04-04 11:03:05 +01:00
ebaef89e06 bump 2018-04-04 11:02:19 +01:00
6ab0cff9d3 Bump for 1.2.13.10
doesn't appear that anything of interest has changed
2018-04-04 11:01:46 +01:00
ae31ce1d25 LevelSoundEventPacket: updated sounds constants 2018-04-04 11:01:29 +01:00
a1cf5dbd1e fix doc inconsistency 2018-04-04 11:01:14 +01:00
c86132028e BlockFactory: add new "dynamic" fake runtime IDs for unknown legacy ID/meta combinations
This is basically how blockstate discovery would actually work in the full-blown system. This maps blocks with unrecognized blockstates to static runtimeIDs not known to the client.

This means that all blocks which don't have corresponding runtimeIDs in the new system will translate to update! blocks instead.

Mojang do this differently: they try to a) match id+meta, if that fails b) match id+0, and if that fails, then replace with update! block runtime ID. I can't do that here because I need to be able to convert both ways. They only need to be able to convert from legacy -> new.
2018-04-04 11:00:58 +01:00
5ce55bd3b0 duct tape for block ID remapping 2018-04-04 11:00:39 +01:00
c81f178cdb fix skins on 1.2.13.5
this is not the full changeset and more things are needed!
2018-04-04 10:59:09 +01:00
fc795b80ae Protocol changes for 1.2.10 2018-04-04 10:58:49 +01:00
99134de6b6 Updated NBT dependency
this needs further changes (particularly to Furnace) to stop things abusing NBT for runtime data handling, otherwise performance is going to drop off a cliff.
2018-04-04 10:29:32 +01:00
1fc388d6de DataPropertyManager: fix an unnecessary FQN 2018-04-02 12:34:05 +01:00
eba1ca030c Fix variadic type docs ...again
PhpStorm changed its mind how it wants these documenting in 2018.1, and apparently the correct syntax follows the PHP code.
2018-04-02 12:33:24 +01:00
8ce0fab8cc Remove unused imports 2018-04-02 12:26:13 +01:00
5ed2d6022c GiveCommand: don't catch Throwables
this caused me to think a thyntax error in my code was a syntax error in the NBT I was trying to parse.
2018-04-01 12:17:17 +01:00
37d085f793 UPnP: error messages on failure to portforward instead of silently failing 2018-03-31 12:51:17 +01:00
69c54de460 UPnP: remove useless 'or false' 2018-03-31 12:42:11 +01:00
b9d3bd22a3 Player: fixed getLastPlayed() being useless
this should only be set on quit, not on join.
2018-03-31 10:44:59 +01:00
d4d57aa9ea Merge branch 'feature/xp-event' 2018-03-30 12:46:53 +01:00
4ce1f228e6 Player: removed checkBlockCollision() override 2018-03-30 12:23:00 +01:00
4b03dbebba Entity: use temporalVector in checkBlockCollision() instead of creating a new Vector3 2018-03-30 12:21:37 +01:00
1d5978df98 Fixed falling blocks getting moved by currents, closes #2080 2018-03-30 12:20:59 +01:00
5d32587cf7 DeadBush: match placement condition with break condition, fixes #2116 2018-03-30 11:54:57 +01:00
d53258c943 EffectCommand: restrict range of values for duration, fixes #2055 2018-03-30 11:51:20 +01:00
773f760fff VanillaCommand: added getBoundedInt() 2018-03-30 11:48:42 +01:00
c20b16a0fe Living: fixed damage resistance negating >100% of damage, closes #2052 2018-03-30 11:31:43 +01:00
b151cb26a5 Fix deprecated event message (#2127) 2018-03-30 11:09:24 +01:00
49622cc2a5 NetworkBinaryStream: simplify read of canPlaceOn and canDestroy lists 2018-03-30 11:07:29 +01:00
56328f66a7 InventoryAction: remove useless creationTime field 2018-03-29 12:20:13 +01:00
f41a731493 DropItemAction: don't require a source item in constructor 2018-03-29 12:18:19 +01:00
ec332e3e60 Fill null UUIDs in CraftingDataPacket, remove all UUID things from CraftingRecipe
This allows deleting lots of code, and additionally provides a huge reduction in the compressed size of CraftingDataPacket. Since we don't care about these UUIDs (they are only used in CraftingEventPacket, which is broken and unused in PM) we fill them with zeros instead.
2018-03-29 12:05:23 +01:00
a1090623a2 CraftingRecipe: added methods to allow recipes to derive outputs from inputs
this will be needed for special recipes like shulker-box and banner recipes.
2018-03-29 12:05:22 +01:00
8572e9e560 Crafting: nuke
This commit brings in a much-needed rewrite of crafting transaction handling.

The following classes have been removed:
- CraftingTransferMaterialAction
- CraftingTakeResultAction

The following classes have significant changes:
- CraftingTransaction
	- All API methods have been removed and are now handled in CraftItemEvent
- CraftItemEvent
	- added the following:
		- getInputs()
		- getOutputs()
		- getRepetitions() (tells how many times a recipe was crafted in this event)
- Recipe interface:
	- Removed getResult() (individual recipes may handle this differently)
- CraftingRecipe interface
	- removed the following:
		- matchItems()
		- getExtraResults()
		- getAllResults()
	- added the following
		- getResults()
		- getIngredientList() : Item[], which must return a 1D array of items that should be consumed (wildcards accepted).
		- matchesCraftingGrid(CraftingGrid)
- ShapedRecipe
	- constructor now accepts string[], Item[], Item[]
- ShapelessRecipe
	- constructor now accepts Item[], Item[]
2018-03-29 12:05:22 +01:00
bc836aaec1 Make CraftingManager::sort() more cool with spaceship operators 😎 2018-03-29 11:45:12 +01:00
145a4fad0f CraftingManager: Make sort() static
this doesn't need access to $this
2018-03-29 11:45:06 +01:00
08c48d8145 CraftingRecipe: removed requiresCraftingTable()
the requirement for a crafting table is determined by the number of ingredients can fit on the grid (shapeless) or the max height and width (shaped). It's impossible to craft a big recipe with a small crafting table simply because you're not able to put the required resources into the grid.
2018-03-29 11:43:31 +01:00
81ecb56095 ShapedRecipe: fixed bug in constructor 2018-03-29 11:32:39 +01:00
a6d7365a28 Moved CraftingManager init to its own function
this allows the crafting manager to be re-initialized on the fly without recreating it.
2018-03-29 11:32:22 +01:00
1f4f8ab3f0 Inventory: Removed BigCraftingGrid, allow arbitrary size parameter
This is more flexible and requires less classes.
2018-03-29 11:24:28 +01:00
1420cd1fa5 InventoryTransaction: Added a more robust action flattening mechanism
This now handles the case where there are multiple options which could be taken, and opts for the first result which successfully ties all the actions together. Previously it would be entirely down to chance (ordering) whether the actions would get ordered successfully.
2018-03-29 11:23:52 +01:00
30a83544a0 don't break double chests 2018-03-27 10:23:18 +01:00
7e20385bdb BaseInventory: improved performance of getContents()
this old code is extremely inefficient. This showed up distinctly in my crafting bruteforce benchmarks, where I discovered that getContents() accounted for the vast majority of the time taken to match shaped recipes.
2018-03-27 10:13:55 +01:00
c7e803372c Inventory: added API method isSlotEmpty() 2018-03-26 09:24:00 +01:00
cf3638ad8d BaseInventory: fixed doc comment for slots field 2018-03-26 09:22:38 +01:00
0dd8fd2651 CraftingTransaction: fixed ingredient map trimming (again)
closes #2118
2018-03-25 13:46:39 +01:00
c0c684b12e Removed the need for paintings to check for destruction on schedule
Since we have a mechanism for triggering things on entities anyway, make use of it to do more than just forcing movement updates.
2018-03-25 13:15:10 +01:00
924334a776 Painting: fixed performance bug, close #2117 2018-03-25 13:06:02 +01:00
be7c27f60d Player: explicitly load chunk for player to spawn, fixes #2115
this is an ugly fix, but it'll do for now...
2018-03-25 12:45:51 +01:00
2b37b4a659 Player: close session in interface right at the top
I don't know why this would be anywhere _but_ here...
2018-03-24 13:00:44 +00:00
a4c50d3204 Remove unused imports 2018-03-24 11:59:15 +00:00
eb9f60f41c Entity: some minor cleanup to constructor 2018-03-24 11:52:23 +00:00
071aa44d29 Player: fixed facepalm 2018-03-24 11:05:03 +00:00
25089f5e70 Player: use setPosition() when jumping to off position 2018-03-24 10:58:31 +00:00
22dd8faf1d Player: don't jump to bad position when reverting movement 2018-03-24 10:57:59 +00:00
7354a55af8 Player: use vector methods for calculating diff on move 2018-03-24 10:50:09 +00:00
611f5d684b Player: removed redundant isFirst check for movement
Since the addition of resetLastMovements(), this code is useless.

Additionally, it doesn't make sense to ignore the first movement, because the first movement still _moves the player_ from point A to point B.
2018-03-24 10:40:30 +00:00
9a099d3f5d Player: remove a couple of useless lines from respawn()
teleport() handles these already.
2018-03-24 10:34:30 +00:00
5eb1ee3416 Position: use setLevel() in constructor to validate level 2018-03-24 10:02:10 +00:00
e4b6a18404 Player: removed redundant proxy function 2018-03-23 19:56:35 +00:00
364d278714 Player: removed useless condition for chunk ordering
This just causes it to attempt to spam chunk orders prior to the player spawning. It won't succeed, because the render distance is zero.

The other time this could occur is when teleporting into an unloaded chunk, but it's not necessary to continually spam chunk orders in that case, especially since chunk orders are done on teleport anyway.
2018-03-23 19:48:33 +00:00
c464d39401 Player: Order chunks immediately on receiving chunk radius request 2018-03-23 19:44:03 +00:00
a185b78486 Player: fixed logic of move-into-bad-chunk checks
particularly the hack with chunk switching was causing unexpected behaviour wrt. invisible players.
2018-03-23 19:34:45 +00:00
c19cf22ac5 Fixed #2110 2018-03-21 21:52:55 +08:00
d2fb32c28a PluginManager: added event call recursion limit, closes #2109
This prevents unexplained segfaults on accidental event call recursion by limiting the max depth of event call stack to 50. If another event attempts to be called, an exception will be thrown.
2018-03-21 10:40:08 +00:00
49fbbea7bf Implemented event handler inheritance, allow registering handlers for any valid event (#1792)
* Event handlers always handle subclass events. public static $handlerList no longer required.
* Removed $handlerList declarations
* HandlerList cleanup: Removed HandlerList->handlers and related bake methods
* Removed obsolete Event->getHandlers()
* EventPriority: Added fromString()
* PluginManager: throw exceptions on registering handlers with invalid priorities

This allows specifying a handler of `EntityDamageEvent` which will handle any instanceof it (as per current behaviour), AND also now allows specifying a handler specifically for `EntityDamageByEntityEvent`, which only handles `EntityDamageEvent`.

This was not previously possible due to limitations in the way handlers were registered.

Abstract events may not be handled unless they declare the `@allowHandle` PhpDoc tag.
2018-03-20 17:05:09 +00:00
1648fff916 Replaced Position->getLevel() null checks with isValid() 2018-03-20 11:10:36 +00:00
73e09392b6 Timings: Clean up some terrible code, move namespaces 2018-03-19 19:05:51 +00:00
209e28dfe5 Level: Removed MovingObjectPosition 2018-03-19 16:58:45 +00:00
ac5a91b67e Cleaned up bool comparison mess 2018-03-19 14:10:55 +00:00
24c5d7557e Updated PreProcessor submodule 2018-03-19 12:44:54 +00:00
3d89bf5693 Updated PocketMine Math dependency 2018-03-18 18:08:24 +00:00
e48ec9fb71 Ore: replaced a sub-optimal multiply()->divide() on Vector2 2018-03-18 18:06:04 +00:00
95606b6e04 Generator: fixed a couple of hardcoded block IDs 2018-03-18 18:03:23 +00:00
c243daabe1 DumpMemoryCommand: removed token annoyance, use date/time to identify memory dumps by default 2018-03-18 12:17:31 +00:00
357674cb54 DumpMemoryCommand: move memory dumps to their own folder
this is for ease of ignoring in IDEs.
2018-03-18 12:06:15 +00:00
9d5eeb328e Player: cleanup how login verification is handled
Players are now only considered authenticated if they have an XUID AND have a keychain with a Mojang signature in it somewhere.
2018-03-17 18:44:26 +00:00
b2ee6b2ca5 Player: consolidate and add type docs for fields 2018-03-17 17:42:01 +00:00
2860e9e8ee Player: remove clientSecret (useless) 2018-03-17 16:44:34 +00:00
e82073834f Player: protect some fields 2018-03-17 16:43:34 +00:00
7fcc538a75 Level: clone Block object passed to setBlock() if set successfully
closes #2042
2018-03-17 16:35:10 +00:00
7f6b8ad7c2 Moved \pocketmine\math to a separate library 2018-03-17 12:45:55 +00:00
313b224bec Updated Composer dependency names and repo URLs 2018-03-17 12:19:14 +00:00
d12b1d3e07 Updated RakLib dependency 2018-03-17 11:27:56 +00:00
eeeef8df51 Fixed concrete powder not falling 2018-03-16 16:43:47 +00:00
9c786089f8 Level: don't create objects which aren't going to be used 2018-03-16 13:00:16 +00:00
e3cae7364f Level: don't send empty block update batches 2018-03-16 12:58:46 +00:00
d542bbc736 Level: Fixed race condition between direct and batched block updating
This happened when a block was set into the world with a direct update, when an entry for that block was already present in the changedBlocks map. This fixes the bug by removing the entry from the changedBlocks map to avoid sending outdated block updates in batches.
2018-03-16 11:44:57 +00:00
e88541b269 TeleportCommand: add /teleport alias 2018-03-16 10:49:57 +00:00
fdad965db8 Player: if command has aliases, add command name as alias if not found
closes #2106

For some strange reason, using aliases overwrites the original command name instead of coexisting with it. This is rather astonishing behaviour, and probably a bug in the client. However, this workaround is the same thing vanilla does (see /tp in vanilla).
2018-03-16 10:41:00 +00:00
dd844f7ad3 Position: call parent constructor 2018-03-15 10:29:21 +00:00
596c8a7b4f Tile: Removed cyclic dependence on Chunks
Chunks were used by tiles for a couple of things:
- 1. for coordinates - which can be gotten using bitshifts
- 2. setChanged() - which is unnecessary as seen in the previous commit

Removing this circular dependency was actually remarkably easy to do.
2018-03-15 10:21:42 +00:00
9c598d1345 Spawnable: don't mark chunk as changed onChanged()
this is unnecessary because a chunk is considered "changed" if it has tiles on it anyway.
2018-03-15 09:48:28 +00:00
a2af838b1d Level: fixed autosave not kicking in when entities are updated in a chunk (e.g. moving, dying, spawning) 2018-03-15 09:46:04 +00:00
bf97eab98f Block: remove redundant local variable from collidesWithBB() 2018-03-15 09:38:14 +00:00
a9a55e9558 GlowingRedstoneOre: fixed infinite recursion and crash on block update
closes #2104

The inheritance of GlowingRedstoneOre from RedstoneOre maybe should be reconsidered. They only share properties in reality.
2018-03-15 09:24:48 +00:00
95fb1d1602 AxisAlignedBB: added epsilon for floating-point comparison (#2101)
This fixes bugs where, for example, one cannot place a block below oneself at y=7.0.
2018-03-14 16:52:05 +00:00
fa644edef3 Entity: removed redundant return values for move() 2018-03-14 13:39:23 +00:00
ddc9dca8b4 Player: fixed being able to eat cake in creative
closes #2070
2018-03-13 18:32:08 +00:00
86eee429bb Block: Split onUpdate() into several functions, removed Level::BLOCK_UPDATE_* constants
This allows the removal of lots of ugly code, and also exposes lots of similarities with how this update type was handled. This can be further improved in the future to more generically handle cases.

I realized in the process of changing this, that it might actually be simpler to treat to treat scheduled updates and neighbour updates as one and the same. They use the same mechanism for being saved on chunks (TileTicks),
and doing that would make updating only require one queue instead of two.

RedstoneOre: use onActivate() to trigger glowing
this is not technically correct behaviour, but this preserves the current behaviour.
2018-03-13 17:29:46 +00:00
4f20a504e3 Level: remove dead function
this is handled by a queue now instead of ondemand, to avoid recursion bugs.
2018-03-13 11:46:23 +00:00
6a1f8640f6 Cactus: fix bugs in local block updating 2018-03-13 11:40:45 +00:00
8a0414f306 Server: Changed logic of isLevelGenerated() to prevent astonishing behaviour
Previously to this, a level would be considered "not generated" if no level providers registered as valid for that directory. This caused astonishing behaviour when the user's world has, for example, a mixture of .mca and .mcr region files - the world would instead get _re-generated_ according to the default level format, which might or might not load the existing regions depending on the format used for generation. This behaviour is utterly absurd.

This changes the behaviour of the generated check to check for a non-empty directory in the given path. Non-empty directories without recognized world files in them are now considered to have an unknown format.
2018-03-12 10:24:59 +00:00
d478661961 Minor cleanup to LevelDB constructor 2018-03-11 18:15:20 +00:00
b8064aa45c LevelDB: fixed more usages of CompoundTag ArrayAccess API 2018-03-11 17:55:35 +00:00
00f596c4f8 Level: typehint hashing methods 2018-03-11 16:42:57 +00:00
3f7b14bf59 Level: Remove dead generator leftovers
This is all handled by the population mechanism now. Nothing uses these things anymore since years.
2018-03-11 13:56:41 +00:00
ba0a256834 SplashPotion: fix max stack size 2018-03-11 13:43:45 +00:00
f2f8c235e7 Explosion: add exception throws for bad arguments 2018-03-11 13:06:29 +00:00
69b3bb183d Explosion: typehints and docs 2018-03-11 13:02:46 +00:00
cd35bd6872 git diff-tree --check $(git hash-object -t tree /dev/null) HEAD 2018-03-11 10:31:25 +00:00
d09a43cfef Added PlayerExperienceChangeEvent 2018-03-10 20:04:36 +00:00
40b995a435 Level: Fixed botch-job PR #2089
@zKoz210 Do not contribute to this repository again without first testing your changes.
2018-03-10 19:08:30 +00:00
590826b9bd Player: Disallow modifying NBT of tiles inside spawn protection 2018-03-10 18:19:17 +00:00
a5e87484d9 Player: removed superfluous null-check from setMotion()
this is already checked by broadcastMotion().
2018-03-10 17:08:00 +00:00
8a86e0825b Entity: Moved PrimedTNT and FallingSand to object\PrimedTNT and object\FallingBlock 2018-03-10 16:25:07 +00:00
b39bbffdc5 Entity: Moved and renamed entity\Item to entity\object\ItemEntity 2018-03-10 12:36:46 +00:00
bd3d2451bc Level: Added getRandomTickedBlocks() function (#2089) 2018-03-10 11:32:01 +00:00
606407933e ProjectileItem: fixed error when projectile entity is null 2018-03-10 10:59:22 +00:00
ad09e8c8d0 Implemented Bottle o' Enchanting 2018-03-10 10:53:03 +00:00
486edf0e55 Projectile: remove redundant parent onHit() calls 2018-03-10 10:31:24 +00:00
2ee01eb195 Projectile: fix stupidity with collided block IDs 2018-03-09 21:50:27 +00:00
9098502199 Item: added some foods, cleaned up Fish abomination
@PEMapModder GET A CLIENT ALREADY
2018-03-09 19:54:42 +00:00
b130374e46 EnderPearl: fixed max stack size 2018-03-09 19:19:21 +00:00
31106bc227 ItemFactory: Register Dragon's Breath item
this is only used for brewing, it doesn't need anything special.
2018-03-09 19:13:30 +00:00
cc1a3d695f Implemented basic Ender Pearls
this doesn't have full functionality yet (like spawning endermites) because some things aren't implemented yet.
2018-03-09 19:05:14 +00:00
8020780fc5 LevelEventPacket: added enderman teleport particle cloud constant 2018-03-09 17:20:35 +00:00
2f266a5922 Player: added a server-side forced cooldown mechanism
This is necessary because the stupid client constantly spams right-click actions if you carry on trying to eat/throw/whatever the item when cooldown is in effect. Therefore ender pearls would be fired like machine guns without these checks server side.
2018-03-09 14:45:01 +00:00
3827892e48 ArmorInventory: fixed debug spam when sending contents to the player itself 2018-03-09 13:23:51 +00:00
e06b78b0ee Implemented armor durability 2018-03-09 13:21:05 +00:00
74cff89df3 Instant Damage splash potions now deal knockback 2018-03-09 12:52:09 +00:00
a9957c3db3 Water bottles extinguish fires when hitting a block 2018-03-09 12:25:34 +00:00
2e9bf7e93b Implemented Splash Potions 2018-03-09 12:25:02 +00:00
dbcc69c2de LevelEventPacket: added useless constant 2018-03-09 11:35:08 +00:00
cdd3fe81e1 Projectile: allow using negative damage amounts to remove damage effects 2018-03-09 11:35:08 +00:00
a8a3eb3866 Added particles for snowballs and eggs 2018-03-09 11:35:07 +00:00
83a3c6f614 Arrow: added shake effect and strike sound 2018-03-09 11:35:07 +00:00
8cc6a32a04 Rewritten Projectile movement handling, added ProjectileHitBlockEvent and ProjectileHitEntityEvent, fixed a swathe of arrow-related bugs
I usually avoid mega-commits, but one thing led to another.
2018-03-09 11:35:07 +00:00
c1a2144f60 Particle: added some new constants 2018-03-09 10:42:59 +00:00
b2491a5874 CraftingTransaction: clean up some logic 2018-03-08 20:44:52 +00:00
2e125168c3 CraftingTransaction: Fixed ingredient map trimming
I really don't know why I made this so complicated to start with. This works much better and is much easier to read.

Fixes #2083.
2018-03-08 19:51:06 +00:00
5059a92b91 Fixed bow and throwable sounds 2018-03-08 13:20:26 +00:00
ea5db98d12 Player: fixed draining hunger when teleporting
this was caused by abe5d94d5b because player's lastBlah wasn't getting updated anymore.

Player movement handling really needs cleaning up, but for now this fixes the issue.
2018-03-08 12:18:22 +00:00
1f77c074e9 Level: Unload chunks prior to save() to avoid saving chunks twice on shutdown
save() calls saveChunks() which saves any chunks found to be modified. But chunk unloading does this anyway, so it's better to unload first and then trigger the save mechanism, to avoid saving chunks twice.
2018-03-07 19:47:54 +00:00
73a5788774 Door: remove unused local variable 2018-03-07 18:53:38 +00:00
dc3bf8546e Refactored effects handling, split up concerns of effect types and instances
Removed json insanity for effects

Split up effect types and effect instances

Saturation is an instant effect
2018-03-07 12:42:31 +00:00
c7f8796136 Implemented Paintings (#2073)
This supports vanilla placement of paintings, with overlap and collision checking.
Paintings are removed when a block is placed inside them or if any of their supporting blocks are removed.

As per vanilla, a random painting is chosen from the largest subset that will fit into the given space.
2018-03-07 09:03:30 +00:00
c5336776a5 Update ISSUE_TEMPLATE.md 2018-03-05 09:24:28 +00:00
b623c4aba1 Remove accidentally committed file 2018-03-04 15:17:14 +00:00
49a39fc7bd Split DestroyBlockParticle into two classes
this level-event is not only used for blocks, it's also used for paintings.
2018-03-04 13:11:38 +00:00
2e4519cb36 ExperienceOrb: fixed behaviour when placing blocks on top of them 2018-03-04 12:47:09 +00:00
2ff3b12376 Cleaned up projectile "collide" checks 2018-03-04 12:19:41 +00:00
9e4bccd8c0 updated Language submodule 2018-03-03 19:59:13 +00:00
1c5180b720 McRegion: don't assign regions to the index until all exception handling is done
it appears that errors are occurring in the exception handler when handling corrupted regions, leaving regions in the provider index with incomplete location tables. This causes strange-looking errors later down the line.

This moves the region assignment to the end of the condition to avoid leaving incomplete/corrupted regions in the location table when errors occur.
2018-03-02 18:30:45 +00:00
fa6d44ea9e Move Attribute and Effect init calls to Entity::init()
since entities are dependent on these, they should be here.
2018-03-02 10:05:50 +00:00
9d018e8d9e Level: cleaned up chunk loading error handling, close #2056
This now removes logging from the level providers (for the most part) and replaces it with exception throws and catches. The implementation using the providers should catch these exceptions if they are thrown.
2018-03-01 12:30:12 +00:00
ae2e1fdd5a McRegion: Make nbtDeserialize() and nbtSerialize() protected
Not really sure why these are still exposed publicly.
2018-03-01 10:42:27 +00:00
97bfcf6e71 Create support.yml 2018-03-01 10:28:32 +00:00
5457c7a202 Updated PocketMine-Language submodule 2018-03-01 09:53:14 +00:00
ee28296d60 Server: fixed authentication messages
why did I do this...
2018-03-01 09:32:04 +00:00
06af742bef wtf 2018-03-01 09:30:50 +00:00
6bdf5e15c0 Fixed a couple of mistakes in generateLevel() docs 2018-03-01 09:23:50 +00:00
d4eba3f4b1 Moved some things out of Server to appropriate init() functions 2018-03-01 09:18:40 +00:00
5a89e80873 Server: added getPlayerByUUID() and getPlayerByRawUUID()
closes #2047

Since the player list already indexes players by UUID, it's simple to just use that for fetching the player.

A possible future improvement could be to allow fetching an _offline_ player by UUID, but no capability to do that is yet available.
2018-03-01 09:09:34 +00:00
28e601bbb9 Tile: added handling for PC 1.11 save IDs 2018-02-28 19:58:18 +00:00
7e9f1324a7 Entity: fixed tiny sub optimal code in registerEntity() 2018-02-28 19:30:30 +00:00
973d5dc251 Small de-spaghettification of login handling
no need for these to be split up, it just makes the player login code flow look confusing.
2018-02-28 18:48:08 +00:00
533d139385 Server: Move removePlayer() to somewhere more sensible 2018-02-28 18:28:36 +00:00
6a94c8183c NetworkBinaryStream: Add clarification on array structure for gamerules
we need objects for this really
2018-02-28 18:10:47 +00:00
629a254639 Server: stop reporting exceptions as "notice" in crashdumps 2018-02-28 10:57:25 +00:00
732b931556 BatchPacket: use PacketPool::getPacket() instead of getPacketById()
this is what getPacket() is for.
2018-02-27 21:43:40 +00:00
2dd1878d57 Entity: remove dead field isPlayer 2018-02-27 17:01:28 +00:00
3104a312b2 ConsoleCommandSender: Remove useless function isPlayer()
This function is not declared in any useful places (like the CommandSender interface) and it is not present in Player (!!!). Additionally, an is-player check is better done with an instanceof so that type safety is enforced and IDEs can give auto-complete.

This is a BC break, but this is such a pointless function that it's probably not even worth mentioning.
2018-02-27 16:43:40 +00:00
d6d47feda9 Query: Send responses to the source interface only, instead of all the things
who the fuck wrote this shitty code?
2018-02-27 13:23:01 +00:00
0ba1b58ee0 always takes 2 commits to do one simple thing...
I really love Golang being so strict on this.
2018-02-27 12:34:28 +00:00
ab2df8b11b Removed Server->addRecipe()
This method is pointless extra bloat in Server. Use CraftingManager->registerRecipe() instead.
2018-02-27 12:33:32 +00:00
eb01dcaf60 Player: don't save data to disk on login
this is pointless, and it will get saved on disk on quit anyway.
2018-02-27 12:26:30 +00:00
f0535df96d Remove deprecated things 2018-02-27 11:59:16 +00:00
f903dbfe00 Server: Removed identifiers array
This is completely unnecessary and adds extra complexity for no good reason. Maybe it was used historically, but nowadays it is only used to identify players to send async-prepared batch packets to.

There are two alternative ways to do that:
1. use spl_object_hash() as the targets array in CompressBatchedTask
2. use ServerScheduler's object storage to retain references to the Player[] array.

I've opted for the second method.

Removing these identifiers allows great code simplification in removePlayer() and removes the need for those old stupid hacks.

This also includes a backwards-compatibility break by removing the $identifier parameter of Server->addPlayer().
2018-02-27 11:43:02 +00:00
e0d5c79848 Scheduler: Catch exceptions thrown from AsyncTask->onCompletion() 2018-02-27 11:33:16 +00:00
e024f381c9 Living: fixed cycle between armor inventory and holder not getting cleaned up on close
this was getting collected by the cycle GC, but it should have been dealt with properly like other inventories.
2018-02-27 11:08:09 +00:00
2a09aaf456 start.ps1: use -NoProfile for starting child
The child powershell is a workaround for an unidentified bug which causes colours to get messed up after using git in the same console window. However, loading profiles on the child is a major slowdown when starting the server, and for no good reason.
2018-02-27 09:54:29 +00:00
0ad8ea6e92 Remove unused imports 2018-02-24 19:01:09 +00:00
bd47852ca4 Allow Command::getPermissionMessage() to return null (#2057) 2018-02-24 18:15:27 +00:00
2b036b1a5c Added API method Living::hasEffects() (#2054) 2018-02-24 13:48:15 +00:00
e5ec8fa603 Entity: Use MoveEntityPacket teleport flag for teleporting
fixes entities getting movement interpolation between origin and destination
2018-02-24 12:25:25 +00:00
abe5d94d5b Entity: fixed teleport() not updating movement to players
cc @CortexPE
2018-02-24 12:22:03 +00:00
da5febc34a fix crash report 127835 2018-02-24 11:46:36 +00:00
3de5e132a2 CrashDump: fixed broken argv reporting 2018-02-22 22:05:35 +00:00
37e8c8d324 BanEntry: work around stupid bug in ext/date
https://bugs.php.net/bug.php?id=75992

When plugins do time-limited bans and users enter stupid time values, a shitty bug in ext/date gets triggered, but only when reading the ban entries from disk. DateTime->format() is able to produce formatted strings which have more than 4 digits in the year, which are then considered invalid. This works around it by trying to parse a formatted version on the fly to ensure that it is valid.

This also cleans up and improves ban list loading and handling.
2018-02-22 14:48:53 +00:00
aa11dbb928 Player: Add warnings for messing with movement checks 2018-02-20 13:50:30 +00:00
e7adaef2d2 Level: fix syncChunkLoad timer not getting stopped when no chunk is returned 2018-02-20 10:39:41 +00:00
6bf9ae0a18 Expose plugin.yml contents to plugins (#2043)
This allows plugins and libraries to rely on values in plugin.yml without parsing it again
2018-02-19 22:16:45 +00:00
e7b2dc87d6 Most pointless optimization ever (ServerKiller) 2018-02-19 12:20:31 +00:00
d7a02793fa PocketMine.php: update comment 2018-02-19 12:02:27 +00:00
6a996611f8 Move functions from PocketMine.php to Utils
This cleans a lot of mess out of the bootstrap file, and also has the added bonus that threads which do not inherit functions can now get access to them by autoloading Utils.
2018-02-19 11:56:22 +00:00
ad8d67137e Implemented critical hits (#1929) 2018-02-19 10:14:32 +00:00
cbbed6a6c1 Updated RakLib dependency 2018-02-19 10:01:56 +00:00
99ef3e6576 RakLibInterface: don't self-unregister from Network on crash
This is already done by the Network itself.
2018-02-18 11:52:55 +00:00
eeaf75ac85 Server: add typehint to addPlayer() 2018-02-17 19:54:56 +00:00
6954bfac4b Removed RakNet client ID parameters from Player
This is not used anywhere anymore and null is always filled for this, so it's pointless.

Also, this is an API break.
2018-02-17 19:51:04 +00:00
f27b62027c McRegion: fix some missed ArrayAccess usages of CompoundTag 2018-02-17 14:58:04 +00:00
093cb5b39e Updated PocketMine-NBT dependency 2018-02-17 14:29:20 +00:00
3f41628bf3 Merge branch 'legacy/alpha11' 2018-02-17 10:59:19 +00:00
a3fa8adf4a Fixed XP orbs trying to track players after teleport
closes #2028

@mal0ne-23, you are today's MVP.
2018-02-17 10:58:54 +00:00
08daf655e5 RakLibInterface: Remove useless function 2018-02-16 17:57:43 +00:00
61fc090cf2 Player: don't debloat skin geometry twice
This is already done in setSkin(), which is called below.
2018-02-16 14:27:16 +00:00
ecd830463c PlayerNetworkSessionAdapter: Remove dead TODO 2018-02-16 11:49:28 +00:00
ffe89f5e1b fixed Anvils item/block different logic handling, close #1910 2018-02-16 11:07:50 +00:00
88a05845c2 Item: Removed protected block field, items should now override getBlock() 2018-02-16 11:06:29 +00:00
2cabdca3f7 ItemFactory: Allow block-items to be overridden
Currently an ItemBlock is created for every Block requested, but this will need to change in the future (for Anvils because they have stupid bitshifts on the meta instead of a nice bitmask). This allows registering items in the ItemFactory with IDs lower than 256 and having them recognized.
2018-02-16 11:03:04 +00:00
be1ddb9f5b Item: Added API method getVanillaName()
This allows retrieving the name of an item without the custom name being plastered over the top. This will also allow weird things to have special functions for their names.
2018-02-16 10:57:02 +00:00
7fc3eeab00 Level: Remove redundant null checks for Item->getBlock()
this is typehinted to return Block, so these checks are pointless.
2018-02-16 10:45:54 +00:00
9395dbf9fa Player: added missing spawn protection check for frame item removal
fixes #2025
2018-02-16 10:35:16 +00:00
a7396d7ae9 Player: Cancel interaction on frames in spectator mode before calling the event, not after
This convention is used throughout the code to allow plugin developers to alter the behaviour of the event. In this case, it would instead produce unexpected behaviour when the event is not cancelled by a plugin.
2018-02-16 10:29:46 +00:00
3b632c2870 ItemFactory::fromString(): throw an exception on failure to parse meta value 2018-02-16 09:45:38 +00:00
7dd834bca0 Fixed API patch version being useless
Plugins will now be able to require a specific minimum patch version, in case they depend on bug fixes or whatever.
2018-02-15 21:45:46 +00:00
2b6e135c83 Switch to PSR-4 based autoloader
Since we don't use the PEAR-style namespacing convention, there's no reason to use PSR-0 autoloader.
We don't quite follow PSR-4 conventions because there is still a pocketmine subdirectory, but changing this might pollute the git history, so I'm wary of changing it.
2018-02-15 21:01:26 +00:00
c26e3aa9fa GiveCommand: Make invalid player checking logic less confusing
some code in this namespace is just total WTF...
2018-02-15 18:19:41 +00:00
aeba15c5c6 GiveCommand: don't crash when an invalid item is specified 2018-02-15 18:18:09 +00:00
4c583ec8ab ItemFactory: Throw exception on failure to parse string as an item in fromString()
closes #1487
2018-02-15 17:56:55 +00:00
af2435f199 Removed redundant checks from ItemFactory::init() and BlockFactory::init()
These are never called accidentally, or at least it's highly unlikely to do so. It might be reasonable to throw exceptions for this, but for the meantime they are redundant - extra indentation for no good reason.

This also removes the $force parameter from BlockFactory::init().
2018-02-15 17:42:03 +00:00
456987e212 ItemFactory: Don't initialize creative items in init()
Wanting initialized item factory does not require initializing the creative inventory. This is often useless and unwanted extra baggage (when this is used on threads for example).
2018-02-15 17:09:38 +00:00
8e6ec04abc Item: Replace a usage of hardcoded resource path with \pocketmine\RESOURCE_PATH 2018-02-15 12:24:57 +00:00
42a7b7fa36 More NBT updates
This library is going to be completely different before I'm done here >.>
2018-02-15 12:11:36 +00:00
ce4e0bf69c Tile: fixed copying of custom block data 2018-02-15 11:47:12 +00:00
dc84484c2b ContainerTrait: Add PhpDoc for ListTag iteration 2018-02-15 11:45:13 +00:00
e7e4645c0b Fixed a wide range of bugs with floating-point coordinates getting incorrectly int-casted
This causes lots of bugs in negative coordinates.

This fixes #1789 after world load & save.
2018-02-15 10:27:42 +00:00
4e9e285e37 Vector2: Fixed getFloorX() and getFloorY() logical flaws
(int) typecast does not round down, it truncates!!!!!!!! :yodaangry:
2018-02-15 10:24:35 +00:00
3962d32ffe Chunk: Remove obsolete checks for entity/tile coordinate mismatches
This code is no longer necessary, because entities are constructed with a Level instead of a Chunk since API 3.0.0-ALPHA4. This means that they will not get allocated in the wrong chunk at runtime after having been saved on the wrong chunk by something else (such as an older version of PM). They will instead be allocated in a chunk selected by bitshifting their coordinates.

This is necessary to be able to fix #1789 without causing entities affected by the infamous bitshift-on-floats bugs to inexplicably vanish.
2018-02-14 18:58:52 +00:00
a84aba5517 Replaced some bad usages of Vector3 get*() with their respective getFloor*() 2018-02-14 18:45:10 +00:00
0b82d5c8d4 Math: Fix typo in Matrix->subtract() name 2018-02-14 18:22:37 +00:00
3aef4c5a09 Merge branch 'legacy/alpha11' 2018-02-14 09:13:00 +00:00
6307952ae9 Server: bail on trying to send empty batch (issue #2020) 2018-02-14 09:12:52 +00:00
cacd0f5d8f Level: fixed global packet mechanism spamming empty batch packets every tick
This also spammed to nobody when the level is empty.

Closes #2020.
2018-02-14 09:12:07 +00:00
f66928c345 Player: patch exploits relating to quitting on death (#2017)
* Revert "Revert bad duct-tape fix that broke lots of other things"
This reverts commit 4a4900e5e7.

Player: Perform respawn actions when joining while dead
This fixes exploits related to #1567 by calling respawn logic on join when the player has zero health.
This is a shitty fix and doesn't solve the actual issues described in #1567, but it's a simple solution for the exploits related to it.
2018-02-13 21:23:31 +00:00
9abfd54cc1 Updated with ListTag changes from PocketMine-NBT 2018-02-13 16:50:49 +00:00
4a85311c5f Living: Remove redundant isAlive() check from kill()
This just causes unexpected bugs, and hides actual bugs.
2018-02-13 12:47:33 +00:00
8a4f6eb6c2 ArmorInventory: fixed slots not updating when set
closes #2014
2018-02-13 11:33:54 +00:00
6e7a693355 Tests: Make lint.sh a little more useful 2018-02-12 11:34:51 +00:00
b7bd8dc7f1 Human: fixed NPC skin crash after ByteArray change 2018-02-12 09:56:02 +00:00
b445825467 TextFormat: Moved toANSI() to Terminal, close #1995
This also removes a cyclic dependency between TextFormat and Terminal, meaning that TextFormat is now standalone without any external dependencies.

This is also an API break. Beware all ye who wander here, master = bleeding-edge!
2018-02-11 19:11:51 +00:00
98d6aea7fe Server: rename getResourcePackManager()
casual BC break, ain't nobody got time for deprecations!

closes #1797
2018-02-11 17:17:56 +00:00
b75d121c7e Human: remove obsolete TODO 2018-02-11 17:08:59 +00:00
88bbb03f12 Human: store cape & geometry data in NBT 2018-02-11 17:08:01 +00:00
9478bc281f Human: Save skin data as TAG_ByteArray instead of TAG_String
TAG_String has a UTF-8 payload, which makes it more expensive to work with. Also, skins can contain bytes which are not valid UTF-8 characters and will therefore be treated as corrupted by external tools.
Additionally a TAG_String can only hold 32767 bytes, which might become a problem in the future.

A TAG_ByteArray can hold up to 2GB of data, and there is no character encoding restrictions on it.
2018-02-11 16:50:00 +00:00
7ec886faa2 Updated PocketMine-NBT dependency with string corruption fix
This fix doesn't fix existing data, but it will prevent the bug happening in the future by capping the length of strings to 32767 bytes, and throwing an exception if too long.
2018-02-11 16:36:50 +00:00
610e62e2cd Timings: don't return the paste we just sent in the response 2018-02-11 11:56:16 +00:00
906442136b Merge branch 'legacy/alpha11' 2018-02-11 09:56:10 +00:00
3600542d78 Timings: fixed pastes not working after ubuntu pastebin update 2018-02-11 09:55:52 +00:00
3b36d46a8f Living: don't reset attack time on regaining health
fixes #2004 and related bugs
2018-02-10 20:53:39 +00:00
63fa6a36a9 Merge branch 'pr/1982' 2018-02-08 12:09:29 +00:00
e0ed877494 Protocol changes for 1.2.10 release
Looks like they reverted near enough everything they did in the beta.
2018-02-08 11:19:04 +00:00
bab2daf711 Protocol changes for 1.2.10 release
Looks like they reverted near enough everything they did in the beta.
2018-02-08 11:18:46 +00:00
5858025d90 Updated PocketMine-NBT dependency to fix CompoundTag bugs 2018-02-07 19:49:52 +00:00
dbac2abafb TextFormat: make colour matching regex less absurd 2018-02-07 11:31:49 +00:00
266d1cb935 Updated Composer dependencies 2018-02-07 10:22:31 +00:00
ffbb44673f Enchantment: fix mistake in Protection translation key 2018-02-07 10:15:31 +00:00
a84a8ecc14 Fixed 32-bit accident
gud fuckup
2018-02-06 21:39:15 +00:00
687886e70b PermissibleBase: remove useless destructor 2018-02-06 21:10:42 +00:00
bad323f5cc PocketMine.php: move stuff out of do{}while(false) that doesn't need to be in there 2018-02-06 19:13:57 +00:00
ca9f700fb0 PocketMine.php: refactor timezone handling into its own class
This removes lots of bloat from PocketMine.php, and this is also important for reusability across threads.
2018-02-06 19:09:24 +00:00
c51cc6b2fe Drop support for Zephir entirely
This extension hasn't been maintained in 4 years and it doesn't make sense to update it to PHP 7, since :shoghi: just dumped a blob of PHP into zephir. It's not worth the hassle of updating.

I prefer to modularise and then C-ify modules, so that they can be reused on their own.
2018-02-06 18:40:36 +00:00
03c66f0f86 PocketMine.php: clean up dependencies checking 2018-02-06 18:38:09 +00:00
610b041631 PocketMine.php: remove unused import 2018-02-06 18:25:59 +00:00
75289b1498 kill(): fix bug when running with POSIX extension but without pcntl
SIGKILL constant is defined by pcntl, not by posix. If pcntl is not compiled then bugs can occur when trying to kill() the server (such as during a crash).
2018-02-06 17:55:18 +00:00
4eea54780a start.cmd: pause on exit with error code in CMD
Closing the command window immediately when an error occurs is particularly unhelpful. This keeps the command window open so that the user can see what went wrong.

[ci skip]
2018-02-06 17:49:12 +00:00
e860d32b3a Merge branch 'text-container-move' 2018-02-06 13:13:19 +00:00
c4486d9ad7 Tile: Cleaned up utterly pointless overcomplicated code for inventories 2018-02-06 13:01:54 +00:00
8222b16d9a LevelDB: fixed leftover usage of the old CompoundTag API 2018-02-06 11:16:14 +00:00
dcb53b1cbb RCON: Use PTHREADS_INHERIT_NONE - these threads don't need baggage from upstairs 2018-02-05 17:27:00 +00:00
a52a2f6d26 RCON: register autoloader on RCON threads
fixes #1993
Interesting that this bug was never noticed before. Maybe because of the class getting loaded by PocketMine.php previously.
2018-02-04 22:24:19 +00:00
906d7eb176 Lang: Move TranslationContainer and TextContainer to \pocketmine\lang namespace
why the hell were they ever put in \pocketmine\event in the first place??

This change was suggested many months ago but I forgot all about it.
2018-02-04 20:03:30 +00:00
bf3f5532ac Server: duct tape for very early startup crashes
Exceptions occurring early in the start sequence (before BaseLang is initialized) will result in the server hanging and not killing process as expected. This works around that issue.
2018-02-04 19:53:11 +00:00
07bf1c9e22 Bump API version for release 2018-02-04 18:06:02 +00:00
b659a3d39f Server: more shutdown debug 2018-02-04 10:14:35 +00:00
68b30108be CrashDump: fix mis-reporting Composer dependency exceptions as plugin crashes
this is still not foolproof but whatever.
2018-02-03 19:27:59 +00:00
f223fb2876 Use realpath() to determine correct file path case for DATA and PLUGIN_PATH
fixes issues where cleanPath() doesn't remove these paths from crash traces
2018-02-03 19:21:13 +00:00
8bb785b7af Update pthreads for Travis 2018-02-03 14:17:42 +00:00
806a2005d7 added missing dependency check for OpenSSL
this is managed by Composer now so I didn't think to check it.
2018-02-03 01:03:59 +00:00
c794ced0ad fix dependencies order 2018-02-03 01:03:08 +00:00
f993358c5f fixed extremely stupid bug with player spawns
This was causing new players to inexplicably spawn in the wrong place when joining a world for the first time which had a different level name than folder name. With LevelDB worlds, this caused them to spawn wayyyy up at y=32767 for no good reason.
2018-02-02 16:00:28 +00:00
1c12be6bf2 README: Remove IRC
these channels have been dead for years.
2018-02-02 09:31:13 +00:00
a1d9b8486e README: Be more clear about "getting latest phar"
We don't want people to be using latest development builds, but that's the first thing people see when visiting Jenkins. We want them using releases instead.
2018-02-02 09:28:22 +00:00
9397356ce4 Server: fix crash when specifying settings.async-workers on the command-line 2018-02-01 17:58:49 +00:00
e56e363dcc DataPacket: rename split-screen bytes 2018-01-31 12:07:26 +00:00
18b287c3ea AsyncTask: Remove cleanObject() and calls to it
This is no longer needed. Doing worker GC (via collect()) frees the allocated memory anyway, so this function is now redundant.
2018-01-30 16:45:49 +00:00
9014eb72e9 TeleportCommand: Fixed the bug fix again
This all comes from a shitty bugfix by @PEMapModder. Should be applied globally really, but it wasn't - and not properly tested either :P
2018-01-30 15:08:11 +00:00
82948726ed Beware threads/workers might not inherit \pocketmine\PATH
if the inherit flags don't include PTHREADS_INHERIT_CONSTANTS, this code would fail. Store the Composer autoloader path in advance instead.
2018-01-30 14:50:19 +00:00
c601816586 Terminal::hasFormattingCodes() workaround for STDOUT not being defined
#1979

This isn't a full solution because formatting codes are still not applied correctly if the calling thread doesn't inherit classes.
2018-01-30 10:54:04 +00:00
54f7a88fbb Added getXuid() 2018-01-30 01:25:27 +03:00
d2d1df0447 MainLogger: Remove redundant condition
these are always ThreadedLoggerAttachments anyway, this code doesn't make sense.
2018-01-29 12:24:00 +00:00
f9b1afe4cf Fixed race condition causing exception log messages to sometimes not get written to disk when kill() is used
Synchronize with the logger thread when logging an exception or killing. This forces the main thread to wait for disk write to complete when logging exceptions or killing the process.
2018-01-29 12:04:23 +00:00
033cb8bd63 oops, wrong namespace 2018-01-28 13:08:11 +00:00
0ed9fcb641 Restrict VerifyLoginTask exception handling to known exceptions
everything else should produce a nice big stack trace for debugging purposes, because everything else is probably bugs

This fixes random exception error messages getting relayed to the client when a user does stupid things like editing the source code without knowing what they are doing.
2018-01-28 13:07:09 +00:00
efac23d4af Updated to new RakLib version 2018-01-27 19:10:55 +00:00
48dc1c38f7 Generator: fixed misuse of InvalidArgumentCountException 2018-01-27 12:46:09 +00:00
ffb3e2b47a Player: Fixed logical nonsense in removeWindow()
The only time this is set anyway is obviously if the ID is non-null.
2018-01-27 11:02:03 +00:00
ef816c0a52 Player: Fixed window ID of closing inventory always being -1
reported by @Muqsit, thank you sir
2018-01-27 11:00:08 +00:00
3e35bc38e2 Inventory: Fixed crash when breaking right half of a double chest while open 2018-01-27 10:57:04 +00:00
de0741f727 Item: remove unused imports 2018-01-26 17:12:00 -05:00
6fd4b9f1e2 Entity: Cater for old data with CustomNameVisible as a StringTag
This was a bug in older versions, fixed by 890f72dbf2. However since ALPHA10 this has been moved to the new, strict-ified CompoundTag API, which shits its pants when it encounters a tag of the wrong type.

Closes jojoe77777/Slapper#119
2018-01-26 20:01:04 +00:00
6c8a1a5b80 Item: Remove redundant Level parameter from onActivate()
there are three other sources this could be gotten from, an arbitrary level doesn't make sense.
2018-01-25 10:15:36 +00:00
3842ee15cf Item: Removed now-obsolete Cake class
>> As of 1.2, cake has a max stack size of 64, making this class redundant as its only purpose was to declare a stack size of 1.
2018-01-25 10:09:09 +00:00
6c71b443e8 Fixed armor not dropping (#1962) 2018-01-24 20:01:32 +00:00
4a4900e5e7 Revert bad duct-tape fix that broke lots of other things
Revert "Fixed players getting full health on rejoin after quitting on death"

This reverts commit 1d4bafb6ff.
2018-01-24 19:21:32 +00:00
26d4169fea EntityShootBowEvent: Remove unnecessary kill() 2018-01-24 19:17:08 +00:00
7d88a8b315 Player: Remove useless assignments from constructor 2018-01-24 18:22:23 +00:00
41592a04b7 InventoryTransactionPacket: Update some field names 2018-01-24 13:50:30 +00:00
1d4bafb6ff Fixed players getting full health on rejoin after quitting on death
This makes #1567 less exploitable. Now, players who attempt to exploit this bug will get stuck - they won't be able to move or do anything. Not ideal, because they won't be able to respawn either - but it's better than nothing.
2018-01-24 12:27:10 +00:00
28996f561f Player: Added a hack for knockback being messed up
This needs to be updated server side and isn't because of the way player movement is currently handled. Fixing this properly will require a lot more work than this.
2018-01-24 11:56:32 +00:00
0658c0851b Entity: Remove some unused properties 2018-01-24 11:37:01 +00:00
0df2064802 Implement armor damage protection enchantments (#1839) 2018-01-24 10:13:24 +00:00
6543d96910 Inventory: Split up armor and player inventory (#1957)
* Inventory: Split up PlayerInventory and armour handling
* Fixed other players don't see armour changes. This bug also exists on master.
2018-01-23 20:01:26 +00:00
0bf5ab76fb Remove WeakRef leftovers 2018-01-23 19:04:37 +00:00
8e1394bf53 MemoryManager: Use get_declared_classes() to build lists of static properties
This makes memory dumping independent from the autoloader implementation, and fixes #1958.
2018-01-23 18:23:53 +00:00
6ddbdc9dc1 Fixed worker memory dump crash
$GLOBALS does not exist at all on threads :(
2018-01-23 17:21:24 +00:00
2a8be527d7 Remove redundant paths from BaseClassLoader
Everything under src is now handled by the Composer autoloader, and SPL doesn't exist anymore (it's a Composer library now).
2018-01-23 17:03:04 +00:00
aca1422fca Updated pthreads version for Travis 2018-01-23 16:49:32 +00:00
b0d0932ed9 DoubleChestInventory: Fixed items getting rearranged in single chests when creating a double chest
I fixed this elsewhere more than 18 months ago, why is this still here?
2018-01-23 15:50:13 +00:00
fd5557861b Changed how login verification is handled, add more useful error messages
closes #1955
2018-01-28 14:13:59 +00:00
1de7c5b114 Inventory: Added includeEmpty parameter to getContents() 2018-01-22 22:33:57 +00:00
2fb580db26 Inventory: Removed need for Inventory to have an InventoryHolder
Inventory holders are now freed from BaseInventory. They are now declared by subclasses by convention, but are not required in most cases.

Ideally, this would be followed by the removal of the need for inventories to know their holders at all. They should just be simple containers of items.

This fixes #1560 by removing FakeBlockMenu.
2018-01-22 19:44:52 +00:00
e5ca22a9a6 Player: Simplified implementation of windows => window ID map
it is not necessary to reference the actual objects here. Doing so makes the implementation more confusing. Hashes are sufficient.
2018-01-22 18:58:19 +00:00
69ddaacc28 Inventory: Add a $send parameter to clearAll() 2018-01-22 18:39:39 +00:00
897a31e608 Player: Moved logic of setUsingItem()
plugins might be using this method, or the item may have been dropped involuntarily due to server-side logic. Therefore it should be handled when the transaction is received and not when the item is dropped into the world.
2018-01-22 18:36:48 +00:00
4943ff9dfc Not sure how this got missed :< 2018-01-21 19:36:42 +00:00
e36b38939c Lever: fix placement 2018-01-21 17:53:41 +00:00
ecb3f9aeac Level: Allow broadcastLevelEvent() to accept a null position to broadcast to everyone in the Level 2018-01-21 17:41:00 +00:00
f0696f77ef Level: Added global packet broadcast mechanism 2018-01-21 17:40:31 +00:00
6813838754 EntityDamageEvent: Remove redundant TODO
Armor does absorb lightning damage by default.
2018-01-21 17:40:03 +00:00
65fe19ca71 Entity: Fixed logic error in getBlocksAround() which caused yet another firebug
Try setting a fire at z = -204, then stand on the edge between -205 and -206.

The coordinates that a BB's corners are encapsulated in are always the floor()ed coordinates

If you stand at -205.0, your BB min is -205.3 and your BB max is -204.7, which then incorrectly tells you that the BB intersects with block -204
because ceil(-204.7) == -204
when you actually are only intersecting with -205 and -206
this is as bad as using (int) to floor integers :kms:
2018-01-21 15:43:03 +00:00
a4f5cab12d Entity: Added getDataPropertyManager() 2018-01-20 20:07:11 +00:00
29e06e30b2 Fix projectiles throwing errors on launching, fix #1942 (#1943)
* Fix Projectile::setOwningEntity() on null error
2018-01-20 18:07:53 +00:00
3939e2d9dd NetworkBinaryStream: add some typehints 2018-01-20 11:05:41 +00:00
2579438b84 NetworkBinaryStream: Use nullable typehint for putVector3Nullable() instead of default value
the parameter is not optional
2018-01-20 11:01:16 +00:00
95d42b9907 Network: Remove legacy Vector3 primitive encode/decode methods 2018-01-20 10:58:39 +00:00
2eb6e075ae Refactored entity metadata handling into its own class, with type-safe methods (#1876)
This includes several other changes, including:
- SLOT data properties now accept items directly
- POS data properties now accept floored Vector3s (in future this will be block positions) or null for 0,0,0
- VECTOR3F data properties now accept Vector3s or null for 0,0,0
2018-01-20 10:52:14 +00:00
8f928915d9 Merge PR #1936: Vector3:: setComponents() documentation fix
Vector3::setComponents() and override changes/removal
2018-01-19 08:12:44 +00:00
3af8cf48b2 Removed setComponents() override in Position 2018-01-18 19:03:53 -05:00
21c03670b6 PhpDoc fix for my sanity 2018-01-18 18:04:54 -05:00
0c868b16b6 Network: Added config to pocketmine.yml to allow changing max MTU size
This might be useful for people with older routers where the connection MTU is actually lower than the router allows.
2018-01-18 18:15:14 +00:00
1e67360048 SpawnEgg: Remove redundant isSurvival() check 2018-01-18 17:04:25 +00:00
3520dafd29 Entity: Make fall distance explicit float to shut a PhpStorm bug up 2018-01-18 16:52:17 +00:00
857b63ba8f Entity: Added recalculateBoundingBox() 2018-01-18 16:35:38 +00:00
9551e5b8e5 Durable: Allow subclasses to override behaviour when the item breaks 2018-01-18 14:37:22 +00:00
c7f15a556d Durable: Don't allow damage to exceed max damage 2018-01-18 14:34:50 +00:00
efca9f0450 Item: Moved getMaxDurability() to Durable class only, and make it abstract
It's only now used in the Durable class, so it does not make sense to keep it in Item anymore. This is a leftover from the days where Durable did not exist.
2018-01-18 14:16:30 +00:00
d728154e87 Level: Fixed entities getting deleted when switching levels
So this came from a bugfix (795d6c8ddf) which fixed a memory leak related to entities getting kill()ed on chunk unload.
HOWEVER, me2016 did NOT realize that this code is actually entirely pointless and causes unexpected behaviour.

removeEntity() is used in 2 places in the core code:
1. in Entity->close() (so close() doesn't need to be called again, obviously)
2. in Entity->switchLevel() (which then causes the entirely unexpected behaviour of close()ing the entity on level change.

Conclusion: This code is pointless. This fixes the bugfix.
2018-01-17 11:30:59 +00:00
2e1a167bed Arrow class: No need to import Item class with other name (#1932) 2018-01-17 10:59:50 +00:00
6f6e3aaa21 Fixed projectiles collding with spectator players
closes #1857
2018-01-17 10:57:04 +00:00
9c65a2b890 Furnace: Fixed lit furnaces dropping the wrong item
closes #1915
2018-01-17 10:24:01 +00:00
beb5bf6dda Add API methods: Entity::isInvisible(), Entity::setInvisible() (#1930)
* Make use of the API function in Effect class
2018-01-17 09:56:59 +00:00
7a5e5773b7 Updated RakLib dependency 2018-01-16 20:01:41 +00:00
f1b0a4f1de Not sure why we are still blaming @shoghicp for this :< 2018-01-15 11:17:01 +00:00
751345c736 Updated BinaryUtils dependency 2018-01-14 18:56:31 +00:00
e850f34d76 Fix TNT block not setting fuse NBT correctly (#1917) 2018-01-14 18:10:57 +00:00
8d7c65585c Enchantment: Implement Silk Touch (#1912) 2018-01-14 13:37:27 +00:00
96f6362117 Fixed glowing redstone ore giving itself when block-picked 2018-01-14 13:35:41 +00:00
66c768d453 PR template: Make clear that "tested" is not acceptable test information
[ci skip]
2018-01-14 11:44:29 +00:00
6fe7763db9 Contributing: require details of tests done
[ci skip]
2018-01-14 11:37:51 +00:00
fda97decaa Contributing: batch commit of changes
very hypocritical of me, I know...

[ci skip]
2018-01-14 11:35:04 +00:00
b3f44562e9 Contributing: updated example
[ci skip]
2018-01-14 11:04:46 +00:00
51350be190 CONTRIBUTING.md: fixed indentation
[ci skip]
2018-01-14 10:42:53 +00:00
7f4b5d282e Fixed plugin name validation
Invalid characters in plugin names are no longer stripped. They always result in a load error.

The behaviour of replacing spaces with underscores is not changed.
2018-01-14 18:28:19 +08:00
94feecd44b Enchantment: Implemented Unbreaking 2018-01-13 19:34:45 +00:00
45b02d92d4 Math: Added RayTraceResult, removed dependence on MovingObjectPosition
MOP doesn't make any sense anyway.

RayTraceResult is a container which represents the point at which a line hits a bounding box. No dependence on blocks or entities is wanted or needed.
MovingObjectPosition has API changes to allow it to wrap RayTraceResult, but nothing uses MOP anymore anyway.

This would allow modularisation of the pocketmine\\math namespace.
2018-01-12 14:28:41 +00:00
fe4b5498e6 Level: Fixed 2D block cache not getting counted correctly
Fixes #1903
Closes #1906, which, while a pretty solution, is very inefficient (see PR discussion). This is an optimization of microscopic proportions, but the point still stands.
2018-01-12 11:02:43 +00:00
98b36fd73e Enchantment: Implemented Efficiency
This is only needed server-side for block-break animation times.
2018-01-11 20:13:57 +00:00
07c7048433 Enchantment: Converted item type bitflags to hex 2018-01-11 20:09:42 +00:00
f09cf92197 Enchantment: Updated item type flags 2018-01-11 20:08:50 +00:00
98eba11da5 Human: Use Item->getEnchantmentLevel() for Respiration check 2018-01-11 18:32:46 +00:00
a6c1e02847 Enchantment: Register Respiration enchantment
First working enchantment on master. Hooray for 3 years late.

This works out of the box (the code checking for this enchantment already exists in Human->doAirSupplyTick()).
2018-01-11 18:32:22 +00:00
b04cee12ea Item: Added API method getEnchantmentLevel() 2018-01-11 18:22:29 +00:00
c4966404bb Moved NBT to Composer library 2018-01-11 14:18:09 +00:00
579c508761 Move Binary and BinaryStream to Composer library 2018-01-11 13:19:59 +00:00
43959bccb1 Change Composer package vendor name to pocketmine instead of pmmp, update dependencies 2018-01-11 13:16:27 +00:00
e6bd12dc2f Consolidated MCPE network binary handling methods into one class, remove protocol-specific methods from BinaryStream
Remove MCPE-network specific stuff from BinaryStream, added NetworkBinaryStream
This removes dependencies of BinaryStream on core code, while providing some consolidation of network handling code.
2018-01-11 12:28:56 +00:00
7daca754b1 BinaryStream: Fixed wrong header being included
This is currently harmless, except for adding a redundant extra use
statement. However harmless it is though, it is still incorrect.
2018-01-11 12:26:50 +00:00
cb90e30bcf Entity: Fixed intersecting with blocks they aren't actually intersecting with...
at the expense of magma no longer working (which will need to be done better anyway).

This:
- reverts the +0.01 outset which hugely exacerbated the lava bug (fixes #1892)
- adds a 0.001 inset (PC-style) which prevents entities incorrectly intersecting with diagonally adjacent blocks at far-ish coordinates (lava at x=4000, z=4000 is a good way to test this).

PR #1880 does also solve this issue, but again at the expense of magma. Since the bugfix does not require a big bounding-box handling refactor, it has been separated out.
2018-01-11 11:10:36 +00:00
71d11c73f0 Math: Kill BlockIterator, added a VoxelRayTrace class with level-independent generator functions (#1885)
This is a rather larger commit than I'm happy with, but oh well.

This kills off the enormously overcomplicated BlockIterator and replaces it with a VoxelRayTrace class containing ray tracing generator functions. These functions are independent of any Level. They yield Vector3 objects with current ray trace positions to allow implementations to handle the intercepted blocks in their own ways.

Living->getLineOfSight() now uses VoxelRayTrace instead of BlockIterator.
2018-01-10 20:14:36 +00:00
24116ba846 Remove old pthreads v2 workarounds
This used to cause problems in earlier versions of pthreads if PTHREADS_INHERIT_CLASSES was not used. This is no longer a problem in pthreads v3, because pthreads v3 copies passed threaded object classes under the hood, so there is no need to manually include them anymore.

Additionally, the files in these paths don't exist anymore.
2018-01-10 10:59:58 +00:00
a0683dbb0f Chunk: Remove useless code in fastDeserialize() 2018-01-08 21:38:30 +00:00
b6811b643c .gitignore: Ignore all directories starting with bin
This might cause problems later on, but it's unlikely. Right now however, I am tired of my various PHP version directories showing up in git untracked files.
2018-01-08 11:17:29 +00:00
4d2549b50a PlayerInventory: Fixed $send parameter not working for setting armour slots 2018-01-06 16:24:41 +00:00
1fb3274f37 Server: Make start() private
This should not be exposed to plugin use.
2018-01-06 15:04:58 +00:00
6772a69c55 Server: Prevent construction of more than one server instance at a time
I have no idea when one might choose to do this, but it could cause extremely undesirable effects, so it should be prevented.
2018-01-06 14:58:51 +00:00
266a253c03 Remove dead imports 2018-01-05 19:48:04 +00:00
c62e1abf2f Kill the instabreak anti-cheat
This is annoying and it requires that the server must match this precisely to not cause bugs. Additionally, this code shits its pants when the client hits a spot of network lag.

This can be implemented easily as a plugin. There is no reason whatsoever for this to be in the core.
2018-01-05 19:43:51 +00:00
55f405f5c2 Player: Extend acceptable block-break distance by 1
Survival reach distance is 6, but that's only a measure of how far the player must reach to hit any part of the target block. Measured from the centre, this again provides a possible corner reach which is too far away from the centre of the block by sqrt(3) / 2 blocks.

Simple fix - allow an extra block's distance.
2018-01-05 19:36:02 +00:00
8fbd0e58f0 Level: Fixed possible crash with changed blocks handling
Since chunks are unloaded before changed blocks are processed, there is a small chance that a block might get changed in a chunk, and then get unloaded due to not being in use, before the updates are broadcasted.
This is unlikely to ever happen since chunks usually don't get unloaded unless they don't have loaders anyway, but it could happen (?) if a chunk is forcefully unloaded.
2018-01-05 13:46:21 +00:00
418d099a2e Merge PR #1561: Implement XP 2018-01-05 12:53:48 +00:00
9d2eb5e911 Human: Added some void typehints 2018-01-05 12:30:03 +00:00
b6c1124d50 Move XP drop amount to Human instead of Player 2018-01-05 12:09:24 +00:00
03fda936a8 Added XP level-up sounds and refactored XP gain sound handling 2018-01-05 11:58:54 +00:00
684fd46d09 Entity: Throw exception when trying to get save ID of non registered entity 2018-01-04 21:05:17 +00:00
90fc649441 Fixed bad PhpDoc leftovers from NBT streams refactor 2018-01-04 20:32:06 +00:00
0410df77aa Drop experience on death 2018-01-04 19:33:37 +00:00
0f30467f62 Added Level->dropExperience() and API for splitting XP into orb sizes 2018-01-04 19:32:54 +00:00
a84910f04c Implemented XP orbs 2018-01-04 19:28:19 +00:00
3ee225caec Human: Refactored XP API methods 2018-01-04 19:15:26 +00:00
f963dbd10d Level: Added getNearestEntity()
This may be used for AI in the future.
2018-01-04 19:10:43 +00:00
debfbf0d93 Math: Added solveQuadratic()
will be used in future for XP. This is extracted from the experience work branch.
2018-01-04 15:58:54 +00:00
5c37d298a6 Player: Changed canInteract() default max diff to sqrt(3) / 2
This is needed because players can break blocks that are outside of their field of view. A player can be inside a block and be able to break that block, while looking up, which places its centre (which is where the interact check is done from) actually behind the player's field of view. This causes anti-cheat to be triggered and makes it impossible to break blocks one is inside.

This commit changes the max negative diff to be half of the distance between a block's centre and its corners (M_SQRT_3 / 2).
2018-01-04 15:46:49 +00:00
3ca162f23f Revert "Player: Remove obsolete maxDiff parameter from canInteract()"
This reverts commit a5c3fbdd7a.
2018-01-04 15:33:23 +00:00
5f48433c95 Bucket: Added sounds for bucket fill/empty 2018-01-03 14:27:41 +00:00
33352638a9 Bucket: Fixed appearing empty when picking up still liquids
Buckets already affected by this bug will still appear empty until used. After that they'll work fine.
2018-01-03 14:22:53 +00:00
db52501462 Bucket: Fixed stack size handling for empty buckets
GOD this code is horrible
close #1472
2018-01-03 14:12:04 +00:00
3a0cbd1cd4 Block: Cleaned up double-block break handling, close #1862, close #1525
This now removes the need for recursing around for structures comprised of multiple blocks. Instead, override getAffectedBlocks() to return all blocks that need to be deleted when the current block is deleted, and make sure that only one half of the block drops something. When a player breaks one of the blocks, all the blocks affected by that block will also be destroyed, creating particles and sounds where appropriate.

This fixes creative drops for double plants and beds.
2018-01-03 13:01:05 +00:00
1bdb68b7da EnderChest: Remove dead onBreak() code (follow-up to previous commit) 2018-01-03 12:10:36 +00:00
6ce728169e Chest: Remove redundant unpairing code from onBreak()
This is already done in the Level.
2018-01-03 12:08:35 +00:00
06a3c7c478 Entity: Write attributes in AddEntityPacket 2018-01-03 11:30:22 +00:00
70982c145b Level: Clarified documentation for loadChunk() and changed misleading parameter name 2018-01-02 18:08:43 +00:00
417f2d8998 Level: Clarified documentation on getChunk() 2018-01-02 18:05:30 +00:00
7339c4ac2f Player: Fixed not being able to interact with blocks in adventure mode, close #1848
This allows other undesired behaviour like flint&steel, buckets to work in adventure mode when they shouldn't, but that's a bug for another time.
2018-01-02 16:26:59 +00:00
43a0ede9d2 Player: Fix floating-point errors when float Vector3s are given to sleepOn()
In the future this will change to block positions and the Vector3 issue will cease to be an issue.

Closes #1871
2018-01-02 16:09:58 +00:00
c747c7d025 Throw exceptions when entities/tiles are created on chunks that don't exist
These assertions don't make sense. Since the chunk field is used below in both cases, the chunk should **never** be null no matter what.
2018-01-02 13:12:54 +00:00
c9e2e8980f Fixed some places entities/players use their chunk without checking if it is valid
This may be invalid in some cases, such as:
- chunk is not loaded
- entity is not fully constructed
- entity is a Player who has not yet completed the login sequence.
2018-01-02 12:57:04 +00:00
9a956692de Fixed wasteful throwaway objects used for spawn positions 2018-01-02 12:21:11 +00:00
d30a6b60b7 .gitignore: Ignore crashdumps directory
How did this never become a problem before?!
2018-01-02 12:09:31 +00:00
41873bb115 Merge PR #1864: LevelProviders refactor 2018-01-02 11:47:11 +00:00
8064152777 LevelProvider: Add documentation for doGarbageCollection() and close() 2018-01-02 11:39:51 +00:00
872df446bd Level: Remove redundant duplicate condition in unloadChunk() 2018-01-02 11:16:20 +00:00
376a615634 thanks for the warning PhpStorm... not 2018-01-02 11:14:01 +00:00
c16c9efdf3 Chunk: Rename unload() to onUnload()
this more accurately describes what the function does.
2018-01-02 10:50:22 +00:00
c3cc6f9880 Chunk: Clean up unnecessary checks in unload() 2018-01-02 10:48:01 +00:00
1e139743b8 Level: Do level provider GC every 5 minutes from level tick
this should solve #1183, pending further testing.
2018-01-02 10:23:57 +00:00
bde0ba1100 Level: Set chunk coordinates in setChunk()
The level provider used to do this in LevelProvider->setChunk(), but it does not anymore.
2018-01-01 13:13:47 +00:00
50f273c041 Vector2: Fixed ceil() and floor() totally broken logic
"So if I Vector2->ceil()->ceil() my vector2 magically gets incrementing values..." @Sandertv 2018
2018-01-01 12:57:34 +00:00
db095f9705 Updated PreProcessor submodule 2018-01-01 12:54:18 +00:00
f580f27ec7 LevelProvider: Updated documentation 2018-01-01 11:59:22 +00:00
a46029c0f6 LevelProvider: Nuked the complicated mess out of level providers
Level providers are now cut back to just an interface to a world's data. They don't keep their own chunk registries or any stupid shit like that because the Level already does that.

This furthers the goal of being able to move level I/O off the main thread, and also drastically decreases the complication of implementing level providers.
2018-01-01 11:21:46 +00:00
1a615591e2 LevelProvider: Remove cyclic dependency between Level and LevelProvider
This will now allow LevelProviders to be constructed on threads.
2018-01-01 10:50:13 +00:00
d19683b7dd LevelProvider: Remove some dead methods 2017-12-31 18:35:23 +00:00
f17b3b2a3b LevelProvider: Refactor providers to drop lots of duplicated code 2017-12-31 18:35:23 +00:00
a0a2ea01bc LevelDB: Check for LEVELDB_ZLIB_RAW_COMPRESSION when checking for the extension's presence
We always want to validate that the leveldb provided supports the world format.
2017-12-31 17:49:02 +00:00
5132ab6cd9 LevelDB: Remove redundant folder creation in generate()
This is pointless because the call below - which is _also_ recursively creating directories - will create this directory anyway.
2017-12-31 17:46:07 +00:00
256bdf2581 McRegion: Use MainLogger::getLogger()
another one bites the dust
2017-12-31 16:06:08 +00:00
8a3f8b4706 LevelProvider: Remove redundant method requestChunkTask()
This removes one more dependency that LevelProvider has on Level.
2017-12-31 16:05:58 +00:00
7264ce43ae McRegion: Added method pathToRegion() 2017-12-31 14:25:17 +00:00
66e475cbb8 Region: Remove RegionLoader/McRegion cyclic dependency 2017-12-30 19:59:35 +00:00
1e896efff9 McRegion: Added an assert 2017-12-30 19:49:44 +00:00
4db7a7e57f Region: Change chunk offset calculation in regions to use bitmasks
I don't know why it wasn't done like this to start with. However this has not been tested yet, so this goes on a different branch for now to test.
2017-12-30 19:41:58 +00:00
54b23968e7 McRegion: Refactor some ambiguous variable names 2017-12-30 18:59:01 +00:00
bcb080e2b9 Level: Make sleepTicks private, don't write directly 2017-12-30 18:41:13 +00:00
e5c58f9b04 Player: Add typehint for maxDistance parameter of canInteract()
Not sure why this was missing :<
2017-12-30 17:43:12 +00:00
af7aef70db Implemented TextFormat::colorize() (#1837)
Implemented TextFormat::colorize()
See 4c46087ffc for the initial discussion
2017-12-30 16:51:04 +00:00
3ea72a0bf9 Merge PR #1775: NBT streams refactor 2017-12-30 15:53:47 +00:00
be02fbb352 NBT: Add typehints to PHP 7.2 standards 2017-12-30 15:07:50 +00:00
a67f7e3930 Add header includes and preprocessor checks 2017-12-30 14:56:29 +00:00
965c19375f NBT: Split up concerns of endianness and varint NBT into their own classes, separate stream handling from NBT class
The remaining methods, constants and fields in the NBT class now pertain to generic NBT functionality (except for the matchList()/matchTree() methods, but that's a job for another time). All NBT I/O specific logic has now been moved to NBTStream and its descendents.
2017-12-30 14:55:45 +00:00
63edcb8934 Updated PreProcessor submodule 2017-12-30 14:15:33 +00:00
e7a012d69a Player: Remove dead imports 2017-12-30 12:42:42 +00:00
99c55ac889 Plugin: Fixed return type documentation for getResource() 2017-12-30 12:40:50 +00:00
f14adf5827 Updated RakLib dependency 2017-12-28 12:51:16 +00:00
c64b9ad63a MovingObjectPosition: Use asVector3() instead of creating a new vector the hard way 2017-12-26 15:37:00 +00:00
dda71b06ae AxisAlignedBB: Use elseif in calculate*Offset()
It's impossible for both of these conditions to be met in the same call.
2017-12-26 14:31:42 +00:00
3c4dca7fdb ZippedResourcePack: Handle json decoding errors correctly
Previously this would crash if it failed to decode the JSON (https://forums.pmmp.io/threads/texture-pack-shows-errors-not-working.4880/)
2017-12-25 19:01:02 +00:00
ddbc5cf960 Player: Use fmod() instead of modulo operator for yaw/pitch
the modulo (%) operator only operates on integers. If it's used on floats, they are silently casted to ints, which results in loss of accuracy. Fractions of a degree might not seem important, but for ray-tracing purposes a fraction of a degree can make the difference between hit and miss.
2017-12-24 19:48:43 +00:00
1edf69892a Fixed chorus fruit teleporting players into the void in superflat worlds 2017-12-24 16:27:58 +00:00
f10c2a2df2 FlowerPot: Fix drops retaining damage
close #1844
2017-12-23 17:54:22 +00:00
3bbdc5ab5b Implemented chorus fruit 2017-12-23 15:11:48 +00:00
082e3404c3 Potion: Implement potion effects 2017-12-23 15:07:39 +00:00
547833ae23 Effect: Add constants with vanilla names where missing 2017-12-23 14:48:56 +00:00
6e1df36188 Consumables refactor (#1796)
* Removed broken EntityEatEvents - these don't fit the pattern since they only apply to Human entities anyway. PlayerItemConsumeEvent and PlayerInteractEvent can be used for cancellation purposes, and plugins can do custom stuff without mess.

* Restrict item consuming to Living entities only

* Added FoodSource->requiresHunger()

* Only items implementing the Consumable interface can now be consumed.

* The effects from consuming items are now generic-ized by way of the Living->consume() function. This is overridden in Human to allow applying food and hunger.

* Fixed the hardcoded mess for buckets
2017-12-23 13:03:41 +00:00
329fe7d844 Effect: Implement Saturation effect
I thought I did this months ago, but apparently not. Whatever, it's here now.
2017-12-23 11:35:01 +00:00
b7aaf54a6f Effect: Fixed mistake in bitshifting with effect level in instant effects
This should be the amplifier, otherwise the effect will have double-effect on level 1.
2017-12-23 11:32:58 +00:00
6332814a04 Effect: Minor cleanup on Instant Health/Damage effect amplification 2017-12-23 11:23:29 +00:00
9d4818d360 Effect: Hunger is supposed to apply every tick
This fixes oddities in the behaviour noticeable with higher effect levels.
2017-12-23 11:15:23 +00:00
36f3accf4b Effect: Don't allow cancellation of expired effect removal, close #1770 2017-12-23 10:55:25 +00:00
8d08840ea4 Effect: Better fix for duration bug seen in 3614711a02 2017-12-23 10:45:59 +00:00
7f0d0c9d63 Revert "fixed negative effect durations when level tick rate is > 1"
This reverts commit 3614711a02.
2017-12-23 10:44:21 +00:00
bf55f03a3e Merge pull request #1842 from pmmp/issues/983-interact-fix
Fix direction checking for player interactions, close #983
2017-12-23 09:42:39 +00:00
a5c3fbdd7a Player: Remove obsolete maxDiff parameter from canInteract() 2017-12-22 20:38:39 +00:00
a8bf2191b9 Player: Do direction checks for interaction in 3D instead of 2D
This fixes #983, but I haven't yet tested if this will prevent cheating in an actual hacker scenario. Needs more tests.

Additionally, this should remove the need for the negative threshold - if the diff is less than 0, the player is almost definitely cheating.
2017-12-22 20:06:59 +00:00
0688a86f57 Player: Fixed interaction checks preventing placing blocks when stood on the corner of one when using crosshairs
This issue can be seen on W10 Edition. Stand on the corner of a block and turn so that the majority of the target block is behind you. Then look down and try to mine it.
2017-12-22 19:58:33 +00:00
2e11e448dd Player: Dump crafting grid on death, not on respawn
This fixes players managing to retain items by getting killed while they have something in the crafting grid.
2017-12-22 11:34:33 +00:00
8bf275cb8b Player: Execute PlayerPreLoginEvent before banlist/whitelist checks, close #1831 (#1833) 2017-12-22 11:19:56 +00:00
1896576a24 ResourcePackManager: Remove Server constructor dependency 2017-12-22 11:11:58 +00:00
8f811c29d7 ResourcePackManager: Remove redundant config property
This was only used in the constructor, there's no need to store it.
2017-12-22 11:05:47 +00:00
3a4f79629c ResourcePackManager: Add API method getPath() 2017-12-22 11:04:15 +00:00
375243860e Potion: Restrict item stack size to 1 2017-12-21 15:02:56 +00:00
a842a5319f Enchantment: Create constant name once, and reuse it
this is more readable and more maintainable.
2017-12-21 13:11:31 +00:00
c2b0f6af22 Enchantment: Simplify getEnchantment() with null coalesce
This is made possible by 0e538ee51d.
2017-12-21 13:02:24 +00:00
6490d99ac2 Enchantment: Added a TODO (calculating XP min/max level cost bounds) 2017-12-21 12:55:55 +00:00
e0b063ac85 Enchantment: Added max level property 2017-12-21 12:49:34 +00:00
12ac2f4ac7 Enchantment: Fixed rarity constant values to match vanilla
Rarity is used for "weighting" enchantments on enchantment tables and such. Therefore higher numbers mean the enchantment is more common. This changes the rarity values to match vanilla.
2017-12-21 12:48:35 +00:00
cc1951c7ba Enchantment: Remove activation type stuff
This isn't and won't be used anywhere.
2017-12-21 12:48:14 +00:00
0e538ee51d Enchantment: Split up enchantment type data and enchantment instance data (#1825)
* Enchantment: Split enchantment type data from instance data
This commit splits enchantments into (effectively) enchantment TYPES vs enchantment INSTANCES.

When applying an enchantment to an item, it only needs to know 2 things:
1. the enchantment ID (identifier) which is used to identify the TYPE
2. the enchantment LEVEL which is used to modify the enchantment's power IN THIS INSTANCE.

Therefore, the LEVEL is not an immutable property. However, all other properties of the currently-named "Enchantment" class are immutable type properties.
Currently, when applying an enchantment to an item, a copy of the enchantment object is created from the registry, and returned. This copies all of the properties contained by the type, which is obviously sub optimal.
2017-12-21 12:40:33 +00:00
1b4b832c8c Added a getEntry() to BanList (#1830) 2017-12-21 10:08:56 +00:00
4f8e4f0522 Add EOF newlines where missing (bulk) (#1836)
This should solve issues with people making GitHub PRs and having the web editor messing things up. GitHub Web Editor sucks :(
2017-12-20 11:56:36 +00:00
0ee78d2416 Update DevTools submodule, fix build 2017-12-17 15:01:05 +00:00
4c46087ffc TextFormat: Added EOL constant (for MCPE)
MCPE always uses LF for line endings. PHP_EOL might be LF, CRLF, or CR depending on the platform, so it should not be used for (for example) sending messages to players containing newlines.
2017-12-17 14:58:37 +00:00
bb3e72ea4b StringTag: Fixed bad error message for bad value type 2017-12-17 12:30:18 +00:00
914e4c9a72 Enchantment: Fix formatting issue 2017-12-16 13:04:25 +00:00
9fd7312629 EnchantCommand: Fix vanilla translation
This parameter isn't required server side, but it doesn't matter anyway.
2017-12-16 10:34:38 +00:00
24387d1efe Enchantment: Add some PhpDoc for fields 2017-12-16 10:01:42 +00:00
3853938ef3 Level: Manage block cache appropriately when loading/unloading/replacing chunks, close #1813 (#1823)
This changes the block cache to be a 2-dimensional hashmap of [chunkHash][blockHash]. This is needed to more effectively dispose of chunk-specific block caches when chunks are modified.

This now destroys the cache for specific chunk indexes in the following circumstances:
- When a chunk is unloaded (the cache isn't needed anymore)
- When a chunk is set into the world (for example, from the generator)
- When a chunk is loaded (probably unnecessary)

This resolves the ghost blocks bug many have been complaining about.
2017-12-16 09:49:48 +00:00
4ec8416f9a Level: Fix minor code duplication in setChunk() 2017-12-15 16:47:59 +00:00
8aff793a4f Fix drops for leaves, close #1821
Seems that leaves are another special case - they technically speaking accept any tool to break, but only drop when shears are used. They don't REQUIRE shears because if they did the break time would be longer for non-shears tools.
2017-12-15 10:14:24 +00:00
d93ded9047 merge 1.2.7 "changes" 2017-12-14 18:59:11 +00:00
fbd04b0fe7 Bump to 1.2.7 2017-12-14 18:56:32 +00:00
953f45c50f Altered armour handling, now works for damage other than PvP 2017-12-14 12:37:28 +00:00
1822abc862 Living: Apply absorption after effect damage reduction is checked 2017-12-14 12:03:12 +00:00
92e966686e Refactor Living->attack() into several methods 2017-12-14 11:39:05 +00:00
3f50f88e2c Player: Cleaned up how hurt animations are handled
Override Living->doHitAnimation() instead to ensure that the animation always gets sent to the player.
2017-12-14 11:34:09 +00:00
532600ab67 Player: Remove another redundant attack check
This is checked in Player->attack() anyway.
2017-12-14 11:03:13 +00:00
78f8fe602c Player: Remove redundant PvP check
This is already checked in a block lower down.
2017-12-14 10:59:17 +00:00
e75fbd7fb4 Changed Effect colours to use Color objects instead of arrays (#1814) 2017-12-14 10:21:07 +00:00
06f605879a Effect: Save and restore ambiency properly 2017-12-14 10:10:26 +00:00
4c7038f941 Effect: Added proper documentation on "ambiency" 2017-12-14 09:57:20 +00:00
4bd4d42b82 Fixed raw porkchop being inedible 2017-12-14 09:09:47 +00:00
f5ebfc3418 Effect: Added Fatal Poison effect
This is identical to normal Poison, except that it kills the victim. Parrots receive this effect when they are fed cookies.
2017-12-13 18:59:49 +00:00
4ae278686c Player: Hack anti-fly to ignore levitation 2017-12-13 18:50:56 +00:00
740786c99e PillarRotationHelper: Drop redundant commit 2017-12-13 18:39:16 +00:00
6abf880e44 Block: Drop unnecessary parameters for ItemFactory::get() 2017-12-13 18:37:04 +00:00
853411fa4f Merge pull request #1795 from pmmp/tools-refactor
Tools refactor
2017-12-13 18:04:12 +00:00
6e30d23254 Added missing properties for several blocks 2017-12-13 16:28:21 +00:00
717b36a983 Cleaned up non-trivial getDrops() stuff 2017-12-13 14:47:50 +00:00
90eed14cd6 Fixed cobweb drops 2017-12-13 14:46:58 +00:00
4452e6ac93 Merge branch 'master' into tools-refactor 2017-12-13 12:58:50 +00:00
56f1a6ba37 Block: Migrated all trivial drops code to getDropsForCompatibleTool()
getDrops() should now be overridden only for special cases. There are some non-trivial overrides left that are going to need some extra work to clean up.
2017-12-13 12:49:58 +00:00
8c47a338df Block: Remove unused imports 2017-12-13 12:44:21 +00:00
7c6535283e SnowLayer: Fixed tool requirement 2017-12-13 12:39:29 +00:00
c669819bbb Fixed stained/hardened clay being harvestable without a pickaxe, close #1803 2017-12-13 12:01:46 +00:00
50f3231629 Fixed being able to mine double stone slabs without a pickaxe 2017-12-13 11:34:41 +00:00
015cde2169 Merge branch 'master' into tools-refactor 2017-12-13 11:26:24 +00:00
b9b50dd5dc Added Block->getDropsForCompatibleTool(), removed lots of boilerplate code from subclasses
The function name is a little long-winded, but that can always be refactored later if needed. This provides a way for blocks requiring specific tools to override drops with non-standard stuff without needing to worry about what tool type was used.

It's also possible that passing the Item used here is actually entirely redundant, but again that can be fixed later.
2017-12-12 20:02:50 +00:00
da3640357c Rename Block->canBeBrokenWith() to isCompatibleWithTool() and add documentation
This name better describes it. "can be broken with" implies that items which this returns false for cannot destroy the block at all, which is incorrect. What this actually returns is whether the item is the best tool to use to break the block.
2017-12-12 19:51:31 +00:00
0004e7429f Added some documentation on harvest level properties 2017-12-12 16:55:00 +00:00
e2e6b7516a Removed WoodenTool classes
These were only needed for their fuel properties, which are the same for all tools of the wooden tier anyway.
2017-12-12 13:55:38 +00:00
b903161a5d Refactored tool efficiency handling
This fixes lots of bugs with things like wool, cobwebs, swords.
2017-12-12 13:55:36 +00:00
99fe63b2a3 Added harvest level properties to applicable blocks
this fixes block-breaking animations with wrong tools, and also finally resolves the long-standing hierarchy problem in Stair.
2017-12-12 13:54:17 +00:00
dbc180315e Declare tool harvest level as a property 2017-12-12 13:54:16 +00:00
45983acc0d Fixed too-fast break times with wrong tool types 2017-12-12 13:54:16 +00:00
a02af1053f Remove redundant overrides from WoodenTools 2017-12-12 13:54:16 +00:00
7de88b9040 Tool tier efficiency should still apply if the block can't be harvested
If you use an iron pickaxe on obsidian, it still mines faster because the tool types are compatible, even though the tool is not high enough.
2017-12-12 13:54:06 +00:00
58327d0514 Change block tool types to bitflags
This allows specification of multiple tool types for a block, such as cobwebs.
2017-12-12 13:51:33 +00:00
db31d13f96 Added Item->getBlockToolType() 2017-12-12 13:45:52 +00:00
55d0684565 Move block-breaking tool-type constants to a BlockToolType interface 2017-12-12 13:45:52 +00:00
7e3cd24444 Added TieredTool->getTier() 2017-12-12 13:45:51 +00:00
2088a43c56 Refactored tool hierarchy 2017-12-12 13:45:51 +00:00
854 changed files with 12763 additions and 14844 deletions

View File

@ -1,6 +1,6 @@
### Issue description
<!---
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
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
@ -28,7 +28,7 @@ NO support whatsoever will be provided for third-party modified variants of Pock
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
-->
* PocketMine-MP:
* PocketMine-MP: <!-- LATEST IS NOT A VALID VERSION -->
* PHP:
* Server OS:
* Game version: PE/Win10 (delete as appropriate)
@ -43,6 +43,6 @@ If the issue is **not** reproducible without plugins:
### Crashdump, backtrace or other files
- Do not paste crashdumps into an issue - please use our Crash Archive at https://crash.pmmp.io for submitting crash reports to not spam the issue tracker. Add links to your reports in the Crash Archive here.
- Please use gist or anything else to add other files and add links here
- Please use gist or anything else to add other files and add links here
* ...

View File

@ -33,4 +33,8 @@ Requires translations:
-->
## Tests
<!-- Attach scripts or actions to test this pull request, as well as the result -->
<!--
Details should be provided of tests done. Simply saying "tested" or equivalent is not acceptable.
Attach scripts or actions to test this pull request, as well as the result
-->

12
.github/support.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# Configuration for support-requests - https://github.com/dessant/support-requests
# Label used to mark issues as support requests
supportLabel: "Support request"
# Comment to post on issues marked as support requests. Add a link
# to a support page, or set to `false` to disable
supportComment: >
This issue tracker is not a support forum. Please use the [forums](https://forums.pmmp.io) for support.
# Whether to close issues marked as support requests
close: true
# Whether to lock issues marked as support requests
lock: false

5
.gitignore vendored
View File

@ -1,14 +1,15 @@
players/*
worlds/*
plugins/*
bin/*
bin*/*
timings/*
crashdumps/*
*.log
*.txt
*.phar
server.properties
/pocketmine.yml
memoryDump_*/*
memory_dumps/*
resource_packs/
# Common IDEs

View File

@ -8,7 +8,7 @@ before_script:
- echo | pecl install channel://pecl.php.net/yaml-2.0.2
- git clone https://github.com/krakjoe/pthreads.git
- cd pthreads
- git checkout 6c6b15138c923b69cfa46ee05fc2dd45da587287
- git checkout d32079fb4a88e6e008104d36dbbf0c2dd7deb403
- phpize
- ./configure
- make

View File

@ -5,58 +5,48 @@
## Creating an Issue
- If you are reporting a bug:
- **make sure that you are using the latest supported version** before opening an issue.
- **test it on a clean test server, WITHOUT PLUGINS**, to see if the issue still occurs. If not then it may be a plugin issue. Please also indicate the result of such tests.
- [Search the issue tracker](https://github.com/pmmp/PocketMine-MP/issues?utf8=%E2%9C%93&q=is%3Aissue) to check if anyone has already reported it, to avoid needlessly creating duplicate issues. Make sure you also check closed issues, as an issue you think is valid may already have been resolved.
- If your issue is related to a plugin, **do not report here, contact the plugin's original author** instead.
- **make sure that you are using the latest supported version** before opening an issue.
- **test it on a clean test server, WITHOUT PLUGINS**, to see if the issue still occurs. If not then it may be a plugin issue. Please also indicate the result of such tests.
- **[Search the issue tracker](https://github.com/pmmp/PocketMine-MP/issues?utf8=%E2%9C%93&q=is%3Aissue)** to check if anyone has already reported it, to avoid needlessly creating duplicate issues. Make sure you also check closed issues, as an issue you think is valid may already have been resolved.
- **Do not report plugin issues here.** If your issue is related to a plugin, contact the plugin's original author instead.
- **Support requests are not bugs.** Issues such as "How do I do this" are not bugs and will be closed. If you need help, please see [here](README.md#discussion) and do not misuse our issue tracker.
- **No generic titles** such as "Question", "Help", "Crash Report" etc. A good issue report provides a quick summary in the title. If you just got a crash report but you don't understand it, please look for a line starting with `Message`. It summarizes the bug.
- Information must be provided in the issue body, not in the title. No tags like `[BUG]` are allowed in the title, including `[SOLVED]` for solved issues.
- Similarly, no generic issue reports. For bugs, it is the issue author's responsibility to provide us an issue that is **trackable, debuggable, reproducible, reported professionally and is an actual bug**.
<br><br>Valid issue reports must include instructions how to reproduce the issue or a crashdump/backtrace (unless the cause of the issue is obvious).
<br><br>**If you do not provide us with a summary or instructions on how to reproduce the issue, it will be treated as spam and will therefore be closed.**
<br><br>In simple words, if the issue cannot be properly confirmed to be valid or lacks required information, the issue will be closed until further information is provided.
- **Provide information in the issue body, not in the title.** No tags like `[BUG]` are allowed in the title, including `[SOLVED]` for solved issues.
- **No generic issue reports.** For bugs, it is the issue author's responsibility to provide us an issue that is **trackable, debuggable, reproducible, reported professionally and is an actual bug**.
<br>Valid issue reports must include instructions how to reproduce the issue or a crashdump/backtrace (unless the cause of the issue is obvious).
<br>**If you do not provide us with a summary or instructions on how to reproduce the issue, it will be treated as spam and will therefore be closed.**
<br>In simple words, if the issue cannot be properly confirmed to be valid or lacks required information, the issue will be closed until further information is provided.
- To express appreciation, objection, confusion or other supported reactions on pull requests, issues or comments on them, use GitHub [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) rather than posting an individual comment with an emoji only. This helps keeping the issue/pull request conversation clean and readable.
- If your issue is related to the PocketMine-MP website, forums, etc., please [talk to a human directly](README.md#discussion).
## Contributing Code
- To contribute code to the repository, [fork it on GitHub](https://github.com/pmmp/PocketMine-MP/fork), create a branch on your fork, and make your changes on your fork. You can then make a [pull request](https://github.com/pmmp/PocketMine-MP/pull/new) to the project to compare your branch to ours and propose your changes to our repository. We use the Pull Request system to allow members of the team to review changes before they are merged.
## Contributing
To contribute to the repository, [fork it on GitHub](https://github.com/pmmp/PocketMine-MP/fork), create a branch on your fork, and make your changes on your fork. You can then make a [pull request](https://github.com/pmmp/PocketMine-MP/pull/new) to the project to compare your branch to ours and propose your changes to our repository. We use the Pull Request system to allow members of the team to review changes before they are merged.
- By proposing a pull request to the project, you agree to your code being distributed within PocketMine-MP under the [LGPL license](LICENSE).
### Licensing
By proposing a pull request to the project, you agree to your code being distributed within PocketMine-MP under the [LGPL license](LICENSE).
- At PocketMine, **we enforce a very high standard for contributions**. This is because PocketMine-MP and its related projects are used very widely in production. While this might seem like we are being mean at times, **our priority is what is best for PocketMine-MP itself**. We try to ensure that our project's codebase is as clean as possible and ensure that only top-quality material makes it through to PocketMine-MP itself. **If a contribution does not live up to our standards, changes may be requested or the pull request may be closed.**
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
- **Avoid using GitHub Web Editor**. The web editor lacks most useful GIT features and **should only be used for very minor changes**. It is immediately clear if the web editor has been used, and if so the PR is more likely to be rejected. If you want to make serious contributions, **please learn how to use [GIT version control](https://git-scm.com/)**.
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit. **Cherry-picking is the politer way to copy somebody's changes** and retains all the original accreditation, so there is no need for copy-pasted commits with descriptions like `Some code, thanks @exampleperson`.
- In addition to the above, **make sure you can explain your changes**. If you can't provide a good explanation of changes, your PR may be rejected.
### Contribution standards
- **We enforce a very high standard for contributions**. This is because PocketMine-MP and its related projects are used very widely in production. While this might seem like we are being mean at times, **our priority is what is best for PocketMine-MP itself**.
We try to ensure that our project's codebase is as clean as possible and ensure that only top-quality material makes it through to PocketMine-MP itself.
- **If a contribution does not meet our standards, changes may be requested or the pull request may be closed.**
### Pull requests
- **Create a new branch for each pull request.** Do not create a pull request with commits that exist in another pull request.
- **Code should use the same style as in PocketMine-MP.** See [below](#code-syntax) for an example.
- **The code must be clear** and written in English, comments included.
- **Use descriptive commit titles.** You can see an example [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
- **Try to stick to one change per commit.** This ensures that if you create a PR with several changes, we can decide which ones we wish to include and which ones not to include.
- **It is inadvisable to create pull requests with large commits** unless this has been discussed with the team beforehand. Large pull requests are difficult to review, and such pull requests may end up being closed. The only exception is when all features in the pull request are related to each other, and share the same core changes.
- **Do not include multiple unrelated changes in one commit.** An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set. See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits. See the [documentation on `git add`](https://git-scm.com/docs/git-add) for information on how to isolate local changes for committing.
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
- **It is inadvisable to create large pull requests with lots of changes** unless this has been discussed with the team beforehand. Large pull requests are difficult to review, and such pull requests may end up being closed. The only exception is when all features in the pull request are related to each other, and share the same core changes.
- **You may be asked to rebase your pull request** if the branch becomes outdated and/or if possibly conflicting changes are made to the target branch. To see how to do this, read [this page](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request).
- **Details should be provided of tests done.** Simply saying "Tested" or equivalent is not acceptable.
### Code contributions
- **Avoid using GitHub Web Editor**. The web editor lacks most useful GIT features and **should only be used for very minor changes**. It is immediately clear if the web editor has been used, and if so the PR is more likely to be rejected. If you want to make serious contributions, **please learn how to use [GIT version control](https://git-scm.com/)**.
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit. **Cherry-picking is the politer way to copy somebody's changes** and retains all the original accreditation, so there is no need for copy-pasted commits with descriptions like `Some code, thanks @exampleperson`.
- **Make sure you can explain your changes**. If you can't provide a good explanation of changes, your PR may be rejected.
- **Code should use the same style as in PocketMine-MP.** See [below](#code-syntax) for an example.
- **The code must be clear** and written in English, comments included.
**Thanks for contributing to PocketMine-MP!**
@ -78,17 +68,18 @@ It is mainly [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accept
- Strings SHOULD use the double quote `"` except when the single quote is required.
- All code SHOULD have parameter and type declarations where possible.
- Strict types SHOULD be enabled on new files where it is sensible to do so.
- All constant declarations SHOULD be preceded by a visibility modifier.
```php
<?php
declare(strict_types = 1);
declare(strict_types=1);
namespace pocketmine\example;
class ExampleClass{
const EXAMPLE_CLASS_CONSTANT = 1;
public const EXAMPLE_CLASS_CONSTANT = 1;
public $examplePublicVariable = "defaultValue";
private $examplePrivateVariable;
@ -99,7 +90,7 @@ class ExampleClass{
* @param string $firstArgument the first argument
* @param string|null $secondArgument default null
*/
public function __construct(string $firstArgument, &$secondArgument = null){
public function __construct(string $firstArgument, ?string &$secondArgument = null){
if($firstArgument === "exampleValue"){ //Remember to use === instead of == when possible
//do things
}elseif($firstArgument === "otherValue"){
@ -119,7 +110,6 @@ class ExampleClass{
public function doStuff(string $stuff) : string{
return $stuff;
}
}
```
@ -133,4 +123,4 @@ class ExampleClass{
* After voting has been closed, no further votes will be counted.
* An RFC will be rejected if less than 50% + 1 (simple majority) has voted Yes.
* If the RFC is approved, Team Members have the final word on its implementation or rejection.
* RFCs with complex voting options will specify the vote percentage or other details.
* RFCs with complex voting options will specify the vote percentage or other details.

View File

@ -10,7 +10,6 @@ If you don't find what you're looking for there, [talk to a human](#discussion).
### Discussion
- [Forums](https://forums.pmmp.io/)
- [#pmmp + #pocketmine channel IRC](http://webchat.freenode.net/?channels=pmmp,pocketmine)
### Plugins
There are a very wide range of already-written plugins available which you can use to customise your server. Check out [Poggit](https://poggit.pmmp.io), or just search GitHub.
@ -23,7 +22,10 @@ There are a very wide range of already-written plugins available which you can u
Yes you can! Contributions are welcomed provided that they comply with our [Contributing Guidelines](CONTRIBUTING.md). Please ensure you read the relevant sections of the guidelines carefully before making a Pull Request or opening an Issue.
### Where can I get the latest .phar?
Head over to our [official Jenkins server](https://jenkins.pmmp.io/)
- Latest release builds can be found in our [GitHub releases](https://github.com/pmmp/PocketMine-MP/releases).
- Latest bleeding-edge development builds (and other builds in the build job channels) can be found on our [Jenkins server](https://jenkins.pmmp.io/).
**Note: Please avoid development builds unless there is no other alternative for what you need.** Development builds are subject to changes at any time without notice, and it is likely that your server or plugins might break without warning.
## Third-party Libraries/Protocols Used
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__

View File

@ -1,11 +1,11 @@
{
"name": "pmmp/pocketmine-mp",
"name": "pocketmine/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.0RC3",
"php": ">=7.2.0",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-hash": "*",
@ -21,11 +21,14 @@
"ext-yaml": ">=2.0.0",
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"pmmp/raklib": "dev-master#29ab14d5d8640a8ee359ce315b083a129e72db4a",
"pmmp/pocketmine-spl": "^0.1.0"
"pocketmine/raklib": "0.11.0",
"pocketmine/spl": "0.3.0",
"pocketmine/binaryutils": "0.0.1",
"pocketmine/nbt": "0.1.0",
"pocketmine/math": "0.1.0"
},
"autoload": {
"psr-0": {
"psr-4": {
"": ["src"]
}
},
@ -36,7 +39,19 @@
},
{
"type": "vcs",
"url": "https://github.com/pmmp/PocketMine-SPL"
"url": "https://github.com/pmmp/SPL"
},
{
"type": "vcs",
"url": "https://github.com/pmmp/BinaryUtils"
},
{
"type": "vcs",
"url": "https://github.com/pmmp/NBT"
},
{
"type": "vcs",
"url": "https://github.com/pmmp/Math"
}
]
}

204
composer.lock generated
View File

@ -4,20 +4,163 @@
"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": "169d2724a6847e704f3bb76030bebc87",
"content-hash": "401dbada37e501304f05b0f1fa818953",
"packages": [
{
"name": "pmmp/pocketmine-spl",
"version": "0.1.0",
"name": "pocketmine/binaryutils",
"version": "0.0.1",
"source": {
"type": "git",
"url": "https://github.com/pmmp/PocketMine-SPL.git",
"reference": "c56936e6aaad925bb60002b29b1c70f497af4679"
"url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "03e6851f814aba96487ec64181a6ae948edd9f7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/PocketMine-SPL/zipball/c56936e6aaad925bb60002b29b1c70f497af4679",
"reference": "c56936e6aaad925bb60002b29b1c70f497af4679",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/03e6851f814aba96487ec64181a6ae948edd9f7a",
"reference": "03e6851f814aba96487ec64181a6ae948edd9f7a",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"autoload": {
"psr-4": {
"pocketmine\\utils\\": "src/"
}
},
"license": [
"LGPL-3.0"
],
"description": "Classes and methods for conveniently handling binary data",
"support": {
"source": "https://github.com/pmmp/BinaryUtils/tree/master",
"issues": "https://github.com/pmmp/BinaryUtils/issues"
},
"time": "2018-03-17T11:57:06+00:00"
},
{
"name": "pocketmine/math",
"version": "0.1.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "1df74f0352309a9c1e6728fa416a3f0493d07b16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/1df74f0352309a9c1e6728fa416a3f0493d07b16",
"reference": "1df74f0352309a9c1e6728fa416a3f0493d07b16",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"pocketmine\\math\\": "src/"
}
},
"license": [
"LGPL-3.0"
],
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"source": "https://github.com/pmmp/Math/tree/master",
"issues": "https://github.com/pmmp/Math/issues"
},
"time": "2018-03-18T18:01:56+00:00"
},
{
"name": "pocketmine/nbt",
"version": "0.1.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "d79f8615442887bb45cfacdb52e1e6eb47c38fd7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/d79f8615442887bb45cfacdb52e1e6eb47c38fd7",
"reference": "d79f8615442887bb45cfacdb52e1e6eb47c38fd7",
"shasum": ""
},
"require": {
"php": ">=7.2.0",
"pocketmine/binaryutils": "0.0.1"
},
"type": "library",
"autoload": {
"psr-4": {
"pocketmine\\nbt\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"pocketmine\\nbt\\": "tests/phpunit/"
}
},
"license": [
"LGPL-3.0"
],
"description": "PHP library for working with Named Binary Tags",
"support": {
"source": "https://github.com/pmmp/NBT/tree/0.1.0",
"issues": "https://github.com/pmmp/NBT/issues"
},
"time": "2018-04-13T18:43:03+00:00"
},
{
"name": "pocketmine/raklib",
"version": "0.11.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "1da1b4c6cc6bd5337ce5e468d22bbb013ae02b43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/1da1b4c6cc6bd5337ce5e468d22bbb013ae02b43",
"reference": "1da1b4c6cc6bd5337ce5e468d22bbb013ae02b43",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-sockets": "*",
"php": ">=7.2.0RC3",
"pocketmine/binaryutils": "0.0.1",
"pocketmine/spl": "0.3.0"
},
"type": "library",
"autoload": {
"classmap": [
"./"
]
},
"license": [
"GPL-3.0"
],
"description": "A RakNet server implementation written in PHP",
"support": {
"source": "https://github.com/pmmp/RakLib/tree/0.11.0",
"issues": "https://github.com/pmmp/RakLib/issues"
},
"time": "2018-04-13T19:05:24+00:00"
},
{
"name": "pocketmine/spl",
"version": "0.3.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/SPL.git",
"reference": "ee32424c100fd11ae7f7b8df7604623fd475f0ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/SPL/zipball/ee32424c100fd11ae7f7b8df7604623fd475f0ec",
"reference": "ee32424c100fd11ae7f7b8df7604623fd475f0ec",
"shasum": ""
},
"type": "library",
@ -34,60 +177,21 @@
],
"description": "Standard library files required by PocketMine-MP and related projects",
"support": {
"source": "https://github.com/pmmp/PocketMine-SPL/tree/master"
"source": "https://github.com/pmmp/SPL/tree/master"
},
"time": "2017-12-10T12:18:30+00:00"
},
{
"name": "pmmp/raklib",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "29ab14d5d8640a8ee359ce315b083a129e72db4a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/29ab14d5d8640a8ee359ce315b083a129e72db4a",
"reference": "29ab14d5d8640a8ee359ce315b083a129e72db4a",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"ext-pthreads": ">=3.1.7dev",
"ext-sockets": "*",
"php": ">=7.2.0RC3",
"pmmp/pocketmine-spl": "^0.1.0"
},
"type": "library",
"autoload": {
"classmap": [
"./"
]
},
"license": [
"GPL-3.0"
],
"description": "A RakNet server implementation written in PHP",
"support": {
"source": "https://github.com/pmmp/RakLib/tree/master",
"issues": "https://github.com/pmmp/RakLib/issues"
},
"time": "2017-12-10T12:24:38+00:00"
"time": "2018-03-17T11:56:20+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"php": 5,
"ext-pthreads": 20,
"pmmp/raklib": 20
"ext-pthreads": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.2.0RC3",
"php": ">=7.2.0",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-hash": "*",

View File

@ -44,7 +44,7 @@ PROJECT_NUMBER = "PM_VERSION - API PM_API"
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF =
PROJECT_BRIEF =
# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
# the documentation. The maximum height of the logo should not exceed 55 pixels
@ -151,7 +151,7 @@ FULL_PATH_NAMES = NO
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
STRIP_FROM_INC_PATH =
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
@ -218,13 +218,13 @@ TAB_SIZE = 4
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
ALIASES =
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
@ -268,7 +268,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
EXTENSION_MAPPING =
EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
@ -600,7 +600,7 @@ GENERATE_DEPRECATEDLIST= YES
# sections, marked by \if <section_label> ... \endif and \cond <section_label>
# ... \endcond blocks.
ENABLED_SECTIONS =
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
# initial value of a variable or macro / define can have for it to appear in the
@ -642,7 +642,7 @@ SHOW_NAMESPACES = YES
# by doxygen. Whatever the program writes to standard output is used as the file
# version. For an example see the documentation.
FILE_VERSION_FILTER =
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
@ -655,7 +655,7 @@ FILE_VERSION_FILTER =
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
LAYOUT_FILE =
LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
@ -666,7 +666,7 @@ LAYOUT_FILE =
# search path. Do not use file names with spaces, bibtex cannot handle them. See
# also \cite for info how to create references.
CITE_BIB_FILES =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
@ -725,7 +725,7 @@ WARN_FORMAT = "$file:$line: $text"
# messages should be written. If left blank the output is written to standard
# error (stderr).
WARN_LOGFILE =
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
@ -774,7 +774,7 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@ -804,13 +804,13 @@ EXCLUDE_PATTERNS = */bin/* \
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
# command).
EXAMPLE_PATH =
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
@ -830,7 +830,7 @@ EXAMPLE_RECURSIVE = NO
# that contain images that are to be included in the documentation (see the
# \image command).
IMAGE_PATH =
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@ -847,7 +847,7 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
INPUT_FILTER =
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
@ -856,7 +856,7 @@ INPUT_FILTER =
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER ) will also be used to filter the input files that are used for
@ -871,7 +871,7 @@ FILTER_SOURCE_FILES = NO
# *.ext= (so without naming a filter).
# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
FILTER_SOURCE_PATTERNS =
FILTER_SOURCE_PATTERNS =
# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
# is part of the input, its contents will be placed on the main page
@ -983,7 +983,7 @@ CLANG_ASSISTED_PARSING = NO
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
@ -1009,7 +1009,7 @@ COLS_IN_ALPHA_INDEX = 5
# while generating the index headers.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
@ -1053,7 +1053,7 @@ HTML_FILE_EXTENSION = .html
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
@ -1063,7 +1063,7 @@ HTML_HEADER =
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER =
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of
@ -1075,7 +1075,7 @@ HTML_FOOTER =
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
# defined cascading style sheet that is included after the standard style sheets
@ -1086,7 +1086,7 @@ HTML_STYLESHEET =
# see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
@ -1096,7 +1096,7 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the stylesheet and background images according to
@ -1224,7 +1224,7 @@ GENERATE_HTMLHELP = NO
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler ( hhc.exe). If non-empty
@ -1232,7 +1232,7 @@ CHM_FILE =
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated (
# YES) or that it should be included in the master .chm file ( NO).
@ -1245,7 +1245,7 @@ GENERATE_CHI = NO
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated (
# YES) or a normal table of contents ( NO) in the .chm file.
@ -1275,7 +1275,7 @@ GENERATE_QHP = NO
# the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE =
QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
@ -1300,7 +1300,7 @@ QHP_VIRTUAL_FOLDER = doc
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
@ -1308,21 +1308,21 @@ QHP_CUST_FILTER_NAME =
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
QHG_LOCATION =
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
# generated, together with the HTML files, they form an Eclipse help plugin. To
@ -1455,7 +1455,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
@ -1463,7 +1463,7 @@ MATHJAX_EXTENSIONS =
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_CODEFILE =
MATHJAX_CODEFILE =
# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
# the HTML output. The underlying search engine uses javascript and DHTML and
@ -1523,7 +1523,7 @@ EXTERNAL_SEARCH = NO
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
SEARCHENGINE_URL =
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
# search data is written to a file for indexing by an external tool. With the
@ -1539,7 +1539,7 @@ SEARCHDATA_FILE = searchdata.xml
# projects and redirect the results back to the right project.
# This tag requires that the tag SEARCHENGINE is set to YES.
EXTERNAL_SEARCH_ID =
EXTERNAL_SEARCH_ID =
# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
# projects other than the one defined by this configuration file, but that are
@ -1549,7 +1549,7 @@ EXTERNAL_SEARCH_ID =
# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
# This tag requires that the tag SEARCHENGINE is set to YES.
EXTRA_SEARCH_MAPPINGS =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
@ -1610,7 +1610,7 @@ PAPER_TYPE = a4
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
EXTRA_PACKAGES =
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
# generated LaTeX document. The header should contain everything until the first
@ -1626,7 +1626,7 @@ EXTRA_PACKAGES =
# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
@ -1635,7 +1635,7 @@ LATEX_HEADER =
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
LATEX_FOOTER =
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
@ -1643,7 +1643,7 @@ LATEX_FOOTER =
# markers available.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_FILES =
LATEX_EXTRA_FILES =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
@ -1743,14 +1743,14 @@ RTF_HYPERLINKS = NO
# default style sheet that doxygen normally uses.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_STYLESHEET_FILE =
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# Configuration options related to the man page output
@ -1811,13 +1811,13 @@ XML_OUTPUT = xml
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_SCHEMA =
XML_SCHEMA =
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
# validating XML parser to check the syntax of the XML files.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_DTD =
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
@ -1894,7 +1894,7 @@ PERLMOD_PRETTY = YES
# overwrite each other's variables.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_MAKEVAR_PREFIX =
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
@ -1935,7 +1935,7 @@ SEARCH_INCLUDES = YES
# preprocessor.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
@ -1943,7 +1943,7 @@ INCLUDE_PATH =
# used.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
INCLUDE_FILE_PATTERNS =
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that are
# defined before the preprocessor is started (similar to the -D option of e.g.
@ -1953,7 +1953,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED =
PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@ -1962,7 +1962,7 @@ PREDEFINED =
# definition found in the source code.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_AS_DEFINED =
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all refrences to function-like macros that are alone on a line, have an
@ -1991,13 +1991,13 @@ SKIP_FUNCTION_MACROS = YES
# the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here.
TAGFILES =
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
# tag file that is based on the input files it reads. See section "Linking to
# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE =
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
# class index. If set to NO only the inherited external classes will be listed.
@ -2045,14 +2045,14 @@ CLASS_DIAGRAMS = NO
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
MSCGEN_PATH =
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
DIA_PATH =
# If set to YES, the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
@ -2101,7 +2101,7 @@ DOT_FONTSIZE = 10
# the path where dot can find it using this tag.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
# each documented class showing the direct and indirect inheritance relations.
@ -2239,26 +2239,26 @@ INTERACTIVE_SVG = YES
# found. If left blank, it is assumed the dot tool can be found in the path.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_PATH =
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the \dotfile
# command).
# This tag requires that the tag HAVE_DOT is set to YES.
DOTFILE_DIRS =
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
MSCFILE_DIRS =
MSCFILE_DIRS =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
# command).
DIAFILE_DIRS =
DIAFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
@ -2319,4 +2319,3 @@ GENERATE_LEGEND = YES
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine;
use pocketmine\event\TranslationContainer;
use pocketmine\lang\TranslationContainer;
use pocketmine\utils\TextFormat;
/**
@ -116,7 +116,7 @@ abstract class Achievement{
public static function broadcast(Player $player, string $achievementId) : bool{
if(isset(Achievement::$list[$achievementId])){
$translation = new TranslationContainer("chat.type.achievement", [$player->getDisplayName(), TextFormat::GREEN . Achievement::$list[$achievementId]["name"] . TextFormat::RESET]);
if(Server::getInstance()->getConfigBool("announce-player-achievements", true) === true){
if(Server::getInstance()->getConfigBool("announce-player-achievements", true)){
Server::getInstance()->broadcastMessage($translation);
}else{
$player->sendMessage($translation);

View File

@ -115,10 +115,10 @@ class CrashDump{
}
private function extraData(){
global $arguments;
global $argv;
if($this->server->getProperty("auto-report.send-settings", true) !== false){
$this->data["parameters"] = (array) $arguments;
$this->data["parameters"] = (array) $argv;
$this->data["server.properties"] = @file_get_contents($this->server->getDataPath() . "server.properties");
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $this->data["server.properties"]);
$this->data["pocketmine.yml"] = @file_get_contents($this->server->getDataPath() . "pocketmine.yml");
@ -148,7 +148,7 @@ class CrashDump{
$error = $lastExceptionError;
}else{
$error = (array) error_get_last();
$error["trace"] = getTrace(4); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump
$error["trace"] = Utils::getTrace(4); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump
$errorConversion = [
E_ERROR => "E_ERROR",
E_WARNING => "E_WARNING",
@ -167,7 +167,7 @@ class CrashDump{
E_USER_DEPRECATED => "E_USER_DEPRECATED"
];
$error["fullFile"] = $error["file"];
$error["file"] = cleanPath($error["file"]);
$error["file"] = Utils::cleanPath($error["file"]);
$error["type"] = $errorConversion[$error["type"]] ?? $error["type"];
if(($pos = strpos($error["message"], "\n")) !== false){
$error["message"] = substr($error["message"], 0, $pos);
@ -186,7 +186,7 @@ class CrashDump{
$this->addLine("Line: " . $error["line"]);
$this->addLine("Type: " . $error["type"]);
if(strpos($error["file"], "src/pocketmine/") === false and strpos($error["file"], "src/raklib/") === false and file_exists($error["fullFile"])){
if(strpos($error["file"], "src/pocketmine/") === false and strpos($error["file"], "vendor/pocketmine/") === false and file_exists($error["fullFile"])){
$this->addLine();
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
$this->data["plugin"] = true;
@ -195,7 +195,7 @@ class CrashDump{
$file = $reflection->getProperty("file");
$file->setAccessible(true);
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
$filePath = \pocketmine\cleanPath($file->getValue($plugin));
$filePath = Utils::cleanPath($file->getValue($plugin));
if(strpos($error["file"], $filePath) === 0){
$this->data["plugin"] = $plugin->getName();
$this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName());
@ -257,4 +257,4 @@ class CrashDump{
fwrite($this->fp, $str);
}
}
}

View File

@ -24,9 +24,9 @@ declare(strict_types=1);
namespace pocketmine;
use pocketmine\event\server\LowMemoryEvent;
use pocketmine\event\Timings;
use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings;
use pocketmine\utils\MainLogger;
use pocketmine\utils\Utils;
@ -265,7 +265,7 @@ class MemoryManager{
*/
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);
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize);
if($this->dumpWorkers){
$scheduler = $this->server->getScheduler();
@ -278,13 +278,14 @@ class MemoryManager{
/**
* Static memory dumper accessible from any thread.
*
* @param mixed $startingObject
* @param \ClassLoader $loader
* @param string $outputFolder
* @param int $maxNesting
* @param int $maxStringSize
* @param mixed $startingObject
* @param string $outputFolder
* @param int $maxNesting
* @param int $maxStringSize
*
* @throws \ReflectionException
*/
public static function dumpMemory($startingObject, \ClassLoader $loader, string $outputFolder, int $maxNesting, int $maxStringSize){
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize){
$hardLimit = ini_get('memory_limit');
ini_set('memory_limit', '-1');
gc_disable();
@ -306,7 +307,7 @@ class MemoryManager{
$staticProperties = [];
$staticCount = 0;
foreach($loader->getClasses() as $className){
foreach(get_declared_classes() as $className){
$reflection = new \ReflectionClass($className);
$staticProperties[$className] = [];
foreach($reflection->getProperties() as $property){
@ -330,7 +331,7 @@ class MemoryManager{
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
MainLogger::getLogger()->info("[Dump] Wrote $staticCount static properties");
if($GLOBALS !== null){ //This might be null if we're on a different thread
if(isset($GLOBALS)){ //This might be null if we're on a different thread
$globalVariables = [];
$globalCount = 0;

View File

@ -72,7 +72,7 @@ class OfflinePlayer implements IPlayer, Metadatable{
return;
}
if($value === true){
if($value){
$this->server->addOp(strtolower($this->getName()));
}else{
$this->server->removeOp(strtolower($this->getName()));
@ -84,7 +84,7 @@ class OfflinePlayer implements IPlayer, Metadatable{
}
public function setBanned(bool $value){
if($value === true){
if($value){
$this->server->getNameBans()->addBan($this->getName(), null, null, null);
}else{
$this->server->getNameBans()->remove($this->getName());
@ -96,7 +96,7 @@ class OfflinePlayer implements IPlayer, Metadatable{
}
public function setWhitelisted(bool $value){
if($value === true){
if($value){
$this->server->addWhitelist(strtolower($this->getName()));
}else{
$this->server->removeWhitelist(strtolower($this->getName()));

File diff suppressed because it is too large Load Diff

View File

@ -71,37 +71,99 @@ namespace {
namespace pocketmine {
use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
use pocketmine\utils\ServerKiller;
use pocketmine\utils\Terminal;
use pocketmine\utils\Timezone;
use pocketmine\utils\Utils;
use pocketmine\wizard\SetupWizard;
use raklib\RakLib;
const NAME = "PocketMine-MP";
const VERSION = "1.7dev";
const API_VERSION = "3.0.0-ALPHA10";
const API_VERSION = "3.0.0-ALPHA12";
const CODENAME = "[REDACTED]";
const MIN_PHP_VERSION = "7.2.0RC3";
const MIN_PHP_VERSION = "7.2.0";
function critical_error($message){
echo "[ERROR] $message" . PHP_EOL;
}
/*
* Startup code. Do not look at it, it may harm you.
* Most of them are hacks to fix date-related bugs, or basic functions used after this
* This is the only non-class based file on this project.
* Enjoy it as much as I did writing it. I don't want to do it again.
*/
if(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;
critical_error(\pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . ".");
critical_error("Please use the installer provided on the homepage, or update to a newer PHP version.");
exit(1);
}
if(!extension_loaded("pthreads")){
echo "[CRITICAL] Unable to find the pthreads extension." . PHP_EOL;
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
if(PHP_INT_SIZE < 8){
critical_error("Running " . \pocketmine\NAME . " with 32-bit systems/PHP is no longer supported.");
critical_error("Please upgrade to a 64-bit system, or use a 64-bit PHP binary if this is a 64-bit system.");
exit(1);
}
/* Dependencies check */
$errors = 0;
if(php_sapi_name() !== "cli"){
critical_error("You must run " . \pocketmine\NAME . " using the CLI.");
++$errors;
}
$extensions = [
"bcmath" => "BC Math",
"curl" => "cURL",
"json" => "JSON",
"mbstring" => "Multibyte String",
"openssl" => "OpenSSL",
"phar" => "Phar",
"pthreads" => "pthreads",
"sockets" => "Sockets",
"yaml" => "YAML",
"zip" => "Zip",
"zlib" => "Zlib"
];
foreach($extensions as $ext => $name){
if(!extension_loaded($ext)){
critical_error("Unable to find the $name ($ext) extension.");
++$errors;
}
}
if(extension_loaded("pthreads")){
$pthreads_version = phpversion("pthreads");
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "3.1.7-dev") < 0){
critical_error("pthreads >= 3.1.7-dev is required, while you have $pthreads_version.");
++$errors;
}
}
if(extension_loaded("leveldb")){
$leveldb_version = phpversion("leveldb");
if(version_compare($leveldb_version, "0.2.1") < 0){
critical_error("php-leveldb >= 0.2.1 is required, while you have $leveldb_version");
++$errors;
}
}
if(extension_loaded("pocketmine")){
critical_error("The native PocketMine extension is no longer supported.");
++$errors;
}
if($errors > 0){
critical_error("Please use the installer provided on the homepage, or recompile PHP again.");
exit(1);
}
@ -117,12 +179,6 @@ namespace pocketmine {
set_error_handler('\pocketmine\error_handler');
if(!extension_loaded("phar")){
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
exit(1);
}
if(\Phar::running(true) !== ""){
define('pocketmine\PATH', \Phar::running(true) . "/");
}else{
@ -132,8 +188,8 @@ namespace pocketmine {
define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
function composer_error_die($message){
echo "[CRITICAL] $message" . PHP_EOL;
echo "[CRITICAL] Please install/update Composer dependencies or use provided builds." . PHP_EOL;
critical_error($message);
critical_error("Please install/update Composer dependencies or use provided builds.");
exit(1);
}
@ -146,8 +202,8 @@ namespace pocketmine {
if(!class_exists(RakLib::class)){
composer_error_die("Unable to find the RakLib library.");
}
if(version_compare(RakLib::VERSION, "0.9.0") < 0){ //TODO: remove this check (it's managed by Composer now)
composer_error_die("RakLib version 0.9.0 is required, while you have version " . RakLib::VERSION . ".");
if(version_compare(RakLib::VERSION, "0.11.0") < 0){ //TODO: remove this check (it's managed by Composer now)
composer_error_die("RakLib version 0.11.0 is required, while you have version " . RakLib::VERSION . ".");
}
if(!class_exists(\BaseClassLoader::class)){
composer_error_die("Unable to find the PocketMine-SPL library.");
@ -157,8 +213,6 @@ namespace pocketmine {
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
*/
$autoloader = new \BaseClassLoader();
$autoloader->addPath(\pocketmine\PATH . "src");
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
$autoloader->register(false);
set_time_limit(0); //Who set it to 30 seconds?!?!
@ -175,8 +229,8 @@ namespace pocketmine {
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-profiler"]);
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \realpath(\getcwd()) . DIRECTORY_SEPARATOR);
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \realpath(\getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
Terminal::init();
@ -186,176 +240,16 @@ namespace pocketmine {
mkdir(\pocketmine\DATA, 0777, true);
}
//Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone.
date_default_timezone_set("UTC");
//Logger has a dependency on timezone
$tzError = Timezone::init();
$logger = new MainLogger(\pocketmine\DATA . "server.log");
$logger->registerStatic();
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);
break;
}
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()){
case 'win':
$regex = '/(UTC)(\+*\-*\d*\d*\:*\d*\d*)/';
/*
* wmic timezone get Caption
* Get the timezone offset
*
* Sample Output var_dump
* array(3) {
* [0] =>
* string(7) "Caption"
* [1] =>
* string(20) "(UTC+09:30) Adelaide"
* [2] =>
* string(0) ""
* }
*/
exec("wmic timezone get Caption", $output);
$string = trim(implode("\n", $output));
//Detect the Time Zone string
preg_match($regex, $string, $matches);
if(!isset($matches[2])){
return false;
}
$offset = $matches[2];
if($offset == ""){
return "UTC";
}
return parse_offset($offset);
case 'linux':
// Ubuntu / Debian.
if(file_exists('/etc/timezone')){
$data = file_get_contents('/etc/timezone');
if($data){
return trim($data);
}
}
// RHEL / CentOS
if(file_exists('/etc/sysconfig/clock')){
$data = parse_ini_file('/etc/sysconfig/clock');
if(!empty($data['ZONE'])){
return trim($data['ZONE']);
}
}
//Portable method for incompatible linux distributions.
$offset = trim(exec('date +%:z'));
if($offset == "+00:00"){
return "UTC";
}
return parse_offset($offset);
case 'mac':
if(is_link('/etc/localtime')){
$filename = readlink('/etc/localtime');
if(strpos($filename, '/usr/share/zoneinfo/') === 0){
$timezone = substr($filename, 20);
return trim($timezone);
}
}
return false;
default:
return false;
}
}
/**
* @param string $offset In the format of +09:00, +02:00, -04:00 etc.
*
* @return string|bool
*/
function parse_offset($offset){
//Make signed offsets unsigned for date_parse
if(strpos($offset, '-') !== false){
$negative_offset = true;
$offset = str_replace('-', '', $offset);
}else{
if(strpos($offset, '+') !== false){
$negative_offset = false;
$offset = str_replace('+', '', $offset);
}else{
return false;
}
}
$parsed = date_parse($offset);
$offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];
//After date_parse is done, put the sign back
if($negative_offset == true){
$offset = -abs($offset);
}
//And then, look the offset up.
//timezone_name_from_abbr is not used because it returns false on some(most) offsets because it's mapping function is weird.
//That's been a bug in PHP since 2008!
foreach(timezone_abbreviations_list() as $zones){
foreach($zones as $timezone){
if($timezone['offset'] == $offset){
return $timezone['timezone_id'];
}
}
}
return false;
foreach($tzError as $e){
$logger->warning($e);
}
unset($tzError);
if(isset($opts["enable-profiler"])){
if(function_exists("profiler_enable")){
@ -366,177 +260,39 @@ namespace pocketmine {
}
}
function kill($pid){
switch(Utils::getOS()){
case "win":
exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL");
break;
case "mac":
case "linux":
default:
if(function_exists("posix_kill")){
posix_kill($pid, SIGKILL);
}else{
exec("kill -9 " . ((int) $pid) . " > /dev/null 2>&1");
}
}
if(extension_loaded("xdebug")){
$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);
}
/**
* @param object $value
* @param bool $includeCurrent
*
* @return int
*/
function getReferenceCount($value, $includeCurrent = true){
ob_start();
debug_zval_dump($value);
$ret = explode("\n", ob_get_contents());
ob_end_clean();
if(count($ret) >= 1 and preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
return ((int) $m[1]) - ($includeCurrent ? 3 : 4); //$value + zval call + extra call
}
return -1;
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
}
/**
* @param int $start
* @param array|null $trace
*
* @return array
*/
function getTrace($start = 0, $trace = null){
if($trace === null){
if(function_exists("xdebug_get_function_stack")){
$trace = array_reverse(xdebug_get_function_stack());
}else{
$e = new \Exception();
$trace = $e->getTrace();
$gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){
if(Utils::execute("git rev-parse HEAD", $out) === 0){
$gitHash = trim($out);
if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified
$gitHash .= "-dirty";
}
}
$messages = [];
$j = 0;
for($i = (int) $start; isset($trace[$i]); ++$i, ++$j){
$params = "";
if(isset($trace[$i]["args"]) or isset($trace[$i]["params"])){
if(isset($trace[$i]["args"])){
$args = $trace[$i]["args"];
}else{
$args = $trace[$i]["params"];
}
$params = implode(", ", array_map(function($value){
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"]) : "") . "(" . (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) . ")";
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
return $messages;
}
function cleanPath($path){
return str_replace(["\\", ".php", "phar://", str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH)], ["/", "", "", "", ""], $path);
}
define('pocketmine\GIT_COMMIT', $gitHash);
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
$exitCode = 0;
do{
$errors = 0;
if(PHP_INT_SIZE < 8){
$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\NAME . " using the CLI.");
++$errors;
}
$pthreads_version = phpversion("pthreads");
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$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;
}
if(extension_loaded("leveldb")){
$leveldb_version = phpversion("leveldb");
if(version_compare($leveldb_version, "0.2.1") < 0){
$logger->critical("php-leveldb >= 0.2.1 is required, while you have $leveldb_version");
++$errors;
}
}
if(extension_loaded("pocketmine")){
if(version_compare(phpversion("pocketmine"), "0.0.1") < 0){
$logger->critical("You have the native PocketMine extension, but your version is lower than 0.0.1.");
++$errors;
}elseif(version_compare(phpversion("pocketmine"), "0.0.4") > 0){
$logger->critical("You have the native PocketMine extension, but your version is higher than 0.0.4.");
++$errors;
}
}
if(extension_loaded("xdebug")){
$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 = [
"bcmath" => "BC Math",
"curl" => "cURL",
"json" => "JSON",
"mbstring" => "Multibyte String",
"yaml" => "YAML",
"sockets" => "Sockets",
"zip" => "Zip",
"zlib" => "Zlib"
];
foreach($extensions as $ext => $name){
if(!extension_loaded($ext)){
$logger->critical("Unable to find the $name ($ext) extension.");
++$errors;
}
}
if($errors > 0){
$logger->critical("Please use the installer provided on the homepage, or recompile PHP again.");
$exitCode = 1;
break;
}
$gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){
if(Utils::execute("git rev-parse HEAD", $out) === 0){
$gitHash = trim($out);
if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified
$gitHash .= "-dirty";
}
}
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
}
define('pocketmine\GIT_COMMIT', $gitHash);
@define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN));
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
$installer = new SetupWizard();
if(!$installer->run()){
@ -545,25 +301,20 @@ namespace pocketmine {
}
}
if(\Phar::running(true) === ""){
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
}
ThreadManager::init();
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
$logger->info("Stopping other threads");
$killer = new ServerKiller(8);
$killer->start();
$killer->start(PTHREADS_INHERIT_NONE);
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
if(ThreadManager::getInstance()->stopAll() > 0){
if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
}
kill(getmypid());
Utils::kill(getmypid());
}
}while(false);

View File

@ -33,8 +33,6 @@ use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Attribute;
use pocketmine\entity\Effect;
use pocketmine\entity\Entity;
use pocketmine\entity\Skin;
use pocketmine\event\HandlerList;
@ -43,30 +41,22 @@ use pocketmine\event\level\LevelLoadEvent;
use pocketmine\event\player\PlayerDataSaveEvent;
use pocketmine\event\server\QueryRegenerateEvent;
use pocketmine\event\server\ServerCommandEvent;
use pocketmine\event\TextContainer;
use pocketmine\event\Timings;
use pocketmine\event\TimingsHandler;
use pocketmine\inventory\CraftingManager;
use pocketmine\inventory\Recipe;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\lang\BaseLang;
use pocketmine\level\format\io\leveldb\LevelDB;
use pocketmine\lang\TextContainer;
use pocketmine\level\format\io\LevelProvider;
use pocketmine\level\format\io\LevelProviderManager;
use pocketmine\level\format\io\region\Anvil;
use pocketmine\level\format\io\region\McRegion;
use pocketmine\level\format\io\region\PMAnvil;
use pocketmine\level\generator\biome\Biome;
use pocketmine\level\generator\Flat;
use pocketmine\level\generator\Generator;
use pocketmine\level\generator\hell\Nether;
use pocketmine\level\generator\normal\Normal;
use pocketmine\level\Level;
use pocketmine\level\LevelException;
use pocketmine\metadata\EntityMetadataStore;
use pocketmine\metadata\LevelMetadataStore;
use pocketmine\metadata\PlayerMetadataStore;
use pocketmine\nbt\BigEndianNBTStream;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
@ -77,6 +67,7 @@ use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\AdvancedSourceInterface;
use pocketmine\network\CompressBatchedTask;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
@ -100,6 +91,8 @@ use pocketmine\scheduler\FileWriteTask;
use pocketmine\scheduler\SendUsageTask;
use pocketmine\scheduler\ServerScheduler;
use pocketmine\tile\Tile;
use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler;
use pocketmine\updater\AutoUpdater;
use pocketmine\utils\Binary;
use pocketmine\utils\Config;
@ -262,9 +255,6 @@ class Server{
/** @var Player[] */
private $playerList = [];
/** @var string[] */
private $identifiers = [];
/** @var Level[] */
private $levels = [];
@ -282,7 +272,7 @@ class Server{
* @return bool
*/
public function isRunning() : bool{
return $this->isRunning === true;
return $this->isRunning;
}
/**
@ -520,16 +510,6 @@ class Server{
return -1;
}
/**
* @deprecated Moved to {@link Level#getDifficultyFromString}
*
* @param string $str
* @return int
*/
public static function getDifficultyFromString(string $str) : int{
return Level::getDifficultyFromString($str);
}
/**
* Returns Server global difficulty. Note that this may be overridden in individual Levels.
* @return int
@ -639,7 +619,7 @@ class Server{
/**
* @return ResourcePackManager
*/
public function getResourceManager() : ResourcePackManager{
public function getResourcePackManager() : ResourcePackManager{
return $this->resourceManager;
}
@ -714,10 +694,6 @@ class Server{
return $this->playerList;
}
public function addRecipe(Recipe $recipe){
$this->craftingManager->registerRecipe($recipe);
}
public function shouldSavePlayerData() : bool{
return (bool) $this->getProperty("player.save-player-data", true);
}
@ -749,10 +725,13 @@ class Server{
if($this->shouldSavePlayerData()){
if(file_exists($path . "$name.dat")){
try{
$nbt = new NBT(NBT::BIG_ENDIAN);
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
$nbt = new BigEndianNBTStream();
$compound = $nbt->readCompressed(file_get_contents($path . "$name.dat"));
if(!($compound instanceof CompoundTag)){
throw new \RuntimeException("Invalid data found in \"$name.dat\", expected " . CompoundTag::class . ", got " . (is_object($compound) ? get_class($compound) : gettype($compound)));
}
return $nbt->getData();
return $compound;
}catch(\Throwable $e){ //zlib decode error / corrupt data
rename($path . "$name.dat", $path . "$name.dat.bak");
$this->logger->notice($this->getLanguage()->translateString("pocketmine.data.playerCorrupted", [$name]));
@ -772,11 +751,11 @@ class Server{
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 StringTag("Level", $this->getDefaultLevel()->getFolderName()),
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getFolderName()),
//new IntTag("SpawnX", $spawn->getFloorX()),
//new IntTag("SpawnY", $spawn->getFloorY()),
//new IntTag("SpawnZ", $spawn->getFloorZ()),
//new ByteTag("SpawnForced", 1), //TODO
new ListTag("Inventory", [], NBT::TAG_Compound),
new ListTag("EnderChestInventory", [], NBT::TAG_Compound),
@ -815,14 +794,12 @@ class Server{
$this->pluginManager->callEvent($ev);
if(!$ev->isCancelled()){
$nbt = new NBT(NBT::BIG_ENDIAN);
$nbt = new BigEndianNBTStream();
try{
$nbt->setData($ev->getSaveData());
if($async){
$this->getScheduler()->scheduleAsyncTask(new FileWriteTask($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed()));
$this->getScheduler()->scheduleAsyncTask(new FileWriteTask($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed($ev->getSaveData())));
}else{
file_put_contents($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed());
file_put_contents($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed($ev->getSaveData()));
}
}catch(\Throwable $e){
$this->logger->critical($this->getLanguage()->translateString("pocketmine.data.saveError", [$name, $e->getMessage()]));
@ -893,23 +870,25 @@ class Server{
}
/**
* @param Player $player
* Returns the player online with the specified raw UUID, or null if not found
*
* @param string $rawUUID
*
* @return null|Player
*/
public function removePlayer(Player $player){
if(isset($this->identifiers[$hash = spl_object_hash($player)])){
$identifier = $this->identifiers[$hash];
unset($this->players[$identifier]);
unset($this->identifiers[$hash]);
return;
}
public function getPlayerByRawUUID(string $rawUUID) : ?Player{
return $this->playerList[$rawUUID] ?? null;
}
foreach($this->players as $identifier => $p){
if($player === $p){
unset($this->players[$identifier]);
unset($this->identifiers[spl_object_hash($player)]);
break;
}
}
/**
* Returns the player online with a UUID equivalent to the specified UUID object, or null if not found
*
* @param UUID $uuid
*
* @return null|Player
*/
public function getPlayerByUUID(UUID $uuid) : ?Player{
return $this->getPlayerByRawUUID($uuid->toBinary());
}
/**
@ -1024,7 +1003,7 @@ class Server{
$provider = LevelProviderManager::getProvider($path);
if($provider === null){
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, "Unknown provider"]));
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, "Cannot identify format of world"]));
return false;
}
@ -1050,11 +1029,11 @@ class Server{
}
/**
* Generates a new level if it does not exists
* Generates a new level if it does not exist
*
* @param string $name
* @param int|null $seed
* @param string|null $generator Class name that extends pocketmine\level\generator\Noise
* @param string|null $generator Class name that extends pocketmine\level\generator\Generator
* @param array $options
*
* @return bool
@ -1101,8 +1080,9 @@ class Server{
$this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name]));
$centerX = $level->getSpawnLocation()->getX() >> 4;
$centerZ = $level->getSpawnLocation()->getZ() >> 4;
$spawnLocation = $level->getSpawnLocation();
$centerX = $spawnLocation->getFloorX() >> 4;
$centerZ = $spawnLocation->getFloorZ() >> 4;
$order = [];
@ -1137,10 +1117,9 @@ class Server{
}
$path = $this->getDataPath() . "worlds/" . $name . "/";
if(!($this->getLevelByName($name) instanceof Level)){
if(LevelProviderManager::getProvider($path) === null){
return false;
}
return is_dir($path) and !empty(array_filter(scandir($path, SCANDIR_SORT_NONE), function($v){
return $v !== ".." and $v !== ".";
}));
}
return true;
@ -1264,24 +1243,12 @@ class Server{
return false;
}
/**
* @deprecated
*
* @param string $variable
* @param bool $defaultValue
*
* @return bool
*/
public function getConfigBoolean(string $variable, bool $defaultValue = false) : bool{
return $this->getConfigBool($variable, $defaultValue);
}
/**
* @param string $variable
* @param bool $value
*/
public function setConfigBool(string $variable, bool $value){
$this->properties->set($variable, $value == true ? "1" : "0");
$this->properties->set($variable, $value ? "1" : "0");
}
/**
@ -1432,6 +1399,9 @@ class Server{
* @param string $pluginPath
*/
public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, string $dataPath, string $pluginPath){
if(self::$instance !== null){
throw new \InvalidStateException("Only one server instance can exist at once");
}
self::$instance = $this;
self::$sleeper = new \Threaded;
$this->autoloader = $autoloader;
@ -1522,6 +1492,8 @@ class Server{
if($processors > 0){
$poolSize = max(1, $processors);
}
}else{
$poolSize = (int) $poolSize;
}
ServerScheduler::$WORKERS = $poolSize;
@ -1548,7 +1520,7 @@ class Server{
$this->scheduler = new ServerScheduler();
if($this->getConfigBool("enable-rcon", false) === true){
if($this->getConfigBool("enable-rcon", false)){
try{
$this->rcon = new RCON(
$this,
@ -1584,15 +1556,15 @@ class Server{
$this->onlineMode = $this->getConfigBool("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"]));
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth.enabled"));
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty.enabled"));
}else{
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth", ["disabled", "will not"]));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth.disabled"));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty", ["enable", "true"]));
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty.disabled"));
}
if($this->getConfigBool("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
if($this->getConfigBool("hardcore", false) and $this->getDifficulty() < Level::DIFFICULTY_HARD){
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
}
@ -1621,6 +1593,7 @@ class Server{
Timings::init();
TimingsHandler::setEnabled((bool) $this->getProperty("settings.enable-profiling", false));
$this->consoleSender = new ConsoleCommandSender();
$this->commandMap = new SimpleCommandMap($this);
@ -1630,16 +1603,15 @@ class Server{
BlockFactory::init();
Enchantment::init();
ItemFactory::init();
Item::initCreativeItems();
Biome::init();
Effect::init();
Attribute::init();
$this->craftingManager = new CraftingManager();
$this->resourceManager = new ResourcePackManager($this, $this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR);
$this->resourceManager = new ResourcePackManager($this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR);
$this->pluginManager = new PluginManager($this, $this->commandMap);
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
$this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false));
$this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20);
$this->pluginManager->registerInterface(PharPluginLoader::class);
$this->pluginManager->registerInterface(ScriptPluginLoader::class);
@ -1656,26 +1628,18 @@ class Server{
$this->network->registerInterface(new RakLibInterface($this));
LevelProviderManager::addProvider(Anvil::class);
LevelProviderManager::addProvider(McRegion::class);
LevelProviderManager::addProvider(PMAnvil::class);
LevelProviderManager::addProvider(LevelDB::class);
LevelProviderManager::init();
if(extension_loaded("leveldb")){
$this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
}
Generator::addGenerator(Flat::class, "flat");
Generator::addGenerator(Normal::class, "normal");
Generator::addGenerator(Normal::class, "default");
Generator::addGenerator(Nether::class, "hell");
Generator::addGenerator(Nether::class, "nether");
Generator::registerDefaultGenerators();
foreach((array) $this->getProperty("worlds", []) as $name => $options){
if(!is_array($options)){
continue;
}
if($this->loadLevel($name) === false){
if(!$this->loadLevel($name)){
$seed = $options["seed"] ?? time();
if(is_string($seed) and !is_numeric($seed)){
$seed = Utils::javaStringHash($seed);
@ -1704,7 +1668,7 @@ class Server{
$default = "world";
$this->setConfigString("level-name", "world");
}
if($this->loadLevel($default) === false){
if(!$this->loadLevel($default)){
$seed = getopt("", ["level-seed::"])["level-seed"] ?? $this->properties->get("level-seed", time());
if(!is_numeric($seed) or bccomp($seed, "9223372036854775807") > 0){
$seed = Utils::javaStringHash($seed);
@ -1884,16 +1848,14 @@ class Server{
* @param bool $immediate
*/
public function batchPackets(array $players, array $packets, bool $forceSync = false, bool $immediate = false){
if(empty($packets)){
throw new \InvalidArgumentException("Cannot send empty batch");
}
Timings::$playerNetworkTimer->startTiming();
$targets = [];
foreach($players as $p){
if($p->isConnected()){
$targets[] = $this->identifiers[spl_object_hash($p)];
}
}
$targets = array_filter($players, function(Player $player) : bool{ return $player->isConnected(); });
if(count($targets) > 0){
if(!empty($targets)){
$pk = new BatchPacket();
foreach($packets as $p){
@ -1918,17 +1880,19 @@ class Server{
Timings::$playerNetworkTimer->stopTiming();
}
public function broadcastPacketsCallback(BatchPacket $pk, array $identifiers, bool $immediate = false){
/**
* @param BatchPacket $pk
* @param Player[] $players
* @param bool $immediate
*/
public function broadcastPacketsCallback(BatchPacket $pk, array $players, bool $immediate = false){
if(!$pk->isEncoded){
$pk->encode();
}
foreach($identifiers as $i){
if(isset($this->players[$i])){
$this->players[$i]->sendDataPacket($pk, false, $immediate);
}
foreach($players as $i){
$i->sendDataPacket($pk, false, $immediate);
}
}
@ -2004,7 +1968,7 @@ class Server{
$this->properties->reload();
$this->maxPlayers = $this->getConfigInt("max-players", 20);
if($this->getConfigBool("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
if($this->getConfigBool("hardcore", false) and $this->getDifficulty() < Level::DIFFICULTY_HARD){
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
}
@ -2049,7 +2013,7 @@ class Server{
$this->rcon->stop();
}
if($this->getProperty("network.upnp-forwarding", false) === true){
if($this->getProperty("network.upnp-forwarding", false)){
$this->logger->info("[UPnP] Removing port forward...");
UPnP::RemovePortForward($this->getPort());
}
@ -2089,16 +2053,18 @@ class Server{
if($this->network instanceof Network){
$this->getLogger()->debug("Stopping network interfaces");
foreach($this->network->getInterfaces() as $interface){
$this->getLogger()->debug("Stopping network interface " . get_class($interface));
$interface->shutdown();
$this->network->unregisterInterface($interface);
}
}
$this->getLogger()->debug("Collecting cycles");
gc_collect_cycles();
}catch(\Throwable $e){
$this->logger->logException($e);
$this->logger->emergency("Crashed while crashing, killing process");
@kill(getmypid());
@Utils::kill(getmypid());
}
}
@ -2113,8 +2079,8 @@ class Server{
/**
* Starts the PocketMine-MP server and starts processing ticks and packets
*/
public function start(){
if($this->getConfigBool("enable-query", true) === true){
private function start(){
if($this->getConfigBool("enable-query", true)){
$this->queryHandler = new QueryHandler();
}
@ -2130,7 +2096,11 @@ class Server{
if($this->getProperty("network.upnp-forwarding", false)){
$this->logger->info("[UPnP] Trying to port forward...");
UPnP::PortForward($this->getPort());
try{
UPnP::PortForward($this->getPort());
}catch(\Throwable $e){
$this->logger->alert("UPnP portforward failed: " . $e->getMessage());
}
}
$this->tickCounter = 0;
@ -2173,24 +2143,21 @@ class Server{
$errstr = $e->getMessage();
$errfile = $e->getFile();
$errno = $e->getCode();
$errline = $e->getLine();
$type = ($errno === E_ERROR or $errno === E_USER_ERROR) ? \LogLevel::ERROR : (($errno === E_USER_WARNING or $errno === E_WARNING) ? \LogLevel::WARNING : \LogLevel::NOTICE);
$errstr = preg_replace('/\s+/', ' ', trim($errstr));
$errfile = cleanPath($errfile);
$errfile = Utils::cleanPath($errfile);
$this->logger->logException($e, $trace);
$lastError = [
"type" => $type,
"type" => \get_class($e),
"message" => $errstr,
"fullFile" => $e->getFile(),
"file" => $errfile,
"line" => $errline,
"trace" => getTrace(0, $trace)
"trace" => Utils::getTrace(0, $trace)
];
global $lastExceptionError, $lastError;
@ -2199,7 +2166,7 @@ class Server{
}
public function crashDump(){
if($this->isRunning === false){
if(!$this->isRunning){
return;
}
if($this->sendUsageTicker > 0){
@ -2209,8 +2176,8 @@ class Server{
ini_set("error_reporting", '0');
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.create"));
try{
$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.create"));
$dump = new CrashDump($this);
$this->logger->emergency($this->getLanguage()->translateString("pocketmine.crash.submit", [$dump->getPath()]));
@ -2252,7 +2219,9 @@ class Server{
}
}catch(\Throwable $e){
$this->logger->logException($e);
$this->logger->critical($this->getLanguage()->translateString("pocketmine.crash.error", [$e->getMessage()]));
try{
$this->logger->critical($this->getLanguage()->translateString("pocketmine.crash.error", [$e->getMessage()]));
}catch(\Throwable $e){}
}
//$this->checkMemory();
@ -2260,7 +2229,7 @@ class Server{
$this->forceShutdown();
$this->isRunning = false;
@kill(getmypid());
@Utils::kill(getmypid());
exit(1);
}
@ -2291,22 +2260,23 @@ class Server{
$this->loggedInPlayers[$player->getRawUniqueId()] = $player;
}
public function onPlayerCompleteLoginSequence(Player $player){
$this->sendFullPlayerListData($player);
$player->dataPacket($this->craftingManager->getCraftingDataPacket());
}
public function onPlayerLogout(Player $player){
unset($this->loggedInPlayers[$player->getRawUniqueId()]);
}
public function addPlayer($identifier, Player $player){
$this->players[$identifier] = $player;
$this->identifiers[spl_object_hash($player)] = $identifier;
public function addPlayer(Player $player){
$this->players[spl_object_hash($player)] = $player;
}
/**
* @param Player $player
*/
public function removePlayer(Player $player){
unset($this->players[spl_object_hash($player)]);
}
public function addOnlinePlayer(Player $player){
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());
$this->playerList[$player->getRawUniqueId()] = $player;
}
@ -2324,13 +2294,15 @@ class Server{
* @param int $entityId
* @param string $name
* @param Skin $skin
* @param string $xboxUserId
* @param Player[]|null $players
*/
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, array $players = null){
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, string $xboxUserId = "", array $players = null){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin);
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, "", 0, $skin, $xboxUserId);
$this->broadcastPacket($players ?? $this->playerList, $pk);
}
@ -2352,7 +2324,7 @@ class Server{
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
foreach($this->playerList as $player){
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), "", 0, $player->getSkin(), $player->getXuid());
}
$p->dataPacket($pk);
@ -2481,16 +2453,17 @@ class Server{
}
/**
* @param string $address
* @param int $port
* @param string $payload
* @param AdvancedSourceInterface $interface
* @param string $address
* @param int $port
* @param string $payload
*
* TODO: move this to Network
*/
public function handlePacket(string $address, int $port, string $payload){
public function handlePacket(AdvancedSourceInterface $interface, string $address, int $port, string $payload){
try{
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
$this->queryHandler->handle($address, $port, $payload);
$this->queryHandler->handle($interface, $address, $port, $payload);
}
}catch(\Throwable $e){
if(\pocketmine\DEBUG > 1){

View File

@ -30,6 +30,9 @@ abstract class Thread extends \Thread{
/** @var \ClassLoader */
protected $classLoader;
/** @var string|null */
protected $composerAutoloaderPath;
protected $isKilled = false;
public function getClassLoader(){
@ -37,6 +40,8 @@ abstract class Thread extends \Thread{
}
public function setClassLoader(\ClassLoader $loader = null){
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
if($loader === null){
$loader = Server::getInstance()->getLoader();
}
@ -51,10 +56,8 @@ 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->composerAutoloaderPath !== null){
require $this->composerAutoloaderPath;
}
if($this->classLoader !== null){
$this->classLoader->register(false);

View File

@ -89,4 +89,4 @@ class ThreadManager extends \Volatile{
return $erroredThreads;
}
}
}

View File

@ -30,6 +30,8 @@ abstract class Worker extends \Worker{
/** @var \ClassLoader */
protected $classLoader;
/** @var string|null */
protected $composerAutoloaderPath;
protected $isKilled = false;
@ -38,6 +40,8 @@ abstract class Worker extends \Worker{
}
public function setClassLoader(\ClassLoader $loader = null){
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
if($loader === null){
$loader = Server::getInstance()->getLoader();
}
@ -52,10 +56,8 @@ 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->composerAutoloaderPath !== null){
require $this->composerAutoloaderPath;
}
if($this->classLoader !== null){
$this->classLoader->register(false);

View File

@ -82,4 +82,4 @@ class Air extends Transparent{
return 0;
}
}
}

View File

@ -26,7 +26,7 @@ namespace pocketmine\block;
use pocketmine\inventory\AnvilInventory;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -65,7 +65,11 @@ class Anvil extends Fallable{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function recalculateBoundingBox() : ?AxisAlignedBB{
@ -106,13 +110,9 @@ class Anvil extends Fallable{
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return [
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x0c, 1)
];
}
return [];
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get($this->getItemId(), $this->getDamage() >> 2)
];
}
}
}

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\event\TranslationContainer;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\lang\TranslationContainer;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
@ -176,7 +176,7 @@ class Bed extends Transparent{
if(!$down->isTransparent()){
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
$next = $this->getSide(self::getOtherHalfSide($meta));
if($next->canBeReplaced() === true and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
$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);
@ -190,25 +190,16 @@ class Bed extends Transparent{
return false;
}
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, null, $player !== null); //make sure tiles get removed
}
return true;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
if($this->isHeadPart()){
$tile = $this->getLevel()->getTile($this);
if($tile instanceof TileBed){
return [
ItemFactory::get($this->getItemId(), $tile->getColor(), 1)
ItemFactory::get($this->getItemId(), $tile->getColor())
];
}else{
return [
ItemFactory::get($this->getItemId(), 14, 1) //Red
ItemFactory::get($this->getItemId(), 14) //Red
];
}
}
@ -216,4 +207,15 @@ class Bed extends Transparent{
return [];
}
public function isAffectedBySilkTouch() : bool{
return false;
}
public function getAffectedBlocks() : array{
if(($other = $this->getOtherHalf()) !== null){
return [$this, $other];
}
return parent::getAffectedBlocks();
}
}

View File

@ -49,4 +49,4 @@ class Bedrock extends Solid{
return false;
}
}
}

View File

@ -38,20 +38,20 @@ class Beetroot extends Crops{
return "Beetroot Block";
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
if($this->meta >= 0x07){
return [
ItemFactory::get(Item::BEETROOT, 0, 1),
ItemFactory::get(Item::BEETROOT),
ItemFactory::get(Item::BEETROOT_SEEDS, 0, mt_rand(0, 3))
];
}
return [
ItemFactory::get(Item::BEETROOT_SEEDS, 0, 1)
ItemFactory::get(Item::BEETROOT_SEEDS)
];
}
public function getPickedItem() : Item{
return ItemFactory::get(Item::BEETROOT_SEEDS);
}
}
}

View File

@ -27,13 +27,12 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\level\MovingObjectPosition;
use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
@ -195,8 +194,49 @@ class Block extends Position implements BlockIds, Metadatable{
return true;
}
public function canBeBrokenWith(Item $item) : bool{
return $this->getHardness() !== -1;
/**
* @return int
*/
public function getToolType() : int{
return BlockToolType::TYPE_NONE;
}
/**
* Returns the level of tool required to harvest this block (for normal blocks). When the tool type matches the
* block's required tool type, the tool must have a harvest level greater than or equal to this value to be able to
* successfully harvest the block.
*
* If the block requires a specific minimum tier of tiered tool, the minimum tier required should be returned.
* Otherwise, 1 should be returned if a tool is required, 0 if not.
*
* @see Item::getBlockToolHarvestLevel()
*
* @return int
*/
public function getToolHarvestLevel() : int{
return 0;
}
/**
* Returns whether the specified item is the proper tool to use for breaking this block. This checks tool type and
* harvest level requirement.
*
* In most cases this is also used to determine whether block drops should be created or not, except in some
* special cases such as vines.
*
* @param Item $tool
*
* @return bool
*/
public function isCompatibleWithTool(Item $tool) : bool{
if($this->getHardness() < 0){
return false;
}
$toolType = $this->getToolType();
$harvestLevel = $this->getToolHarvestLevel();
return $toolType === BlockToolType::TYPE_NONE or $harvestLevel === 0 or (
($toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $harvestLevel);
}
/**
@ -220,44 +260,29 @@ class Block extends Position implements BlockIds, Metadatable{
* @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;
}
}
$base = $this->getHardness();
if($this->isCompatibleWithTool($item)){
$base *= 1.5;
}else{
$base *= 3.33;
$base *= 5;
}
if($item->isSword()){
$base /= 1.5;
$efficiency = $item->getMiningEfficiency($this);
if($efficiency <= 0){
throw new \RuntimeException("Item efficiency is invalid");
}
$base /= $efficiency;
return $base;
}
/**
* Called when this block or a block immediately adjacent to it changes state.
*/
public function onNearbyBlockChange() : void{
}
/**
* Returns whether random block updates will be done on this block.
@ -269,14 +294,18 @@ class Block extends Position implements BlockIds, Metadatable{
}
/**
* Fires a block update on the Block
*
* @param int $type
*
* @return bool|int
* Called when this block is randomly updated due to chunk ticking.
* WARNING: This will not be called if ticksRandomly() does not return true!
*/
public function onUpdate(int $type){
return false;
public function onRandomTick() : void{
}
/**
* Called when this block is updated by the delayed blockupdate scheduler in the level.
*/
public function onScheduledUpdate() : void{
}
/**
@ -299,14 +328,6 @@ class Block extends Position implements BlockIds, Metadatable{
return 10;
}
/**
* @deprecated
* @return float
*/
public function getResistance() : float{
return $this->getBlastResistance();
}
/**
* Returns the block's resistance to explosions. Usually 5x hardness.
* @return float
@ -315,13 +336,6 @@ class Block extends Position implements BlockIds, Metadatable{
return $this->getHardness() * 5;
}
/**
* @return int
*/
public function getToolType() : int{
return Tool::TYPE_NONE;
}
/**
* @return float
*/
@ -420,11 +434,53 @@ class Block extends Position implements BlockIds, Metadatable{
* @return Item[]
*/
public function getDrops(Item $item) : array{
if($this->isCompatibleWithTool($item)){
if($this->isAffectedBySilkTouch() and $item->hasEnchantment(Enchantment::SILK_TOUCH)){
return $this->getSilkTouchDrops($item);
}
return $this->getDropsForCompatibleTool($item);
}
return [];
}
/**
* Returns an array of Items to be dropped when the block is broken using the correct tool type.
*
* @param Item $item
*
* @return Item[]
*/
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get($this->getItemId(), $this->getVariant(), 1)
ItemFactory::get($this->getItemId(), $this->getVariant())
];
}
/**
* Returns an array of Items to be dropped when the block is broken using a compatible Silk Touch-enchanted tool.
*
* @param Item $item
*
* @return Item[]
*/
public function getSilkTouchDrops(Item $item) : array{
return [
ItemFactory::get($this->getItemId(), $this->getVariant())
];
}
/**
* Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop
* themselves anyway, this is implicitly true.
*
* @return bool
*/
public function isAffectedBySilkTouch() : bool{
return true;
}
/**
* Returns the item that players will equip when middle-clicking on this block.
* @return Item
@ -441,6 +497,50 @@ class Block extends Position implements BlockIds, Metadatable{
return 0;
}
/**
* Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
* fire.
*
* @return int
*/
public function getFlameEncouragement() : int{
return 0;
}
/**
* Returns the base flammability of this block. Higher values lead to the block burning away more quickly.
*
* @return int
*/
public function getFlammability() : int{
return 0;
}
/**
* Returns whether fire lit on this block will burn indefinitely.
*
* @return bool
*/
public function burnsForever() : bool{
return false;
}
/**
* Returns whether this block can catch fire.
*
* @return bool
*/
public function isFlammable() : bool{
return $this->getFlammability() > 0;
}
/**
* Called when this block is burned away by being on fire.
*/
public function onIncinerate() : void{
}
/**
* Returns the Block on the side $side, works like Vector3::getSide()
*
@ -449,7 +549,7 @@ class Block extends Position implements BlockIds, Metadatable{
*
* @return Block
*/
public function getSide($side, $step = 1){
public function getSide(int $side, int $step = 1){
if($this->isValid()){
return $this->getLevel()->getBlock(Vector3::getSide($side, $step));
}
@ -486,6 +586,16 @@ class Block extends Position implements BlockIds, Metadatable{
);
}
/**
* Returns a list of blocks that this block is part of. In most cases, only contains the block itself, but in cases
* such as double plants, beds and doors, will contain both halves.
*
* @return Block[]
*/
public function getAffectedBlocks() : array{
return [$this];
}
/**
* @return string
*/
@ -501,9 +611,7 @@ class Block extends Position implements BlockIds, Metadatable{
* @return bool
*/
public function collidesWithBB(AxisAlignedBB $bb) : bool{
$bbs = $this->getCollisionBoxes();
foreach($bbs as $bb2){
foreach($this->getCollisionBoxes() as $bb2){
if($bb->intersectsWith($bb2)){
return true;
}
@ -578,15 +686,15 @@ class Block extends Position implements BlockIds, Metadatable{
* @param Vector3 $pos1
* @param Vector3 $pos2
*
* @return MovingObjectPosition|null
* @return RayTraceResult|null
*/
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
$bbs = $this->getCollisionBoxes();
if(empty($bbs)){
return null;
}
/** @var MovingObjectPosition|null $currentHit */
/** @var RayTraceResult|null $currentHit */
$currentHit = null;
/** @var int|float $currentDistance */
$currentDistance = PHP_INT_MAX;
@ -604,40 +712,34 @@ class Block extends Position implements BlockIds, Metadatable{
}
}
if($currentHit !== null){
$currentHit->blockX = $this->x;
$currentHit->blockY = $this->y;
$currentHit->blockZ = $this->z;
}
return $currentHit;
}
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
if($this->getLevel() instanceof Level){
$this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
if($this->isValid()){
$this->level->getBlockMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
}
}
public function getMetadata(string $metadataKey){
if($this->getLevel() instanceof Level){
return $this->getLevel()->getBlockMetadata()->getMetadata($this, $metadataKey);
if($this->isValid()){
return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey);
}
return null;
}
public function hasMetadata(string $metadataKey) : bool{
if($this->getLevel() instanceof Level){
return $this->getLevel()->getBlockMetadata()->hasMetadata($this, $metadataKey);
if($this->isValid()){
return $this->level->getBlockMetadata()->hasMetadata($this, $metadataKey);
}
return false;
}
public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
if($this->getLevel() instanceof Level){
$this->getLevel()->getBlockMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
if($this->isValid()){
$this->level->getBlockMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
}
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Position;
use pocketmine\utils\MainLogger;
/**
* Manages block registration and instance creation
@ -50,282 +51,293 @@ class BlockFactory{
/** @var \SplFixedArray<float> */
public static $blastResistance = null;
/** @var int[] */
public static $staticRuntimeIdMap = [];
/** @var int[] */
public static $legacyIdMap = [];
/** @var int */
private static $lastRuntimeId = 0;
/**
* Initializes the block factory. By default this is called only once on server start, however you may wish to use
* this if you need to reset the block factory back to its original defaults for whatever reason.
*
* @param bool $force
*/
public static function init(bool $force = false) : void{
if(self::$list === null or $force){
self::$list = new \SplFixedArray(256);
self::$fullList = new \SplFixedArray(4096);
public static function init() : void{
self::$list = new \SplFixedArray(256);
self::$fullList = new \SplFixedArray(4096);
self::$light = new \SplFixedArray(256);
self::$lightFilter = new \SplFixedArray(256);
self::$solid = new \SplFixedArray(256);
self::$hardness = new \SplFixedArray(256);
self::$transparent = new \SplFixedArray(256);
self::$diffusesSkyLight = new \SplFixedArray(256);
self::$blastResistance = new \SplFixedArray(256);
self::$light = new \SplFixedArray(256);
self::$lightFilter = new \SplFixedArray(256);
self::$solid = new \SplFixedArray(256);
self::$hardness = new \SplFixedArray(256);
self::$transparent = new \SplFixedArray(256);
self::$diffusesSkyLight = new \SplFixedArray(256);
self::$blastResistance = new \SplFixedArray(256);
self::registerBlock(new Air());
self::registerBlock(new Stone());
self::registerBlock(new Grass());
self::registerBlock(new Dirt());
self::registerBlock(new Cobblestone());
self::registerBlock(new Planks());
self::registerBlock(new Sapling());
self::registerBlock(new Bedrock());
self::registerBlock(new Water());
self::registerBlock(new StillWater());
self::registerBlock(new Lava());
self::registerBlock(new StillLava());
self::registerBlock(new Sand());
self::registerBlock(new Gravel());
self::registerBlock(new GoldOre());
self::registerBlock(new IronOre());
self::registerBlock(new CoalOre());
self::registerBlock(new Wood());
self::registerBlock(new Leaves());
self::registerBlock(new Sponge());
self::registerBlock(new Glass());
self::registerBlock(new LapisOre());
self::registerBlock(new Lapis());
//TODO: DISPENSER
self::registerBlock(new Sandstone());
self::registerBlock(new NoteBlock());
self::registerBlock(new Bed());
self::registerBlock(new PoweredRail());
self::registerBlock(new DetectorRail());
//TODO: STICKY_PISTON
self::registerBlock(new Cobweb());
self::registerBlock(new TallGrass());
self::registerBlock(new DeadBush());
//TODO: PISTON
//TODO: PISTONARMCOLLISION
self::registerBlock(new Wool());
self::registerBlock(new Air());
self::registerBlock(new Stone());
self::registerBlock(new Grass());
self::registerBlock(new Dirt());
self::registerBlock(new Cobblestone());
self::registerBlock(new Planks());
self::registerBlock(new Sapling());
self::registerBlock(new Bedrock());
self::registerBlock(new Water());
self::registerBlock(new StillWater());
self::registerBlock(new Lava());
self::registerBlock(new StillLava());
self::registerBlock(new Sand());
self::registerBlock(new Gravel());
self::registerBlock(new GoldOre());
self::registerBlock(new IronOre());
self::registerBlock(new CoalOre());
self::registerBlock(new Wood());
self::registerBlock(new Leaves());
self::registerBlock(new Sponge());
self::registerBlock(new Glass());
self::registerBlock(new LapisOre());
self::registerBlock(new Lapis());
//TODO: DISPENSER
self::registerBlock(new Sandstone());
self::registerBlock(new NoteBlock());
self::registerBlock(new Bed());
self::registerBlock(new PoweredRail());
self::registerBlock(new DetectorRail());
//TODO: STICKY_PISTON
self::registerBlock(new Cobweb());
self::registerBlock(new TallGrass());
self::registerBlock(new DeadBush());
//TODO: PISTON
//TODO: PISTONARMCOLLISION
self::registerBlock(new Wool());
self::registerBlock(new Dandelion());
self::registerBlock(new Flower());
self::registerBlock(new BrownMushroom());
self::registerBlock(new RedMushroom());
self::registerBlock(new Gold());
self::registerBlock(new Iron());
self::registerBlock(new DoubleStoneSlab());
self::registerBlock(new StoneSlab());
self::registerBlock(new Bricks());
self::registerBlock(new TNT());
self::registerBlock(new Bookshelf());
self::registerBlock(new MossyCobblestone());
self::registerBlock(new Obsidian());
self::registerBlock(new Torch());
self::registerBlock(new Fire());
self::registerBlock(new MonsterSpawner());
self::registerBlock(new WoodenStairs(Block::OAK_STAIRS, 0, "Oak Stairs"));
self::registerBlock(new Chest());
//TODO: REDSTONE_WIRE
self::registerBlock(new DiamondOre());
self::registerBlock(new Diamond());
self::registerBlock(new CraftingTable());
self::registerBlock(new Wheat());
self::registerBlock(new Farmland());
self::registerBlock(new Furnace());
self::registerBlock(new BurningFurnace());
self::registerBlock(new SignPost());
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());
self::registerBlock(new WallSign());
self::registerBlock(new Lever());
self::registerBlock(new StonePressurePlate());
self::registerBlock(new IronDoor());
self::registerBlock(new WoodenPressurePlate());
self::registerBlock(new RedstoneOre());
self::registerBlock(new GlowingRedstoneOre());
self::registerBlock(new RedstoneTorchUnlit());
self::registerBlock(new RedstoneTorch());
self::registerBlock(new StoneButton());
self::registerBlock(new SnowLayer());
self::registerBlock(new Ice());
self::registerBlock(new Snow());
self::registerBlock(new Cactus());
self::registerBlock(new Clay());
self::registerBlock(new Sugarcane());
//TODO: JUKEBOX
self::registerBlock(new WoodenFence());
self::registerBlock(new Pumpkin());
self::registerBlock(new Netherrack());
self::registerBlock(new SoulSand());
self::registerBlock(new Glowstone());
//TODO: PORTAL
self::registerBlock(new LitPumpkin());
self::registerBlock(new Cake());
//TODO: REPEATER_BLOCK
//TODO: POWERED_REPEATER
//TODO: INVISIBLEBEDROCK
self::registerBlock(new Trapdoor());
//TODO: MONSTER_EGG
self::registerBlock(new StoneBricks());
self::registerBlock(new BrownMushroomBlock());
self::registerBlock(new RedMushroomBlock());
self::registerBlock(new IronBars());
self::registerBlock(new GlassPane());
self::registerBlock(new Melon());
self::registerBlock(new PumpkinStem());
self::registerBlock(new MelonStem());
self::registerBlock(new Vine());
self::registerBlock(new FenceGate(Block::OAK_FENCE_GATE, 0, "Oak Fence Gate"));
self::registerBlock(new BrickStairs());
self::registerBlock(new StoneBrickStairs());
self::registerBlock(new Mycelium());
self::registerBlock(new WaterLily());
self::registerBlock(new NetherBrick(Block::NETHER_BRICK_BLOCK, 0, "Nether Bricks"));
self::registerBlock(new NetherBrickFence());
self::registerBlock(new NetherBrickStairs());
self::registerBlock(new NetherWartPlant());
self::registerBlock(new EnchantingTable());
self::registerBlock(new BrewingStand());
//TODO: CAULDRON_BLOCK
//TODO: END_PORTAL
self::registerBlock(new EndPortalFrame());
self::registerBlock(new EndStone());
//TODO: DRAGON_EGG
self::registerBlock(new RedstoneLamp());
self::registerBlock(new LitRedstoneLamp());
//TODO: DROPPER
self::registerBlock(new ActivatorRail());
self::registerBlock(new CocoaBlock());
self::registerBlock(new SandstoneStairs());
self::registerBlock(new EmeraldOre());
self::registerBlock(new EnderChest());
self::registerBlock(new TripwireHook());
self::registerBlock(new Tripwire());
self::registerBlock(new Emerald());
self::registerBlock(new WoodenStairs(Block::SPRUCE_STAIRS, 0, "Spruce Stairs"));
self::registerBlock(new WoodenStairs(Block::BIRCH_STAIRS, 0, "Birch Stairs"));
self::registerBlock(new WoodenStairs(Block::JUNGLE_STAIRS, 0, "Jungle Stairs"));
//TODO: COMMAND_BLOCK
//TODO: BEACON
self::registerBlock(new CobblestoneWall());
self::registerBlock(new FlowerPot());
self::registerBlock(new Carrot());
self::registerBlock(new Potato());
self::registerBlock(new WoodenButton());
self::registerBlock(new Skull());
self::registerBlock(new Anvil());
self::registerBlock(new TrappedChest());
self::registerBlock(new WeightedPressurePlateLight());
self::registerBlock(new WeightedPressurePlateHeavy());
//TODO: COMPARATOR_BLOCK
//TODO: POWERED_COMPARATOR
self::registerBlock(new DaylightSensor());
self::registerBlock(new Redstone());
self::registerBlock(new NetherQuartzOre());
//TODO: HOPPER_BLOCK
self::registerBlock(new Quartz());
self::registerBlock(new QuartzStairs());
self::registerBlock(new DoubleWoodenSlab());
self::registerBlock(new WoodenSlab());
self::registerBlock(new StainedClay());
self::registerBlock(new StainedGlassPane());
self::registerBlock(new Leaves2());
self::registerBlock(new Wood2());
self::registerBlock(new WoodenStairs(Block::ACACIA_STAIRS, 0, "Acacia Stairs"));
self::registerBlock(new WoodenStairs(Block::DARK_OAK_STAIRS, 0, "Dark Oak Stairs"));
//TODO: SLIME
self::registerBlock(new Dandelion());
self::registerBlock(new Flower());
self::registerBlock(new BrownMushroom());
self::registerBlock(new RedMushroom());
self::registerBlock(new Gold());
self::registerBlock(new Iron());
self::registerBlock(new DoubleStoneSlab());
self::registerBlock(new StoneSlab());
self::registerBlock(new Bricks());
self::registerBlock(new TNT());
self::registerBlock(new Bookshelf());
self::registerBlock(new MossyCobblestone());
self::registerBlock(new Obsidian());
self::registerBlock(new Torch());
self::registerBlock(new Fire());
self::registerBlock(new MonsterSpawner());
self::registerBlock(new WoodenStairs(Block::OAK_STAIRS, 0, "Oak Stairs"));
self::registerBlock(new Chest());
//TODO: REDSTONE_WIRE
self::registerBlock(new DiamondOre());
self::registerBlock(new Diamond());
self::registerBlock(new CraftingTable());
self::registerBlock(new Wheat());
self::registerBlock(new Farmland());
self::registerBlock(new Furnace());
self::registerBlock(new BurningFurnace());
self::registerBlock(new SignPost());
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());
self::registerBlock(new WallSign());
self::registerBlock(new Lever());
self::registerBlock(new StonePressurePlate());
self::registerBlock(new IronDoor());
self::registerBlock(new WoodenPressurePlate());
self::registerBlock(new RedstoneOre());
self::registerBlock(new GlowingRedstoneOre());
self::registerBlock(new RedstoneTorchUnlit());
self::registerBlock(new RedstoneTorch());
self::registerBlock(new StoneButton());
self::registerBlock(new SnowLayer());
self::registerBlock(new Ice());
self::registerBlock(new Snow());
self::registerBlock(new Cactus());
self::registerBlock(new Clay());
self::registerBlock(new Sugarcane());
//TODO: JUKEBOX
self::registerBlock(new WoodenFence());
self::registerBlock(new Pumpkin());
self::registerBlock(new Netherrack());
self::registerBlock(new SoulSand());
self::registerBlock(new Glowstone());
//TODO: PORTAL
self::registerBlock(new LitPumpkin());
self::registerBlock(new Cake());
//TODO: REPEATER_BLOCK
//TODO: POWERED_REPEATER
//TODO: INVISIBLEBEDROCK
self::registerBlock(new Trapdoor());
//TODO: MONSTER_EGG
self::registerBlock(new StoneBricks());
self::registerBlock(new BrownMushroomBlock());
self::registerBlock(new RedMushroomBlock());
self::registerBlock(new IronBars());
self::registerBlock(new GlassPane());
self::registerBlock(new Melon());
self::registerBlock(new PumpkinStem());
self::registerBlock(new MelonStem());
self::registerBlock(new Vine());
self::registerBlock(new FenceGate(Block::OAK_FENCE_GATE, 0, "Oak Fence Gate"));
self::registerBlock(new BrickStairs());
self::registerBlock(new StoneBrickStairs());
self::registerBlock(new Mycelium());
self::registerBlock(new WaterLily());
self::registerBlock(new NetherBrick(Block::NETHER_BRICK_BLOCK, 0, "Nether Bricks"));
self::registerBlock(new NetherBrickFence());
self::registerBlock(new NetherBrickStairs());
self::registerBlock(new NetherWartPlant());
self::registerBlock(new EnchantingTable());
self::registerBlock(new BrewingStand());
//TODO: CAULDRON_BLOCK
//TODO: END_PORTAL
self::registerBlock(new EndPortalFrame());
self::registerBlock(new EndStone());
//TODO: DRAGON_EGG
self::registerBlock(new RedstoneLamp());
self::registerBlock(new LitRedstoneLamp());
//TODO: DROPPER
self::registerBlock(new ActivatorRail());
self::registerBlock(new CocoaBlock());
self::registerBlock(new SandstoneStairs());
self::registerBlock(new EmeraldOre());
self::registerBlock(new EnderChest());
self::registerBlock(new TripwireHook());
self::registerBlock(new Tripwire());
self::registerBlock(new Emerald());
self::registerBlock(new WoodenStairs(Block::SPRUCE_STAIRS, 0, "Spruce Stairs"));
self::registerBlock(new WoodenStairs(Block::BIRCH_STAIRS, 0, "Birch Stairs"));
self::registerBlock(new WoodenStairs(Block::JUNGLE_STAIRS, 0, "Jungle Stairs"));
//TODO: COMMAND_BLOCK
//TODO: BEACON
self::registerBlock(new CobblestoneWall());
self::registerBlock(new FlowerPot());
self::registerBlock(new Carrot());
self::registerBlock(new Potato());
self::registerBlock(new WoodenButton());
self::registerBlock(new Skull());
self::registerBlock(new Anvil());
self::registerBlock(new TrappedChest());
self::registerBlock(new WeightedPressurePlateLight());
self::registerBlock(new WeightedPressurePlateHeavy());
//TODO: COMPARATOR_BLOCK
//TODO: POWERED_COMPARATOR
self::registerBlock(new DaylightSensor());
self::registerBlock(new Redstone());
self::registerBlock(new NetherQuartzOre());
//TODO: HOPPER_BLOCK
self::registerBlock(new Quartz());
self::registerBlock(new QuartzStairs());
self::registerBlock(new DoubleWoodenSlab());
self::registerBlock(new WoodenSlab());
self::registerBlock(new StainedClay());
self::registerBlock(new StainedGlassPane());
self::registerBlock(new Leaves2());
self::registerBlock(new Wood2());
self::registerBlock(new WoodenStairs(Block::ACACIA_STAIRS, 0, "Acacia Stairs"));
self::registerBlock(new WoodenStairs(Block::DARK_OAK_STAIRS, 0, "Dark Oak Stairs"));
//TODO: SLIME
self::registerBlock(new IronTrapdoor());
self::registerBlock(new Prismarine());
self::registerBlock(new SeaLantern());
self::registerBlock(new HayBale());
self::registerBlock(new Carpet());
self::registerBlock(new HardenedClay());
self::registerBlock(new Coal());
self::registerBlock(new PackedIce());
self::registerBlock(new DoublePlant());
self::registerBlock(new StandingBanner());
self::registerBlock(new WallBanner());
//TODO: DAYLIGHT_DETECTOR_INVERTED
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"));
self::registerBlock(new FenceGate(Block::DARK_OAK_FENCE_GATE, 0, "Dark Oak Fence Gate"));
self::registerBlock(new FenceGate(Block::ACACIA_FENCE_GATE, 0, "Acacia Fence Gate"));
//TODO: REPEATING_COMMAND_BLOCK
//TODO: CHAIN_COMMAND_BLOCK
self::registerBlock(new IronTrapdoor());
self::registerBlock(new Prismarine());
self::registerBlock(new SeaLantern());
self::registerBlock(new HayBale());
self::registerBlock(new Carpet());
self::registerBlock(new HardenedClay());
self::registerBlock(new Coal());
self::registerBlock(new PackedIce());
self::registerBlock(new DoublePlant());
self::registerBlock(new StandingBanner());
self::registerBlock(new WallBanner());
//TODO: DAYLIGHT_DETECTOR_INVERTED
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"));
self::registerBlock(new FenceGate(Block::DARK_OAK_FENCE_GATE, 0, "Dark Oak Fence Gate"));
self::registerBlock(new FenceGate(Block::ACACIA_FENCE_GATE, 0, "Acacia Fence Gate"));
//TODO: REPEATING_COMMAND_BLOCK
//TODO: CHAIN_COMMAND_BLOCK
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
self::registerBlock(new Purpur());
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
self::registerBlock(new Purpur());
self::registerBlock(new PurpurStairs());
self::registerBlock(new PurpurStairs());
//TODO: UNDYED_SHULKER_BOX
self::registerBlock(new EndStoneBricks());
//TODO: FROSTED_ICE
self::registerBlock(new EndRod());
//TODO: END_GATEWAY
//TODO: UNDYED_SHULKER_BOX
self::registerBlock(new EndStoneBricks());
//TODO: FROSTED_ICE
self::registerBlock(new EndRod());
//TODO: END_GATEWAY
self::registerBlock(new Magma());
self::registerBlock(new NetherWartBlock());
self::registerBlock(new NetherBrick(Block::RED_NETHER_BRICK, 0, "Red Nether Bricks"));
self::registerBlock(new BoneBlock());
self::registerBlock(new Magma());
self::registerBlock(new NetherWartBlock());
self::registerBlock(new NetherBrick(Block::RED_NETHER_BRICK, 0, "Red Nether Bricks"));
self::registerBlock(new BoneBlock());
//TODO: SHULKER_BOX
self::registerBlock(new GlazedTerracotta(Block::PURPLE_GLAZED_TERRACOTTA, 0, "Purple Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::WHITE_GLAZED_TERRACOTTA, 0, "White Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::ORANGE_GLAZED_TERRACOTTA, 0, "Orange Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::MAGENTA_GLAZED_TERRACOTTA, 0, "Magenta Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::LIGHT_BLUE_GLAZED_TERRACOTTA, 0, "Light Blue Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::YELLOW_GLAZED_TERRACOTTA, 0, "Yellow Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::LIME_GLAZED_TERRACOTTA, 0, "Lime Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::PINK_GLAZED_TERRACOTTA, 0, "Pink Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::GRAY_GLAZED_TERRACOTTA, 0, "Grey Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::SILVER_GLAZED_TERRACOTTA, 0, "Light Grey Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::CYAN_GLAZED_TERRACOTTA, 0, "Cyan Glazed Terracotta"));
//TODO: SHULKER_BOX
self::registerBlock(new GlazedTerracotta(Block::PURPLE_GLAZED_TERRACOTTA, 0, "Purple Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::WHITE_GLAZED_TERRACOTTA, 0, "White Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::ORANGE_GLAZED_TERRACOTTA, 0, "Orange Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::MAGENTA_GLAZED_TERRACOTTA, 0, "Magenta Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::LIGHT_BLUE_GLAZED_TERRACOTTA, 0, "Light Blue Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::YELLOW_GLAZED_TERRACOTTA, 0, "Yellow Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::LIME_GLAZED_TERRACOTTA, 0, "Lime Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::PINK_GLAZED_TERRACOTTA, 0, "Pink Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::GRAY_GLAZED_TERRACOTTA, 0, "Grey Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::SILVER_GLAZED_TERRACOTTA, 0, "Light Grey Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::CYAN_GLAZED_TERRACOTTA, 0, "Cyan Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::BLUE_GLAZED_TERRACOTTA, 0, "Blue Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::BROWN_GLAZED_TERRACOTTA, 0, "Brown Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::GREEN_GLAZED_TERRACOTTA, 0, "Green Glazed Terracotta"));
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());
self::registerBlock(new ConcretePowder());
self::registerBlock(new GlazedTerracotta(Block::BLUE_GLAZED_TERRACOTTA, 0, "Blue Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::BROWN_GLAZED_TERRACOTTA, 0, "Brown Glazed Terracotta"));
self::registerBlock(new GlazedTerracotta(Block::GREEN_GLAZED_TERRACOTTA, 0, "Green Glazed Terracotta"));
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());
self::registerBlock(new ConcretePowder());
//TODO: CHORUS_PLANT
self::registerBlock(new StainedGlass());
//TODO: CHORUS_PLANT
self::registerBlock(new StainedGlass());
self::registerBlock(new Podzol());
self::registerBlock(new Beetroot());
self::registerBlock(new Stonecutter());
self::registerBlock(new GlowingObsidian());
self::registerBlock(new NetherReactor());
//TODO: INFO_UPDATE
//TODO: INFO_UPDATE2
//TODO: MOVINGBLOCK
//TODO: OBSERVER
//TODO: STRUCTURE_BLOCK
self::registerBlock(new Podzol());
self::registerBlock(new Beetroot());
self::registerBlock(new Stonecutter());
self::registerBlock(new GlowingObsidian());
self::registerBlock(new NetherReactor());
//TODO: INFO_UPDATE
//TODO: INFO_UPDATE2
//TODO: MOVINGBLOCK
//TODO: OBSERVER
//TODO: STRUCTURE_BLOCK
//TODO: RESERVED6
//TODO: RESERVED6
foreach(self::$list as $id => $block){
if($block === null){
self::registerBlock(new UnknownBlock($id));
}
foreach(self::$list as $id => $block){
if($block === null){
self::registerBlock(new UnknownBlock($id));
}
}
/** @var mixed[] $runtimeIdMap */
$runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true);
foreach($runtimeIdMap as $obj){
self::registerMapping($obj["runtimeID"], $obj["id"], $obj["data"]);
}
}
/**
@ -390,9 +402,9 @@ class BlockFactory{
}
if($pos !== null){
$block->x = $pos->x;
$block->y = $pos->y;
$block->z = $pos->z;
$block->x = $pos->getFloorX();
$block->y = $pos->getFloorY();
$block->z = $pos->getFloorZ();
$block->level = $pos->level;
}
@ -417,4 +429,46 @@ class BlockFactory{
$b = self::$list[$id];
return $b !== null and !($b instanceof UnknownBlock);
}
}
/**
* @internal
*
* @param int $id
* @param int $meta
*
* @return int
*/
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
if($id === Block::AIR){
//TODO: HACK! (weird air blocks with non-zero damage values shouldn't turn into update! blocks)
$meta = 0;
}
$index = ($id << 4) | $meta;
if(!isset(self::$staticRuntimeIdMap[$index])){
self::registerMapping($rtId = ++self::$lastRuntimeId, $id, $meta);
MainLogger::getLogger()->error("ID $id meta $meta does not have a corresponding block static runtime ID, added a new unknown runtime ID ($rtId)");
return $rtId;
}
return self::$staticRuntimeIdMap[$index];
}
/**
* @internal
*
* @param int $runtimeId
*
* @return int[] [id, meta]
*/
public static function fromStaticRuntimeId(int $runtimeId) : array{
$v = self::$legacyIdMap[$runtimeId];
return [$v >> 4, $v & 0xf];
}
private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{
self::$staticRuntimeIdMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId;
self::$legacyIdMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
self::$lastRuntimeId = max(self::$lastRuntimeId, $staticRuntimeId);
}
}

View File

@ -21,21 +21,19 @@
declare(strict_types=1);
namespace pocketmine\block;
/**
* Math related classes, like matrices, bounding boxes and vector
* Types of tools that can be used to break blocks
* Blocks may allow multiple tool types by combining these bitflags
*/
namespace pocketmine\math;
interface BlockToolType{
public const TYPE_NONE = 0;
public const TYPE_SWORD = 1 << 0;
public const TYPE_SHOVEL = 1 << 1;
public const TYPE_PICKAXE = 1 << 2;
public const TYPE_AXE = 1 << 3;
public const TYPE_SHEARS = 1 << 4;
abstract class Math{
public static function floorFloat($n) : int{
$i = (int) $n;
return $n >= $i ? $i : $i - 1;
}
public static function ceilFloat($n) : int{
$i = (int) ($n + 1);
return $n >= $i ? $i : $i - 1;
}
}
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\PillarRotationHelper;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -46,7 +46,11 @@ class BoneBlock extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
@ -57,13 +61,4 @@ class BoneBlock extends Solid{
public function getVariantBitmask() : int{
return 0x03;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class Bookshelf extends Solid{
@ -44,10 +43,10 @@ class Bookshelf extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_AXE;
return BlockToolType::TYPE_AXE;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::BOOK, 0, 3)
];
@ -57,4 +56,11 @@ class Bookshelf extends Solid{
return 300;
}
}
public function getFlameEncouragement() : int{
return 30;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class BrewingStand extends Transparent{
@ -42,7 +42,11 @@ class BrewingStand extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getVariantBitmask() : int{
@ -50,4 +54,4 @@ class BrewingStand extends Transparent{
}
//TODO
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class BrickStairs extends Stair{
@ -42,11 +42,15 @@ class BrickStairs extends Stair{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getName() : string{
return "Brick Stairs";
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Bricks extends Solid{
@ -43,18 +42,14 @@ class Bricks extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getName() : string{
return "Bricks";
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -34,4 +34,4 @@ class BrownMushroom extends RedMushroom{
public function getLightLevel() : int{
return 1;
}
}
}

View File

@ -33,9 +33,9 @@ class BrownMushroomBlock extends RedMushroomBlock{
return "Brown Mushroom Block";
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
];
}
}
}

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\StringTag;
use pocketmine\Player;
@ -35,6 +35,8 @@ class BurningFurnace extends Solid{
protected $id = self::BURNING_FURNACE;
protected $itemId = self::FURNACE;
public function __construct(int $meta = 0){
$this->meta = $meta;
}
@ -48,7 +50,11 @@ class BurningFurnace extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getLightLevel() : int{
@ -90,12 +96,4 @@ class BurningFurnace extends Solid{
public function getVariantBitmask() : int{
return 0;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -48,4 +48,4 @@ abstract class Button extends Flowable{
//TODO
return true;
}
}
}

View File

@ -28,7 +28,6 @@ use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -66,50 +65,49 @@ class Cactus extends Transparent{
);
}
public function ticksRandomly() : bool{
return true;
}
public function onEntityCollide(Entity $entity) : void{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
$entity->attack($ev);
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(Vector3::SIDE_DOWN);
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
$this->getLevel()->useBreakOn($this);
}else{
for($side = 2; $side <= 5; ++$side){
$b = $this->getSide($side);
if(!$b->canBeFlowedInto()){
$this->getLevel()->useBreakOn($this);
}
}
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
if($this->meta === 0x0f){
for($y = 1; $y < 3; ++$y){
$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()){
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
}
}
}
$this->meta = 0;
$this->getLevel()->setBlock($this, $this);
}else{
++$this->meta;
$this->getLevel()->setBlock($this, $this);
public function onNearbyBlockChange() : void{
$down = $this->getSide(Vector3::SIDE_DOWN);
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
$this->getLevel()->useBreakOn($this);
}else{
for($side = 2; $side <= 5; ++$side){
$b = $this->getSide($side);
if(!$b->canBeFlowedInto()){
$this->getLevel()->useBreakOn($this);
break;
}
}
}
}
return false;
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
if($this->meta === 0x0f){
for($y = 1; $y < 3; ++$y){
$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()){
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
}
}
}
$this->meta = 0;
$this->getLevel()->setBlock($this, $this);
}else{
++$this->meta;
$this->getLevel()->setBlock($this, $this);
}
}
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
@ -119,7 +117,7 @@ class Cactus extends Transparent{
$block1 = $this->getSide(Vector3::SIDE_SOUTH);
$block2 = $this->getSide(Vector3::SIDE_WEST);
$block3 = $this->getSide(Vector3::SIDE_EAST);
if($block0->isTransparent() === true and $block1->isTransparent() === true and $block2->isTransparent() === true and $block3->isTransparent() === true){
if($block0->isTransparent() and $block1->isTransparent() and $block2->isTransparent() and $block3->isTransparent()){
$this->getLevel()->setBlock($this, $this, true);
return true;
@ -132,4 +130,4 @@ class Cactus extends Transparent{
public function getVariantBitmask() : int{
return 0;
}
}
}

View File

@ -23,11 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Effect;
use pocketmine\event\entity\EntityEatBlockEvent;
use pocketmine\entity\EffectInstance;
use pocketmine\entity\Living;
use pocketmine\item\FoodSource;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -45,7 +44,7 @@ class Cake extends Transparent implements FoodSource{
}
public function getName() : string{
return "Cake Block";
return "Cake";
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
@ -73,37 +72,24 @@ class Cake extends Transparent implements FoodSource{
return false;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
return Level::BLOCK_UPDATE_NORMAL;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
}
return false;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function isAffectedBySilkTouch() : bool{
return false;
}
public function onActivate(Item $item, Player $player = null) : bool{
//TODO: refactor this into generic food handling
if($player instanceof Player and $player->getFood() < $player->getMaxFood()){
$player->getServer()->getPluginManager()->callEvent($ev = new EntityEatBlockEvent($player, $this));
if(!$ev->isCancelled()){
$player->addFood($ev->getFoodRestore());
$player->addSaturation($ev->getSaturationRestore());
foreach($ev->getAdditionalEffects() as $effect){
$player->addEffect($effect);
}
$this->getLevel()->setBlock($this, $ev->getResidue());
return true;
}
if($player !== null){
$player->consumeObject($this);
return true;
}
return false;
@ -117,6 +103,13 @@ class Cake extends Transparent implements FoodSource{
return 0.4;
}
public function requiresHunger() : bool{
return true;
}
/**
* @return Block
*/
public function getResidue(){
$clone = clone $this;
$clone->meta++;
@ -127,9 +120,13 @@ class Cake extends Transparent implements FoodSource{
}
/**
* @return Effect[]
* @return EffectInstance[]
*/
public function getAdditionalEffects() : array{
return [];
}
public function onConsume(Living $consumer) : void{
$this->level->setBlock($this, $this->getResidue());
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -73,16 +72,17 @@ class Carpet extends Flowable{
return false;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
$this->getLevel()->useBreakOn($this);
}
return false;
}
}
public function getFlameEncouragement() : int{
return 30;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -38,7 +38,7 @@ class Carrot extends Crops{
return "Carrot Block";
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
];
@ -47,4 +47,4 @@ class Carrot extends Crops{
public function getPickedItem() : Item{
return ItemFactory::get(Item::CARROT);
}
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\StringTag;
@ -49,7 +48,7 @@ class Chest extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_AXE;
return BlockToolType::TYPE_AXE;
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
@ -102,16 +101,6 @@ class Chest extends Transparent{
return true;
}
public function onBreak(Item $item, Player $player = null) : bool{
$t = $this->getLevel()->getTile($this);
if($t instanceof TileChest){
$t->unpair();
}
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
return true;
}
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
@ -144,4 +133,4 @@ class Chest extends Transparent{
public function getFuelTime() : int{
return 300;
}
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class Clay extends Solid{
@ -40,16 +39,16 @@ class Clay extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
public function getName() : string{
return "Clay Block";
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::CLAY_BALL, 0, 4)
];
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Coal extends Solid{
@ -39,22 +38,26 @@ class Coal extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getName() : string{
return "Coal Block";
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
public function getFuelTime() : int{
return 16000;
}
}
public function getFlameEncouragement() : int{
return 5;
}
public function getFlammability() : int{
return 5;
}
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class CoalOre extends Solid{
@ -40,21 +40,21 @@ class CoalOre extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getName() : string{
return "Coal Ore";
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return [
ItemFactory::get(Item::COAL, 0, 1)
];
}
return [];
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::COAL)
];
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Cobblestone extends Solid{
@ -35,7 +34,11 @@ class Cobblestone extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getName() : string{
@ -45,12 +48,4 @@ class Cobblestone extends Solid{
public function getHardness() : float{
return 2;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class CobblestoneStairs extends Stair{
@ -38,11 +38,15 @@ class CobblestoneStairs extends Stair{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getName() : string{
return "Cobblestone Stairs";
}
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
@ -38,7 +38,11 @@ class CobblestoneWall extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getHardness() : float{

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\ItemFactory;
class Cobweb extends Flowable{
@ -48,19 +48,24 @@ class Cobweb extends Flowable{
}
public function getToolType() : int{
return Tool::TYPE_SWORD;
return BlockToolType::TYPE_SWORD | BlockToolType::TYPE_SHEARS;
}
public function getToolHarvestLevel() : int{
return 1;
}
public function onEntityCollide(Entity $entity) : void{
$entity->resetFallDistance();
}
public function getDrops(Item $item) : array{
//TODO: correct drops
return [];
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::STRING)
];
}
public function diffusesSkyLight() : bool{
return true;
}
}
}

View File

@ -35,5 +35,17 @@ class CocoaBlock extends Transparent{
return "Cocoa Block";
}
public function getHardness() : float{
return 0.2;
}
public function getToolType() : int{
return BlockToolType::TYPE_AXE;
}
//TODO
public function isAffectedBySilkTouch() : bool{
return false;
}
}

View File

@ -24,8 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Concrete extends Solid{
@ -44,15 +43,10 @@ class Concrete extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
}
}

View File

@ -24,8 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorBlockMetaHelper;
use pocketmine\item\Tool;
use pocketmine\level\Level;
class ConcretePowder extends Fallable{
@ -44,16 +42,15 @@ class ConcretePowder extends Fallable{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL and ($block = $this->checkAdjacentWater()) !== null){
public function onNearbyBlockChange() : void{
if(($block = $this->checkAdjacentWater()) !== null){
$this->level->setBlock($this, $block);
return $type;
}else{
parent::onNearbyBlockChange();
}
return parent::onUpdate($type);
}
/**
@ -75,4 +72,4 @@ class ConcretePowder extends Fallable{
return null;
}
}
}

View File

@ -23,9 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\inventory\BigCraftingGrid;
use pocketmine\inventory\CraftingGrid;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\Player;
class CraftingTable extends Solid{
@ -45,12 +44,12 @@ class CraftingTable extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_AXE;
return BlockToolType::TYPE_AXE;
}
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$player->setCraftingGrid(new BigCraftingGrid($player));
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
}
return true;
@ -59,4 +58,4 @@ class CraftingTable extends Solid{
public function getFuelTime() : int{
return 300;
}
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\Server;
@ -65,34 +64,31 @@ abstract class Crops extends Flowable{
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){
$this->getLevel()->useBreakOn($this);
}
}
public function ticksRandomly() : bool{
return true;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if(mt_rand(0, 2) === 1){
if($this->meta < 0x07){
$block = clone $this;
++$block->meta;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
public function onRandomTick() : void{
if(mt_rand(0, 2) === 1){
if($this->meta < 0x07){
$block = clone $this;
++$block->meta;
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
if(!$ev->isCancelled()){
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
}
}else{
return Level::BLOCK_UPDATE_RANDOM;
}
}
}
public function isAffectedBySilkTouch() : bool{
return false;
}
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -52,15 +51,17 @@ class Dandelion extends Flowable{
return false;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
$this->getLevel()->useBreakOn($this);
}
return false;
}
}
public function getFlameEncouragement() : int{
return 60;
}
public function getFlammability() : int{
return 100;
}
}

View File

@ -43,5 +43,9 @@ class DaylightSensor extends Transparent{
return 300;
}
public function getToolType() : int{
return BlockToolType::TYPE_AXE;
}
//TODO
}

View File

@ -25,9 +25,8 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
class DeadBush extends Flowable{
@ -41,29 +40,43 @@ 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){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if(!$this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
return parent::place($item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
$this->getLevel()->useBreakOn($this);
}
}
public function getToolType() : int{
return Tool::TYPE_SHEARS;
return BlockToolType::TYPE_SHEARS;
}
public function getToolHarvestLevel() : int{
return 1;
}
public function getDrops(Item $item) : array{
if($item->isShears()){
return parent::getDrops($item);
if(!$this->isCompatibleWithTool($item)){
return [
ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
];
}
return [
ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
];
return parent::getDrops($item);
}
}
public function getFlameEncouragement() : int{
return 60;
}
public function getFlammability() : int{
return 100;
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Diamond extends Solid{
@ -43,14 +42,10 @@ class Diamond extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_IRON){
return parent::getDrops($item);
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_IRON;
}
}
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class DiamondOre extends Solid{
@ -44,16 +44,16 @@ class DiamondOre extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_IRON){
return [
ItemFactory::get(Item::DIAMOND, 0, 1)
];
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_IRON;
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::DIAMOND)
];
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\Player;
class Dirt extends Solid{
@ -40,7 +39,7 @@ class Dirt extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
public function getName() : string{
@ -64,4 +63,4 @@ class Dirt extends Solid{
return false;
}
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\level\sound\DoorSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
@ -201,26 +200,20 @@ abstract class Door extends Transparent{
return $bb;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false);
if($this->getSide(Vector3::SIDE_UP) instanceof Door){
$this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
}
return Level::BLOCK_UPDATE_NORMAL;
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false);
if($this->getSide(Vector3::SIDE_UP) instanceof Door){
$this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
}
}
return false;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
if($face === Vector3::SIDE_UP){
$blockUp = $this->getSide(Vector3::SIDE_UP);
$blockDown = $this->getSide(Vector3::SIDE_DOWN);
if($blockUp->canBeReplaced() === false or $blockDown->isTransparent() === true){
if(!$blockUp->canBeReplaced() or $blockDown->isTransparent()){
return false;
}
$direction = $player instanceof Player ? $player->getDirection() : 0;
@ -233,36 +226,19 @@ abstract class Door extends Transparent{
$next = $this->getSide($faces[($direction + 2) % 4]);
$next2 = $this->getSide($faces[$direction]);
$metaUp = 0x08;
if($next->getId() === $this->getId() or ($next2->isTransparent() === false and $next->isTransparent() === true)){ //Door hinge
if($next->getId() === $this->getId() or (!$next2->isTransparent() and $next->isTransparent())){ //Door hinge
$metaUp |= 0x01;
}
$this->setDamage($player->getDirection() & 0x03);
$this->getLevel()->setBlock($blockReplace, $this, true, true); //Bottom
$this->getLevel()->setBlock($blockUp, $b = BlockFactory::get($this->getId(), $metaUp), true); //Top
$this->getLevel()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
return true;
}
return false;
}
public function onBreak(Item $item, Player $player = null) : bool{
if(($this->getDamage() & 0x08) === 0x08){
$down = $this->getSide(Vector3::SIDE_DOWN);
if($down->getId() === $this->getId()){
$this->getLevel()->setBlock($down, BlockFactory::get(Block::AIR), true);
}
}else{
$up = $this->getSide(Vector3::SIDE_UP);
if($up->getId() === $this->getId()){
$this->getLevel()->setBlock($up, BlockFactory::get(Block::AIR), true);
}
}
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
return true;
}
public function onActivate(Item $item, Player $player = null) : bool{
if(($this->getDamage() & 0x08) === 0x08){ //Top
$down = $this->getSide(Vector3::SIDE_DOWN);
@ -286,4 +262,32 @@ abstract class Door extends Transparent{
public function getVariantBitmask() : int{
return 0;
}
}
public function getDropsForCompatibleTool(Item $item) : array{
if(($this->meta & 0x08) === 0){ //bottom half only
return parent::getDropsForCompatibleTool($item);
}
return [];
}
public function isAffectedBySilkTouch() : bool{
return false;
}
public function getAffectedBlocks() : array{
if(($this->getDamage() & 0x08) === 0x08){
$down = $this->getSide(Vector3::SIDE_DOWN);
if($down->getId() === $this->getId()){
return [$this, $down];
}
}else{
$up = $this->getSide(Vector3::SIDE_UP);
if($up->getId() === $this->getId()){
return [$this, $up];
}
}
return parent::getAffectedBlocks();
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -84,46 +83,45 @@ class DoublePlant extends Flowable{
);
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(Vector3::SIDE_DOWN);
if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $down->isTransparent())){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
public function onNearbyBlockChange() : void{
if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Vector3::SIDE_DOWN)->isTransparent())){
$this->getLevel()->useBreakOn($this);
}
return false;
}
public function onBreak(Item $item, Player $player = null) : bool{
if(parent::onBreak($item, $player) and $this->isValidHalfPlant()){
$this->getLevel()->useBreakOn($this->getSide(($this->meta & self::BITFLAG_TOP) !== 0 ? Vector3::SIDE_DOWN : Vector3::SIDE_UP), $item, $player, $player !== null);
}
return false;
}
public function getVariantBitmask() : int{
return 0x07;
}
public function getToolType() : int{
return ($this->meta === 2 or $this->meta === 3) ? BlockToolType::TYPE_SHEARS : BlockToolType::TYPE_NONE;
}
public function getToolHarvestLevel() : int{
return ($this->meta === 2 or $this->meta === 3) ? 1 : 0; //only grass or fern require shears
}
public function getDrops(Item $item) : array{
if($this->meta & self::BITFLAG_TOP){
if(!$item->isShears() and ($this->meta === 2 or $this->meta === 3)){ //grass or fern
if(mt_rand(0, 24) === 0){
return [
ItemFactory::get(Item::SEEDS, 0, 1)
];
}
return [];
if($this->isCompatibleWithTool($item)){
return parent::getDrops($item);
}
return parent::getDrops($item);
if(mt_rand(0, 24) === 0){
return [
ItemFactory::get(Item::SEEDS)
];
}
}
return [];
}
}
public function getAffectedBlocks() : array{
if($this->isValidHalfPlant()){
return [$this, $this->getSide(($this->meta & self::BITFLAG_TOP) !== 0 ? Vector3::SIDE_DOWN : Vector3::SIDE_UP)];
}
return parent::getAffectedBlocks();
}
}

View File

@ -38,10 +38,13 @@ abstract class DoubleSlab extends Solid{
return "Double " . BlockFactory::get($this->getSlabId(), $this->getVariant())->getName() . " Slab";
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
];
}
}
public function isAffectedBySilkTouch() : bool{
return false;
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class DoubleStoneSlab extends DoubleSlab{
@ -39,15 +38,10 @@ class DoubleStoneSlab extends DoubleSlab{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
}
}

View File

@ -31,4 +31,4 @@ class DoubleStoneSlab2 extends DoubleStoneSlab{
return self::STONE_SLAB2;
}
}
}

View File

@ -23,8 +23,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
class DoubleWoodenSlab extends DoubleSlab{
protected $id = self::DOUBLE_WOODEN_SLAB;
@ -38,6 +36,14 @@ class DoubleWoodenSlab extends DoubleSlab{
}
public function getToolType() : int{
return Tool::TYPE_AXE;
return BlockToolType::TYPE_AXE;
}
}
public function getFlameEncouragement() : int{
return 5;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Emerald extends Solid{
@ -39,18 +38,14 @@ class Emerald extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_IRON;
}
public function getName() : string{
return "Emerald Block";
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_IRON){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class EmeraldOre extends Solid{
@ -40,20 +40,20 @@ class EmeraldOre extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_IRON;
}
public function getHardness() : float{
return 3;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_IRON){
return [
ItemFactory::get(Item::EMERALD, 0, 1)
];
}
return [];
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::EMERALD)
];
}
}
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\inventory\EnchantInventory;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\EnchantTable as TileEnchantTable;
@ -60,7 +60,11 @@ class EnchantingTable extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function onActivate(Item $item, Player $player = null) : bool{
@ -72,12 +76,4 @@ class EnchantingTable extends Transparent{
return true;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -65,4 +65,4 @@ class EndPortalFrame extends Solid{
$this->z + 1
);
}
}
}

View File

@ -101,4 +101,4 @@ class EndRod extends Flowable{
public function getVariantBitmask() : int{
return 0;
}
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class EndStone extends Solid{
@ -38,10 +38,14 @@ class EndStone extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getHardness() : float{
return 3;
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class EndStoneBricks extends Solid{
@ -43,15 +42,10 @@ class EndStoneBricks extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
}
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\tile\EnderChest as TileEnderChest;
@ -52,7 +52,11 @@ class EnderChest extends Chest{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
@ -71,10 +75,6 @@ class EnderChest extends Chest{
return true;
}
public function onBreak(Item $item, Player $player = null) : bool{
return Block::onBreak($item, $player);
}
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
@ -97,16 +97,14 @@ class EnderChest extends Chest{
return true;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return [ItemFactory::get(Item::OBSIDIAN, 0, 8)];
}
return [];
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::OBSIDIAN, 0, 8)
];
}
public function getFuelTime() : int{
return 0;
}
}
}

View File

@ -24,26 +24,23 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
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 or $down instanceof Fire){
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
public function onNearbyBlockChange() : void{
$down = $this->getSide(Vector3::SIDE_DOWN);
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
$nbt->setInt("TileID", $this->getId());
$nbt->setByte("Data", $this->getDamage());
$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);
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
if($fall !== null){
$fall->spawnToAll();
}
if($fall !== null){
$fall->spawnToAll();
}
}
}
@ -54,4 +51,4 @@ abstract class Fallable extends Solid{
public function tickFalling() : ?Block{
return null;
}
}
}

View File

@ -25,8 +25,6 @@ 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;
@ -47,12 +45,9 @@ class Farmland extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
public function ticksRandomly() : bool{
return true;
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return new AxisAlignedBB(
@ -65,29 +60,28 @@ class Farmland extends Transparent{
);
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
public function onNearbyBlockChange() : void{
if($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;
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
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);
}
}elseif($this->meta < 7){
$this->meta = 7;
$this->level->setBlock($this, $this, false, false);
}
}
protected function canHydrate() : bool{
@ -108,9 +102,13 @@ class Farmland extends Transparent{
return false;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::DIRT, 0, 1)
ItemFactory::get(Item::DIRT)
];
}
}
public function isAffectedBySilkTouch() : bool{
return false;
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\level\sound\DoorSound;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
@ -37,7 +36,7 @@ class FenceGate extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_AXE;
return BlockToolType::TYPE_AXE;
}
@ -95,4 +94,12 @@ class FenceGate extends Transparent{
public function getFuelTime() : int{
return 300;
}
public function getFlameEncouragement() : int{
return 5;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -25,11 +25,11 @@ namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\event\block\BlockBurnEvent;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Server;
@ -61,10 +61,6 @@ class Fire extends Flowable{
return true;
}
public function ticksRandomly() : bool{
return true;
}
public function onEntityCollide(Entity $entity) : void{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
$entity->attack($ev);
@ -79,39 +75,94 @@ class Fire extends Flowable{
}
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
for($s = 0; $s <= 5; ++$s){
$side = $this->getSide($s);
if($side->getId() !== self::AIR and !($side instanceof Liquid)){
return false;
}
}
public function onNearbyBlockChange() : void{
if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
}else{
$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));
}
}
return Level::BLOCK_UPDATE_NORMAL;
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::NETHERRACK){
if(mt_rand(0, 2) === 0){
if($this->meta === 0x0F){
$this->level->setBlock($this, BlockFactory::get(Block::AIR));
}else{
$this->meta++;
$this->level->setBlock($this, $this);
}
public function ticksRandomly() : bool{
return true;
}
return Level::BLOCK_UPDATE_NORMAL;
public function onRandomTick() : void{
$down = $this->getSide(Vector3::SIDE_DOWN);
$result = null;
if($this->meta < 15 and mt_rand(0, 2) === 0){
$this->meta++;
$result = $this;
}
$canSpread = true;
if(!$down->burnsForever()){
//TODO: check rain
if($this->meta === 15){
if(!$down->isFlammable() and mt_rand(0, 3) === 3){ //1/4 chance to extinguish
$canSpread = false;
$result = BlockFactory::get(Block::AIR);
}
}elseif(!$this->hasAdjacentFlammableBlocks()){
$canSpread = false;
if(!$down->isSolid() or $this->meta > 3){ //fire older than 3, or without a solid block below
$result = BlockFactory::get(Block::AIR);
}
}
}
if($result !== null){
$this->level->setBlock($this, $result);
}
$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));
if($canSpread){
//TODO: raise upper bound for chance in humid biomes
foreach($this->getHorizontalSides() as $side){
$this->burnBlock($side, 300);
}
//vanilla uses a 250 upper bound here, but I don't think they intended to increase the chance of incineration
$this->burnBlock($this->getSide(Vector3::SIDE_UP), 350);
$this->burnBlock($this->getSide(Vector3::SIDE_DOWN), 350);
//TODO: fire spread
}
}
public function onScheduledUpdate() : void{
$this->onRandomTick();
}
private function hasAdjacentFlammableBlocks() : bool{
for($i = 0; $i <= 5; ++$i){
if($this->getSide($i)->isFlammable()){
return true;
}
}
return false;
}
}
private function burnBlock(Block $block, int $chanceBound) : void{
if(mt_rand(0, $chanceBound) < $block->getFlammability()){
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockBurnEvent($block, $this));
if(!$ev->isCancelled()){
$block->onIncinerate();
if(mt_rand(0, $this->meta + 9) < 5){ //TODO: check rain
$this->level->setBlock($block, BlockFactory::get(Block::FIRE, min(15, $this->meta + (mt_rand(0, 4) >> 2))));
}else{
$this->level->setBlock($block, BlockFactory::get(Block::AIR));
}
}
}
}
}

View File

@ -42,4 +42,4 @@ abstract class Flowable extends Transparent{
protected function recalculateBoundingBox() : ?AxisAlignedBB{
return null;
}
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -71,15 +70,17 @@ class Flower extends Flowable{
return false;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
$this->getLevel()->useBreakOn($this);
}
return false;
}
}
public function getFlameEncouragement() : int{
return 60;
}
public function getFlammability() : int{
return 100;
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -68,16 +67,10 @@ class FlowerPot extends Flowable{
return true;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_NORMAL){
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
$this->getLevel()->useBreakOn($this);
return Level::BLOCK_UPDATE_NORMAL;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
$this->getLevel()->useBreakOn($this);
}
return false;
}
public function onActivate(Item $item, Player $player = null) : bool{
@ -96,8 +89,12 @@ class FlowerPot extends Flowable{
return true;
}
public function getDrops(Item $item) : array{
$items = parent::getDrops($item);
public function getVariantBitmask() : int{
return 0;
}
public function getDropsForCompatibleTool(Item $item) : array{
$items = parent::getDropsForCompatibleTool($item);
$tile = $this->getLevel()->getTile($this);
if($tile instanceof TileFlowerPot){
@ -110,4 +107,7 @@ class FlowerPot extends Flowable{
return $items;
}
}
public function isAffectedBySilkTouch() : bool{
return false;
}
}

View File

@ -35,4 +35,4 @@ class Furnace extends BurningFurnace{
public function getLightLevel() : int{
return 0;
}
}
}

View File

@ -41,7 +41,7 @@ class Glass extends Transparent{
return 0.3;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
}
}

View File

@ -41,7 +41,7 @@ class GlassPane extends Thin{
return 0.3;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
}
}

View File

@ -25,7 +25,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
use pocketmine\math\Vector3;
use pocketmine\Player;
@ -36,7 +36,11 @@ class GlazedTerracotta extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
@ -56,12 +60,4 @@ class GlazedTerracotta extends Solid{
public function getVariantBitmask() : int{
return 0;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -24,6 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\TieredTool;
class GlowingObsidian extends Solid{
protected $id = self::GLOWING_OBSIDIAN;
@ -47,4 +49,12 @@ class GlowingObsidian extends Solid{
public function getBlastResistance() : float{
return 50;
}
}
public function getToolType() : int{
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_DIAMOND;
}
}

View File

@ -23,12 +23,15 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\level\Level;
use pocketmine\item\Item;
use pocketmine\Player;
class GlowingRedstoneOre extends RedstoneOre{
protected $id = self::GLOWING_REDSTONE_ORE;
protected $itemId = self::REDSTONE_ORE;
public function getName() : string{
return "Glowing Redstone Ore";
}
@ -37,13 +40,19 @@ class GlowingRedstoneOre extends RedstoneOre{
return 9;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_SCHEDULED or $type === Level::BLOCK_UPDATE_RANDOM){
$this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
return Level::BLOCK_UPDATE_WEAK;
}
public function onActivate(Item $item, Player $player = null) : bool{
return false;
}
}
public function onNearbyBlockChange() : void{
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
$this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class Glowstone extends Transparent{
@ -44,16 +43,16 @@ class Glowstone extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getLightLevel() : int{
return 15;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::GLOWSTONE_DUST, 0, mt_rand(2, 4))
];
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Gold extends Solid{
@ -43,14 +42,10 @@ class Gold extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_IRON){
return parent::getDrops($item);
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_IRON;
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class GoldOre extends Solid{
@ -43,14 +42,10 @@ class GoldOre extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_IRON){
return parent::getDrops($item);
}
return [];
public function getToolHarvestLevel() : int{
return TieredTool::TIER_IRON;
}
}
}

View File

@ -26,9 +26,7 @@ namespace pocketmine\block;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
use pocketmine\level\Level;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\utils\Random;
@ -50,12 +48,12 @@ class Grass extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::DIRT, 0, 1)
ItemFactory::get(Item::DIRT)
];
}
@ -63,43 +61,35 @@ class Grass extends Solid{
return true;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_RANDOM){
$lightAbove = $this->level->getFullLightAt($this->x, $this->y + 1, $this->z);
if($lightAbove < 4 and BlockFactory::$lightFilter[$this->level->getBlockIdAt($this->x, $this->y + 1, $this->z)] >= 3){ //2 plus 1 standard filter amount
//grass dies
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this, $this, BlockFactory::get(Block::DIRT)));
public function onRandomTick() : void{
$lightAbove = $this->level->getFullLightAt($this->x, $this->y + 1, $this->z);
if($lightAbove < 4 and BlockFactory::$lightFilter[$this->level->getBlockIdAt($this->x, $this->y + 1, $this->z)] >= 3){ //2 plus 1 standard filter amount
//grass dies
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this, $this, BlockFactory::get(Block::DIRT)));
if(!$ev->isCancelled()){
$this->level->setBlock($this, $ev->getNewState(), false, false);
}
}elseif($lightAbove >= 9){
//try grass spread
for($i = 0; $i < 4; ++$i){
$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($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($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
if(!$ev->isCancelled()){
$this->level->setBlock($this, $ev->getNewState(), false, false);
$this->level->setBlock($b, $ev->getNewState(), false, false);
}
return Level::BLOCK_UPDATE_RANDOM;
}elseif($lightAbove >= 9){
//try grass spread
for($i = 0; $i < 4; ++$i){
$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($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($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
if(!$ev->isCancelled()){
$this->level->setBlock($b, $ev->getNewState(), false, false);
}
}
return Level::BLOCK_UPDATE_RANDOM;
}
}
return false;
}
public function onActivate(Item $item, Player $player = null) : bool{

View File

@ -25,8 +25,6 @@ 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;
@ -43,7 +41,7 @@ class GrassPath extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
protected function recalculateBoundingBox() : ?AxisAlignedBB{
@ -61,18 +59,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()){
public function onNearbyBlockChange() : void{
if($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{
public function getDropsForCompatibleTool(Item $item) : array{
return [
ItemFactory::get(Item::DIRT, 0, 1)
ItemFactory::get(Item::DIRT)
];
}
}
}

View File

@ -25,7 +25,6 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\Tool;
class Gravel extends Fallable{
@ -44,17 +43,17 @@ class Gravel extends Fallable{
}
public function getToolType() : int{
return Tool::TYPE_SHOVEL;
return BlockToolType::TYPE_SHOVEL;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
if(mt_rand(1, 10) === 1){
return [
ItemFactory::get(Item::FLINT, 0, 1)
ItemFactory::get(Item::FLINT)
];
}
return parent::getDrops($item);
return parent::getDropsForCompatibleTool($item);
}
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class HardenedClay extends Solid{
@ -38,10 +38,14 @@ class HardenedClay extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getHardness() : float{
return 1.25;
}
}
}

View File

@ -54,4 +54,12 @@ class HayBale extends Solid{
public function getVariantBitmask() : int{
return 0x03;
}
}
public function getFlameEncouragement() : int{
return 60;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -23,9 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\level\Level;
use pocketmine\Player;
class Ice extends Transparent{
@ -53,29 +52,27 @@ class Ice extends Transparent{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function onBreak(Item $item, Player $player = null) : bool{
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true);
if(!$item->hasEnchantment(Enchantment::SILK_TOUCH)){
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true);
}
return parent::onBreak($item, $player);
}
public function ticksRandomly() : bool{
return true;
}
public function onUpdate(int $type){
if($type === Level::BLOCK_UPDATE_RANDOM){
if($this->level->getHighestAdjacentBlockLight($this->x, $this->y, $this->z) >= 12){
$this->level->useBreakOn($this);
return $type;
}
public function onRandomTick() : void{
if($this->level->getHighestAdjacentBlockLight($this->x, $this->y, $this->z) >= 12){
$this->level->useBreakOn($this);
}
return false;
}
public function getDrops(Item $item) : array{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class Iron extends Solid{
@ -39,18 +38,14 @@ class Iron extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_STONE;
}
public function getHardness() : float{
return 5;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_STONE){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class IronBars extends Thin{
@ -43,20 +42,14 @@ class IronBars extends Thin{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getVariantBitmask() : int{
return 0;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class IronDoor extends Door{
@ -41,18 +41,14 @@ class IronDoor extends Door{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_WOODEN;
}
public function getHardness() : float{
return 5;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_WOODEN){
return parent::getDrops($item);
}
return [];
}
}
}

View File

@ -23,8 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\Tool;
use pocketmine\item\TieredTool;
class IronOre extends Solid{
@ -39,18 +38,14 @@ class IronOre extends Solid{
}
public function getToolType() : int{
return Tool::TYPE_PICKAXE;
return BlockToolType::TYPE_PICKAXE;
}
public function getToolHarvestLevel() : int{
return TieredTool::TIER_STONE;
}
public function getHardness() : float{
return 3;
}
public function getDrops(Item $item) : array{
if($item->isPickaxe() >= Tool::TIER_STONE){
return parent::getDrops($item);
}
return [];
}
}
}

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