964 Commits

Author SHA1 Message Date
Dylan K. Taylor
78ffad5ffc
World: add checks for tile position outside of world bounds, closes #4622 2021-12-07 16:41:52 +00:00
Dylan K. Taylor
ed4978c31b
Added VanillaItems::AIR()
we don't usually add VanillaItems entries for blocks since they already exist in VanillaBlocks, but air has a special use case specifically as an itemstack, so we make an exception for this case.
2021-12-07 00:41:07 +00:00
Dylan K. Taylor
8e37f86480
Avoid file_put_contents() when overwriting files
this fixes many cases of corruption during disk-full situations - file_put_contents() would write an empty file, destroying the original data.
fixes #3152
2021-12-05 00:26:48 +00:00
Dylan K. Taylor
1a046c6cd5
LevelDB: fixed server crash when corrupted / invalid blockstate NBT is encountered 2021-12-04 18:17:17 +00:00
Dylan K. Taylor
e61aaaccca
LevelDB: removed hack for problem fixed by 1f9400f9011546ab914090853069aaa76192a722 2021-12-04 16:20:57 +00:00
Dylan K. Taylor
1f9400f901
World: automatically remap invalid blockstates on chunk load
this fixes a wide range of blocks with invalid blockstates becoming update! blocks on the client.

The most common occurrence of this was air with nonzero metadata left behind by world editors which set blockIDs but not block metadata. This caused large ghost structures of update! blocks to appear from nowhere.

