-
Notifications
You must be signed in to change notification settings - Fork 440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE #4541
base: 1.21.5
Are you sure you want to change the base?
Add ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE #4541
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: I am probably wrong about the threads that the level changes take place, since I was confusing this with chunks actually becoming available to the world, including the difference of getChunk and getChunkNow.
I think implementing this without major changes is a bad idea due to the missing explanation of the meaning of the chunk level type changes.
I believe that if understood correctly, the chunk level type is NOT what you want to track, as the status that is being tracked here only describes whether the game aims to load a chunk, but not whether the chunk is actually being loaded or available to the general game logic.
In my mod, lithium, which tracks whether a chunk is accessible in the world, I had several issues tracking this status correctly. I managed to get all events fire on the server thread, to avoid threading issues. Furthermore, Lithium (almost correctly) tracks whether the chunk is accessible in the world, instead of whether the game tries to make it accessible (status set but chunk future not done yet). I believe that if the API just tracks the level/status, many authors will incorrectly assume that this information is sufficient to know that a chunk is available in the world.
Including the other load statuses, especially regarding entity ticking, adds another layer of complexity and unclear meanings, requiring even more clear documentation.
|
||
@Inject(method = "increaseLevel", at = @At("TAIL")) | ||
private void increaseLevel(ServerChunkLoadingManager chunkLoadingManager, CompletableFuture<OptionalChunk<WorldChunk>> chunkFuture, Executor executor, ChunkLevelType target, CallbackInfo ci) { | ||
ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE.invoker().onChunkLevelTypeChange((ServerWorld) world, this.pos, ChunkLevels.getType(this.lastTickLevel), target); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On which thread should this be called, and should this be ensured with a similar check as in
https://github.com/CaffeineMC/lithium/blob/ebcbdb134365ab1862461548f857cdecf96e4d31/common/src/main/java/net/caffeinemc/mods/lithium/common/world/chunk/ChunkStatusTracker.java#L48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done some testing and it does seem like the event is always consistently called on the main server thread.
/** | ||
* Called when a chunk changes its {@link ChunkLevelType}. | ||
* | ||
* <p>When this event is called, the chunk's level type has already changed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which meaning does changing the chunk level type have?
There might be many misconceptions about this, leading to lots of incorrect implementations. The code comment is very minimal and doesn't indicate any potential issues.
For example, if a mod author believes the chunk status indicates one of the following, there will likely be major issues:
Whether the chunk is loaded, whether entities are ticking in that chunk, whether entities are loaded in that chunk, whether the chunk is ticking blocks in that chunk, etc.
} | ||
|
||
@Inject(method = "decreaseLevel", at = @At("TAIL")) | ||
private void decreaseLevel(ServerChunkLoadingManager chunkLoadingManager, ChunkLevelType target, CallbackInfo ci) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is only called once if a chunk changes from entity ticking to inaccessible in a single tick. This will make event users to only get a INACCESSIBLE
when such transition happens. The event should be called for all intermediate states to avoid confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean there should be a check to see if the old/new chunk levels are sequential, and if not artificially invoke the event for all the intermediate level types in order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean there should be a check to see if the old/new chunk levels are sequential, and if not artificially invoke the event for all the intermediate level types in order?
Yes.
This is a side note but
These are all level decreases, and I don't think this changes the actual functionality of the event but just pointing it out. |
Rewording my concerns: |
…hunk's future is actually completed.
The event is now called when the chunk future has actually completed, and is called on the main thread's executor. I added some rough logging tests to verify the chunk's behaviour aligns with the level type but I'm honestly not sure how to test such a thing correctly. This has been implemented but there is a potential issue:
If a chunk goes straight from ENTITY_TICKING to INACCESSIBLE, and all the intermediate level types are artificially called, then the calls for ENTITY_TICKING -> BLOCK_TICKING and BLOCK_TICKING -> FULL may make modders assume the chunk is still accessible when it really isn't. |
…w levelTypes are actually sequential
Add a new event that fires when a chunk's level type changes. (Relates to #4507)
Changed the name from
CHUNK_STATUS_CHANGE
as to not confuse it with theChunkStatus
class which refers to chunk generation stages.The event only provides a
ChunkPos
and not aWorldChunk
. If really needed, a potentially nullWorldChunk
can be obtained viaChunkHolder#getLatest()
but I do not think it's necessary.The documentation of
CHUNK_UNLOAD
has also been updated to clarify server chunk unload timing.