Skip to content

Commit

Permalink
[1.21.x] [BC] Move firing point of ChunkEvent$Unload to after chunk s…
Browse files Browse the repository at this point in the history
…ave (#1778)

This change also strongly types the load and unload events to LevelChunk instead of ChunkAccess and updates the class javadocs.
  • Loading branch information
Shadows-of-Fire authored Dec 16, 2024
1 parent 24b9991 commit b13ec03
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 48 deletions.
8 changes: 6 additions & 2 deletions patches/net/minecraft/server/level/ChunkMap.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
return p_140179_;
}
}
@@ -529,8 +_,11 @@
@@ -529,12 +_,15 @@
} else {
ChunkAccess chunkaccess = p_140183_.getLatestChunk();
if (this.pendingUnloads.remove(p_140182_, p_140183_) && chunkaccess != null) {
+ net.neoforged.neoforge.common.CommonHooks.onChunkUnload(this.poiManager, chunkaccess); // Neo: Must be called for all chunk unloading. Not just LevelChunks.
+ this.chunkTypeCache.remove(chunkaccess.getPos().toLong()); // Neo: Prevent chunk type cache from permanently retaining data for unloaded chunks
if (chunkaccess instanceof LevelChunk levelchunk) {
levelchunk.setLoaded(false);
+ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.level.ChunkEvent.Unload(chunkaccess));
}

this.save(chunkaccess);
if (chunkaccess instanceof LevelChunk levelchunk1) {
+ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.level.ChunkEvent.Unload(levelchunk1));
this.level.unload(levelchunk1);
}

@@ -579,6 +_,7 @@
Profiler.get().incrementCounter("chunkLoad");
if (p_372662_.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* ChunkDataEvent is fired when a chunk is about to be loaded from disk or saved to disk.
*/
public abstract class ChunkDataEvent extends ChunkEvent {
public abstract class ChunkDataEvent extends ChunkEvent<ChunkAccess> {
private final SerializableChunkData data;

public ChunkDataEvent(ChunkAccess chunk, SerializableChunkData data) {
Expand Down
73 changes: 28 additions & 45 deletions src/main/java/net/neoforged/neoforge/event/level/ChunkEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,83 +9,66 @@
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.neoforged.bus.api.Event;
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
import net.neoforged.neoforge.common.NeoForge;
import org.jetbrains.annotations.ApiStatus;

/**
* ChunkEvent is fired when an event involving a chunk occurs.<br>
* If a method utilizes this {@link Event} as its parameter, the method will
* receive every child event of this class.<br>
* <br>
* {@link #chunk} contains the Chunk this event is affecting.<br>
* <br>
* All children of this event are fired on the {@link NeoForge#EVENT_BUS}.<br>
**/
public abstract class ChunkEvent extends LevelEvent {
private final ChunkAccess chunk;
* Base class for events involving chunks.
* <p>
* All children of this event are fired on the {@link NeoForge#EVENT_BUS}.
*/
public abstract class ChunkEvent<T extends ChunkAccess> extends LevelEvent {
private final T chunk;

public ChunkEvent(ChunkAccess chunk) {
public ChunkEvent(T chunk) {
super(chunk.getLevel());
this.chunk = chunk;
}

public ChunkEvent(ChunkAccess chunk, LevelAccessor level) {
public ChunkEvent(T chunk, LevelAccessor level) {
super(level);
this.chunk = chunk;
}

public ChunkAccess getChunk() {
public T getChunk() {
return chunk;
}

/**
* ChunkEvent.Load is fired when vanilla Minecraft attempts to load a Chunk into the level.<br>
* This event is fired during chunk loading in <br>
*
* Chunk.onChunkLoad(). <br>
* <strong>Note:</strong> This event may be called before the underlying {@link LevelChunk} is promoted to {@link ChunkStatus#FULL}. You will cause chunk loading deadlocks if you don't delay your level interactions.<br>
* <br>
* This event is not {@link ICancellableEvent}.<br>
* <br>
* This event does not have a result. {@link HasResult} <br>
* <br>
* This event is fired on the {@link NeoForge#EVENT_BUS}.<br>
**/
public static class Load extends ChunkEvent {
* This event is fired after Minecraft loads a {@link LevelChunk} into the level, on both the client and server.
* <p>
* Specifically, this is fired during chunk loading in {@link ChunkStatusTasks#full}, and when the client receives a chunk from the server.
* <p>
* <b>Note:</b> On the server, this event is fired before the underlying {@link LevelChunk} is promoted to {@link ChunkStatus#FULL}.
* Interactions with the {@link LevelChunk#getLevel() level} must be delayed until the next game tick to prevent deadlocking the game.
*/
public static class Load extends ChunkEvent<LevelChunk> {
private final boolean newChunk;

@ApiStatus.Internal
public Load(ChunkAccess chunk, boolean newChunk) {
public Load(LevelChunk chunk, boolean newChunk) {
super(chunk);
this.newChunk = newChunk;
}

/**
* Check whether the Chunk is newly generated, and being loaded for the first time.
*
* <p>Will only ever return {@code true} on the {@linkplain net.neoforged.fml.LogicalSide#SERVER logical server}.</p>
*
* @return whether the Chunk is newly generated
* {@return true if this is a newly-generated chunk, instead of one loaded from disk}
*
* @apiNote This method only has meaning on the server, since the client does not generate chunks.
*/
public boolean isNewChunk() {
return newChunk;
}
}

/**
* ChunkEvent.Unload is fired when vanilla Minecraft attempts to unload a Chunk from the level.<br>
* This event is fired during chunk unloading in <br>
* Chunk.onChunkUnload(). <br>
* <br>
* This event is not {@link ICancellableEvent}.<br>
* <br>
* This event does not have a result. {@link HasResult} <br>
* <br>
* This event is fired on the {@link NeoForge#EVENT_BUS}.<br>
**/
public static class Unload extends ChunkEvent {
public Unload(ChunkAccess chunk) {
* This event is fired when Minecraft unloads a Chunk from the level, just before the side-specific unload method is called.
* <p>
* On the server, this event is fired after the chunk has been saved, and {@link ChunkDataEvent.Save} has been fired.
*/
public static class Unload extends ChunkEvent<LevelChunk> {
public Unload(LevelChunk chunk) {
super(chunk);
}
}
Expand Down

0 comments on commit b13ec03

Please sign in to comment.