- `AsyncGeneratorExecutor` class added that encapsulates the logic of generating chunks using async tasks as previously
- `GeneratorExecutor` interface added that can be implemented to provide chunks in other ways
- `SyncGeneratorExecutor` which invokes the generator directly on the main thread, useful for simple generators like `Flat` where async tasks are not needed
- Some redundant APIs were removed from `World` (these will probably come back as deprecated stubs for the remainder of 5.x, but I was having too much fun deleting code)
- Removed internal `World->registerGeneratorToWorker()` (no longer useful)
- `World` now invokes generator executor instead of posting AsyncTasks directly
- Some internal classes moved to `pocketmine\world\generator\executor` (PopulationTask excluded because plugins use it in lieu of being able to regenerate chunks
- Generators can opt into main-thread execution by setting the `$fast` parameter to `true` in `GeneratorManager::register()`
I want to do the same for items, but items are going to be a pain in the ass.
For items there are multiple possible entry points and all of them will need to be checked:
- dropped items
- inventory contents
- lecterns
- item frames
I don't see a good way to deal with all these. We can't check for registration in the constructor
because we need to fully construct the item in order to register it.
Blocks are also a potential issue in other areas, but setBlock() is definitely the biggest offender.
This PR significantly improves performance of entity movement calculation.
Previous attempts to optimise this were ineffective, as they used a cache to mitigate the cost of recomputing AABBs. Entities tend to move around randomly, so the non-cached pathway really needed to be optimized.
This change improves performance on multiple fronts:
1) avoiding Block allocations for blocks with 1x1x1 AABBs and with no AABBs (the most common)
2) avoiding Block allocations and overlapping intersection checks unless a stateID is specifically known to potentially exceed its cell boundaries (like fences)
3) avoiding overlapping AABB checks when overlaps can't make any difference anyway (cubes)
Together, these changes improve the performance of World->getBlockCollisionBoxes() by a factor of 5. In real-world terms, this shows up as a major performance improvement in situations with lots of entities moving in random directions. Testing with item entities showed an increase from 400 to 1200 moving items with the same CPU usage.
This change is built on the assumption that `Block->recalculateCollisionBoxes()` and its overrides don't interact with any world. This is technically possible due to the crappy design of the `Block` architecture, but should be avoided. As a world is not available during `RuntimeBlockStateRegistry` initialization, attempting to interact with a world during `recalculateCollisionBoxes()` will now cause a crash.
This turned out to be a problem for `ChorusPlant`, which was fixed by 70fb9bbdfd06c7eda00b4cd2c2c3840755e6b8f6. The correct solution in this case was to use dynamic states similar to how we currently deal with fence connections.
This has been a long-standing issue since at least 2016, and probably longer.
Heavy use of getBlock(At) could cause the cache to blow up and use all available memory.
Recently, it's become clear that unmanaged cache size is also a problem for GC, because
the large number of objects blows up the GC root buffer. At first, this causes more frequent
GC runs; later, the frequency of GC runs drops, but the performance cost of them goes up
substantially because of the sheer number of objects. We can avoid this by trimming the
cache when we detect that it's exceeded limits.
I've implemented this in such a way that failing to update blockCacheSize in new code
won't have lasting impacts, since the cache count will be recalculated during scheduled
cache cleaning anyway.
Closes#152.
This allows, for example, banning the usage of spawn eggs, without preventing opening of doors, without the need for item ID whitelists.
It also allows customizing the behaviour of item and block interactions when sneaking - it's now possible to force spawn eggs to work when sneaking, or force containers to open.
Finally, this also allows preventing any interaction at all without preventing block placement (by setting both to false). Since cancelling the event will typically prevent placement too (which might not be desired).
Side note: Blocks are now always synced when right-clicking on a block.
This differs from the previous behaviour, where the blocks were only synced when the action "failed".
However, since this change introduces a situation where the action may succeed but have different results than the client expects, it's best to just always sync blocks in this situation.
Fixes#3267
we can safely assume this for blocks (though the type info doesn't reflect it) but this is not safe to assume for random APIs that might be used by plugins.
This reverts commit 8f804f6f342e650156767372bac2d42b55297361.
This change is too disruptive, since popular plugins like
ExtendedBlocks and ExtendedBlocksConverter relied on custom tiles.
Deleting them at this stage would prevent these plugins from working,
making it impossible to upgrade old data.
An alternative solution to this problem will need to be developed.
The old code was allocating 6 Vector3s which were all immediately discarded. In addition, we didn't need to take the performance hit of reading Vector3 properties when we could have just passed integers directly.
The real performance difference of this is likely to be close to zero, but it's still worth doing.
closes#6104
This function has been a footgun for anyone using it, since it also returns entity AABBs by default.
In all core use cases, this functionality was disabled, and we were paying a needless (admittedly micro) performance penalty for passing the extra useless argument and useless condition check.
This reverts commit 128eb500ebee5163583b84640a9c4f28c0218d42.
This breaks when entities in neighbouring chunks overlap into the
current chunk without actually being tracked by it.
Perhaps it might be worth having entities tracked by all chunks their
AABB touches in the future, so that we don't have to check padding
chunks and waste CPU time.
this slashes the cost of checking this with no entities by 50%, which should be the common case for farms and such.
once factoring in other things, this translates into a real-world performance gain of about 15% for block updates.
in many instances, remnants of improperly removed blocks from PM3 have been causing problems, such as flower pot tiles where there are no flower pots.
this change might break some plugins which are using tiles for custom purposes, but this is a misuse that was never supported properly in the first place.
a couple of usages of properties that no longer exist couldn't be migrated.
in addition, this revealed a couple of dead properties in the default file.
this is not an ideal solution (I'd much rather model the configs using classes and map them) but in the absence of a good and reliable library to do that, this is the next best thing.
* World: cache block AABBs directly in the world
this removes some indirection when fetching the AABBs, and also allows the AABB cache to live longer than the block cache.
In local testing this showed a 10-20% performance improvement, but it was difficult to properly measure.
* World: eliminate padding block checks in getCollisionBoxes()
this substantially improves the function's performance for small entities.
The padding of 1 block in each direction was previously necessary to account for blocks like fences, which might have an AABB larger than the cell containing them. However, by tracking this information in the collisionBoxCache directly, we can avoid the need to check this at the expense of slightly more complex code. This reduces the number of blocks checked for a moving item entity from 27-64 all the way down to 1-8, which is a major improvement.
Locally, this change allowed me to simulate 2100 item entities without lag, compared with 1500 on the previous commit.
having them be clean by default makes no sense. It only makes sense for them to be clean if they were loaded directly from disk without any alterations.
Default clean is a footgun.