WorldProviders now have the following requirements removed:
- __construct() is no longer required to have a specific signature
- static isValid() no longer needs to be implemented (you will still need it for registering, but it can be declared anywhere now)
- static generate() no longer needs to be implemented
This paves the way for more interesting types of world providers that use something other than local disk to store chunks (e.g. a mysql database).
WorldProviderManager no longer accepts class-string<WorldProvider>. Instead, WorldProviderManagerEntry is required, with 2 or 3 callbacks:
- ReadOnlyWorldProviderManager must provide a callback for isValid, and a callback for fromPath
- WritableWorldProviderManagerEntry must provide the same, and also a generate() callback
In practice, this requires zero changes to the WorldProviders themselves, since a WorldProviderManagerEntry can be created like this:
`new WritableWorldProviderManagerEntry(\Closure::fromCallable([LevelDB::class, 'isValid']), fn(string ) => new LevelDB(), \Closure::fromCallable([LevelDB::class, 'generate']))`
This provides identical functionality to before for the provider itself; only registration is changed.
this implementation is working, although incomplete:
- The shulker close sound should not be played until the end of the shulker closing animation, which takes approximately 1 second.
- An open shulker box has a different collision box than a closed one - it should be +0.5 in whichever direction the shulker is facing. (During the animation, the bounding box also dynamically changes size - you can see this in vanilla by shooting an arrow into the top of an open shulkerbox facing UP, and then closing it - the arrow will fall and collide with the lid multiple times.
However, resolving both of these issues requires significant internal changes which are beyond the scope of this PR.
the intent of these hacks was to break cyclic references to avoid having objects lingering in memory. However, all of the stuff that's being removed in this commit no longer has any effect anyway, due to the fact that these things don't circularly reference each other anymore. Notably, Tile inventories now keep Position instead of a Tile ref.
this makes more sense overall from a reader's perspective.
and also provide a rug-jerk for any idiots using World->close() when they aren't supposed to? ....
since we write these into a transaction instead of actually modifying the world directly, we can use the transaction to verify that the placement location is OK before setting the blocks.
closes#4248
instead, use a const array of the offsets and add them to the coordinates, which avoids the allocations.
In synthetic benchmarks, this method takes 40-50% less CPU time by eliding ZEND_INIT_ARRAY and ZEND_ADD_ARRAY opcodes. In practice, the benefit will likely be much smaller (perhaps even irrelevant).
this can fail if the backups directory points to a different drive than the original worlds location. In this case, we have to copy and delete the files instead, which is much slower, but works.
I REALLY advise against putting backups on a different mount point than worlds if you plan to convert large worlds.
when a chunk population is ordered, its only chunk loader is the one that the World installed to keep the chunk loaded while it was generated. So, when the resolver removes its chunk loader from the chunk, it triggers the chunk unloading mechanism, which causes the promise to directly be rejected.
closes#3461
literally every other particle/sound has the subject first, followed by the (optional) verb, and finally Particle (or Sound).
In addition, we refer to breaking blocks as 'break' everywhere except here, where we refer to it as 'destroy'.
this is slightly slower, but saves a significant amount of memory (~80 KB per chunk).
Since ext-chunkutils2 doesn't do copy-on-write trickery like the PHP impl did, we need this to get the memory advantages back.