The performance impact of this is very minimal (20 microseconds per chunk load in timings, compared to average 660 microseconds to load tiles).
2021-11-27 01:12:30 +00:00
Dylan K. Taylor
e5149756a8
WorldTimings: fixed merge error introduced by 3bf87378ef24eec8845bb048a6916f188d9b1220 2021-11-27 00:06:09 +00:00
Dylan K. Taylor
5c7125f190
Improved error handling for loading broken entity / tile data 2021-11-23 17:41:26 +00:00
Dylan K. Taylor
d8f0fd0a7e
McRegion: skip chunks with TerrainGenerated=false
legacy PM used to save even ungenerated chunks, and omitted some tags when doing so which we expect to always be present.
2021-11-23 01:49:48 +00:00
Dylan K. Taylor
fb0eebc0dc
RegionWorldProvider: Show a more specific message on missing required ByteArrayTags 2021-11-23 01:39:35 +00:00
Dylan K. Taylor
269231c228
Ban foreach(arrayWithStringKeys as k => v)
this is not as good as phpstan/phpstan-src#769 (e.g. array_key_first()/array_key_last() aren't covered by this, nor is array_rand()) but it does eliminate the most infuriating cases where this usually crops up.
2021-11-15 22:52:05 +00:00
Dylan K. Taylor
2f408708f0
Explosion: fixed blocks with tiles not using said tiles for drop info
closes #4571
2021-11-14 16:27:47 +00:00
Dylan K. Taylor
a6f6b60bed
fix CS again 2021-11-08 18:02:24 +00:00
Dylan K. Taylor
c6c992a1f0
Preparations for negative Y support 2021-11-08 17:28:22 +00:00
DataLion
4131bcef08
Changed "Level" string to "World" in Position::__toString() method. (#4559) 2021-11-07 21:11:55 +00:00
Dylan K. Taylor
0356716e8e
PopulationTask: do not expose internal fields as public
this code dates back to pthreads v2, when visibility on Threaded object fields meant different things (wtf, krakjoe??)
2021-11-03 15:23:43 +00:00
Dylan K. Taylor
5c81b04813
PopulationTask: use typed properties 2021-11-03 15:22:49 +00:00
Dylan K. Taylor
1ebb206762
World: fixed yet another edge case in drainPopulationRequestQueue() leading to assertion failure
really had to go fucking nuclear on it :(
2021-11-03 14:58:58 +00:00
Dylan K. Taylor
d184838ba0
Move Promise classes to their own namespace 2021-11-02 17:10:07 +00:00
Dylan K. Taylor
38f97bed52
World: fixed PopulationTask failed assumption that generator is always registered
if the worker selected previously had a generator registered, but has since been shutdown, the workerStartHook that cleans up generatorRegisteredWorkers won't yet have been called.
This results in the worker being started by the submission of PopulationTask, and the generator doesn't get preemptively registered.
2021-11-02 16:58:14 +00:00
Dylan K. Taylor
e34364412b
Replace InvalidStateException usages with InvalidArgument or LogicException 2021-11-02 16:05:54 +00:00
Dylan K. Taylor
8b3565b75d
PopulationTask no longer depends on a World object
this means it's now possible to test generation offline without too much hassle.
World::generateChunkCallback() has been removed from public API.
2021-11-02 15:40:51 +00:00
Dylan K. Taylor
facfd7c04a
sanity check 2021-11-02 15:26:54 +00:00
Dylan K. Taylor
65ef9f786a
Use standard chunkHash() to index population chunks 2021-11-02 15:25:03 +00:00
Dylan K. Taylor
34ea199fb0
World: fixed additional edge case - population promise rejected before task completion
if this happened, the index would stay set in activeChunkPopulationTasks, eventually causing the generation queue to jam up completely and non-forced generation to come to a standstill.
2021-11-02 14:30:23 +00:00
Dylan K. Taylor
1775699f05
World: make sure that chunks locked by PopulationTask always get unlocked, no matter what
fixes #4527
2021-11-02 14:20:42 +00:00
Dylan K. Taylor
c17587d436
World: use new Vector3() instead of Block->getPosition()
When profiling this, I noticed that we spend a stupidly large amount of time creating useless Position objects in the case of update=true, because Vector3->sides() calls Position->getSide(), which calls Position::fromObject(parent::getSide()). This is stupid because the update logic doesn't require Positions anywhere (as evidenced by this change needing no other alterations.

A rough profile shows that this improves setBlock() performance by about 25% in the update=true case, which is a pretty big margin.
As an added bonus, it gets rid of some unrealized cyclic dependencies in World->changedBlocks.
2021-11-02 03:00:00 +00:00
Dylan K. Taylor
616eb0050d
World: remove premature optimisation of setBlockAt() introduced by ece28e5d7b0d4c8d12a9477cdd1d3337277e892d
closes #4531
it turns out that letting the light updates themselves handle this is faster than trying to get in the way.
2021-11-01 02:34:44 +00:00
Dylan K. Taylor
9d30bc8b95
World: fixed assertion failure when requesting, cancelling, and then re-requesting chunks via requestChunkPopulation()
if the request/cancel/re-request happens all in the time before the queue gets drained, chunk hashes may appear multiple times in the queue. We don't want to process them twice if this happens (although it's mostly harmless anyway).
2021-11-01 02:17:11 +00:00
Dylan K. Taylor
c781efcf90
World: avoid calling the same logic twice in requestChunkPopulation()
orderChunkPopulation() checks the preconditions too. Have them both call an internal function that doesn't.
2021-11-01 00:36:57 +00:00
Dylan K. Taylor
e4a54f5b6a
World: deduplicate code in request/orderChunkPopulation 2021-11-01 00:33:18 +00:00
Dylan K. Taylor
afb54f1ae4
World: flip orderChunkPopulation() condition around
this makes it more obvious that the code is similar to requestChunkPopulation() barring one distinct difference.
2021-11-01 00:25:30 +00:00
Dylan K. Taylor
8f803df511
World: check population locks _after_ checking if the chunk is already populated, not before
this led to another case where a population request would be queued up for an already-populated chunk for no reason.
2021-10-31 23:54:27 +00:00
Dylan K. Taylor
f4a3c40b5c
World: use better variable names in orderChunkPopulation() 2021-10-31 23:48:00 +00:00
Dylan K. Taylor
9dec82cdbc
World: fixed requestChunkPopulation() queuing requests for chunks which are already populated
this led to chunk sending getting bogged down if there were more than population-queue-size chunks waiting to be generated.
2021-10-31 23:40:34 +00:00
Dylan K. Taylor
74031d2fbe
World: remove the fulfilled promise from the population request map
fixes crash when unregistering chunk loaders
2021-10-31 23:05:12 +00:00
Dylan K. Taylor
96cfdc79b8
World: fixed original promise not getting fulfilled if the chunk became populated=true after a promise was already made (but not fulfilled) to populate it
this could happen if a plugin calls setPopulated(true) on a chunk after a request for its population landed in the queue, but before it actually got processed. In that case, the promise would never get fulfilled.
2021-10-31 22:54:37 +00:00
Dylan K. Taylor
2fa0a914ff
World::orderChunkPopulation() may return a pre-resolved promise
this does not indicate a failure; it indicates that the chunk has already been successfully populated.
In this case, we shouldn't be putting the task back on the queue.

This is skirting around the real bug, which is that requestChunkPopulation() doesn't check if the target chunk is already populated before it creates a new promise that it will be.
2021-10-31 22:51:37 +00:00
Dylan T
0f78a2b5ef
Advisory chunk locking for chunk population (#4513)
this allows chunks locked for population to be modified. If the PopulationTask detects that the chunk was modified during the onCompletion(), the result of the population will be discarded and rescheduled, so that it includes user modifications.
2021-10-31 21:11:20 +00:00
Dylan K. Taylor
f1a791ef75
Improved Promise API - separate resolver and consumer APIs
this makes creating a promise slightly more cumbersome, but I'm more concerned about people who might try to call 'new Promise' directly.
2021-10-31 19:49:57 +00:00
Dylan K. Taylor
4fe3f69702
World: eliminate final remaining 'no loaders attached' debug message on player creation 2021-10-31 14:33:27 +00:00
Dylan K. Taylor
fbb91d123d
World::unregisterChunkListenerFromAll(): go through unregisterChunkListener()
this ensures that everything gets cleaned up properly (e.g. player chunk listeners).
2021-10-31 14:03:40 +00:00
Dylan K. Taylor
3dc75644d9
World: avoid duplicated logger code in initChunk() 2021-10-31 14:02:25 +00:00
Dylan K. Taylor
1cabe4baf3
World: do not crash on duplicate tiles loaded from disk
closes #4049
2021-10-31 13:58:32 +00:00
Dylan K. Taylor
faad2365e2
World: Register a temporary chunk loader on chunks used by PopulationTask
fixes #3839
2021-10-30 22:17:06 +01:00
Dylan K. Taylor
465a509858
World: remove spammy debug message 2021-10-30 16:13:01 +01:00
Dylan K. Taylor
a4eda9a8f5
World: call nearby entities' onNearbyBlockChange() in setChunk()
fixes #2779 in all known cases.
2021-10-28 23:59:32 +01:00
Dylan K. Taylor
eb75df6f8e
World: Intelligently perform automatic transfer or deletion of tiles in setChunk(), depending on the context
tiles may be deleted in the following circumstances:
1) the target block in the new chunk doesn't expect a tile
2) the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile)
3) there's already a tile in the target chunk which conflicts with the old one

In all other cases, the tile will be transferred.

This resolves a large number of unintentional bugs caused by world editors replacing chunks without setting the deleteTilesAndEntities parameter to false (even the core itself does it).

closes #4520
2021-10-28 23:48:17 +01:00
Dylan K. Taylor
c66790b6a6
World: never delete entities in setChunk()
entities exist completely independently from chunks now, so there is no need to interact with them whatsoever.
As I wrote in #4520, there's no sense in deleting entities here, since a chunk replacement is essentially just a mass block update.

On that theme, it might be a good idea to call Entity->onNearbyBlockChange() for all entities in the target and adjacent chunks when replacing a chunk, to ensure that they get the proper movement updates.
2021-10-28 23:42:28 +01:00
Dylan K. Taylor
d78801b9d5
World: fixed tiles and entities getting deleted when adjacent chunks are modified during population 2021-10-28 22:24:47 +01:00