Skip to content

Commit

Permalink
Merge branch '1.21.x' into gh-791
Browse files Browse the repository at this point in the history
  • Loading branch information
neoforged-automation[bot] authored Dec 16, 2024
2 parents 20c6e3e + b13ec03 commit 50f5f2a
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 49 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 @@ -535,6 +535,7 @@ public NeoForgeMod(IEventBus modEventBus, Dist dist, ModContainer container) {
ITEM_SUB_PREDICATES.register(modEventBus);
SLOT_DISPLAY_TYPES.register(modEventBus);
INGREDIENT_TYPES.register(modEventBus);
FLUID_INGREDIENT_TYPES.register(modEventBus);
CONDITION_CODECS.register(modEventBus);
GLOBAL_LOOT_MODIFIER_SERIALIZERS.register(modEventBus);
NeoForge.EVENT_BUS.addListener(this::serverStopping);
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ public class FluidIngredientCodecs {
static Codec<FluidIngredient> codec() {
return Codec.xor(
NeoForgeRegistries.FLUID_INGREDIENT_TYPES.byNameCodec().<FluidIngredient>dispatch("neoforge:ingredient_type", FluidIngredient::getType, FluidIngredientType::codec),
SimpleFluidIngredient.CODEC).xmap(either -> either.map(i -> i, i -> i), ingredient -> switch (ingredient) {
// Use lazy: SimpleFluidIngredient.CODEC is initialized after FluidIngredient.CODEC which lives in a superclass.
Codec.lazyInitialized(() -> SimpleFluidIngredient.CODEC))
.xmap(either -> either.map(i -> i, i -> i), ingredient -> switch (ingredient) {
case SimpleFluidIngredient simple -> Either.right(simple);
default -> Either.left(ingredient);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package net.neoforged.neoforge.unittest;

import com.mojang.serialization.JsonOps;
import java.util.List;
import java.util.stream.Stream;
import net.minecraft.core.component.DataComponentPatch;
Expand All @@ -17,6 +18,7 @@
import net.neoforged.neoforge.fluids.crafting.CompoundFluidIngredient;
import net.neoforged.neoforge.fluids.crafting.DataComponentFluidIngredient;
import net.neoforged.neoforge.fluids.crafting.FluidIngredient;
import net.neoforged.neoforge.fluids.crafting.IntersectionFluidIngredient;
import net.neoforged.testframework.junit.EphemeralTestServerProvider;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -74,6 +76,7 @@ void fluidIngredientComponentMatchingWorks(boolean strict, MinecraftServer serve
.isEqualTo(!strict);
}

@Test
void singleFluidIngredientIgnoresSizeAndData(MinecraftServer server) {
var ingredient = FluidIngredient.of(Fluids.WATER);

Expand All @@ -85,4 +88,30 @@ void singleFluidIngredientIgnoresSizeAndData(MinecraftServer server) {
.withFailMessage("Single fluid ingredient should match regardless of fluid data!")
.isTrue();
}

@Test
void customFluidIngredientSerialization(MinecraftServer server) {
var ingredient1 = FluidIngredient.of(Fluids.WATER, Fluids.LAVA);
var ingredient2 = FluidIngredient.of(Fluids.LAVA);
var intersection = IntersectionFluidIngredient.of(ingredient1, ingredient2);

var ops = server.registryAccess().createSerializationContext(JsonOps.INSTANCE);
var result = FluidIngredient.CODEC.encodeStart(ops, intersection)
.getOrThrow(error -> new RuntimeException("Failed to serialize ingredient: " + error));

var deserialized = FluidIngredient.CODEC.decode(ops, result)
.getOrThrow(error -> new RuntimeException("Failed to deserialize ingredient: " + error))
.getFirst();

if (!(deserialized instanceof IntersectionFluidIngredient)) {
throw new AssertionError("Deserialized ingredient is not an IntersectionFluidIngredient! Got " + deserialized);
}

if (deserialized.test(new FluidStack(Fluids.WATER, 1))) {
throw new AssertionError("Deserialized ingredient should not match water!");
}
if (!deserialized.test(new FluidStack(Fluids.LAVA, 1))) {
throw new AssertionError("Deserialized ingredient should match lava!");
}
}
}

0 comments on commit 50f5f2a

Please sign in to comment.