Skip to content

Commit ea9be10

Browse files
committed
new: implements FabricMC/fabric#4610
1 parent 2407963 commit ea9be10

File tree

8 files changed

+135
-6
lines changed

8 files changed

+135
-6
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.ishland.c2me.base.common.config;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
public class LateModStatuses {
7+
8+
private static final Logger LOGGER = LoggerFactory.getLogger(ModStatuses.class);
9+
public static final boolean fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE = isAvailable0_fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE();
10+
11+
private static boolean isAvailable0_fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE() {
12+
if (!ModStatuses.fabric_lifecycle_events_v1) {
13+
LOGGER.info("Fabric Lifecycle Events (v1) not found, skipping compat");
14+
return false;
15+
}
16+
Class<?> clazzServerChunkEvents;
17+
try {
18+
clazzServerChunkEvents = Class.forName("net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents");
19+
} catch (ClassNotFoundException e) {
20+
LOGGER.warn("net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents not found, but fabric-loader claims fabric-lifecycle-events-v1 is present, outdated fabric-api?", e);
21+
return false;
22+
}
23+
try {
24+
clazzServerChunkEvents.getField("CHUNK_LEVEL_TYPE_CHANGE");
25+
} catch (NoSuchFieldException e) {
26+
LOGGER.warn("Lnet/fabricmc/fabric/api/event/lifecycle/v1/ServerChunkEvents;CHUNK_LEVEL_TYPE_CHANGE:Lnet/fabricmc/fabric/api/event/Event; not found, outdated fabric-api?", e);
27+
return false;
28+
}
29+
30+
return true;
31+
}
32+
33+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.ishland.c2me.base.mixin.access.fapi;
2+
3+
import org.spongepowered.asm.mixin.Mixin;
4+
import org.spongepowered.asm.mixin.gen.Accessor;
5+
6+
@Mixin(targets = "net.fabricmc.fabric.impl.base.event.ArrayBackedEvent", remap = false)
7+
public interface IArrayBackedEvent<T> {
8+
9+
@Accessor("handlers")
10+
T[] c2me$getHandlers();
11+
12+
}

c2me-base/src/main/resources/c2me-base.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"access.IXoroshiro128PlusPlusRandomDeriver",
5454
"access.IXoroshiro128PlusPlusRandomImpl",
5555
"priority.MixinServerChunkManager",
56+
"access.fapi.IArrayBackedEvent",
5657
"scheduler.MixinThreadedAnvilChunkStorage",
5758
"theinterface.MixinStorageIoWorker",
5859
"util.log4j2shutdownhookisnomore.MixinMain",

c2me-rewrites-chunk-system/src/main/java/com/ishland/c2me/rewrites/chunksystem/common/fapi/LifecycleEventInvoker.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,65 @@
11
package com.ishland.c2me.rewrites.chunksystem.common.fapi;
22

3+
import com.ishland.c2me.base.mixin.access.fapi.IArrayBackedEvent;
34
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
5+
import net.minecraft.server.world.ChunkLevelType;
46
import net.minecraft.server.world.ServerWorld;
57
import net.minecraft.world.chunk.WorldChunk;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
610

711
public class LifecycleEventInvoker {
812

13+
private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleEventInvoker.class);
14+
915
public static void invokeChunkLoaded(ServerWorld world, WorldChunk chunk, boolean newChunk) {
1016
try {
1117
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(world, chunk);
1218
if (newChunk) {
1319
ServerChunkEvents.CHUNK_GENERATE.invoker().onChunkGenerate(world, chunk);
1420
}
1521
} catch (Throwable t) {
16-
t.printStackTrace();
22+
LOGGER.error("Failed to invoke chunk load event (world={}, pos={}, newChunk={})", world, chunk.getPos(), newChunk, t);
1723
}
1824
}
1925

2026
public static void invokeChunkUnload(ServerWorld world, WorldChunk chunk) {
2127
try {
2228
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(world, chunk);
2329
} catch (Throwable t) {
24-
t.printStackTrace();
30+
LOGGER.error("Failed to invoke chunk unload event (world={}, pos={})", world, chunk.getPos(), t);
31+
}
32+
}
33+
34+
private static boolean cachedNeedsInvokeChunkLevelTypeChange = false;
35+
36+
public static boolean needsInvokeChunkLevelTypeChange() {
37+
if (cachedNeedsInvokeChunkLevelTypeChange) return true;
38+
try {
39+
if (ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE instanceof IArrayBackedEvent<?> accessor0) {
40+
IArrayBackedEvent<ServerChunkEvents.LevelTypeChange> accessor = (IArrayBackedEvent<ServerChunkEvents.LevelTypeChange>) accessor0;
41+
if (accessor.c2me$getHandlers().length > 0) {
42+
cachedNeedsInvokeChunkLevelTypeChange = true;
43+
return true;
44+
}
45+
} else {
46+
LOGGER.warn("Unexpected Event implementation of ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE: {}", ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE.getClass().getName());
47+
cachedNeedsInvokeChunkLevelTypeChange = true;
48+
return true;
49+
}
50+
return false;
51+
} catch (Throwable t) {
52+
LOGGER.error("Failed to check if chunk level type change event is needed", t);
53+
cachedNeedsInvokeChunkLevelTypeChange = true;
54+
return true;
55+
}
56+
}
57+
58+
public static void invokeChunkLevelTypeChange(ServerWorld world, WorldChunk chunk, ChunkLevelType oldLevelType, ChunkLevelType newLevelType) {
59+
try {
60+
ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE.invoker().onChunkLevelTypeChange(world, chunk, oldLevelType, newLevelType);
61+
} catch (Throwable t) {
62+
LOGGER.error("Failed to invoke chunk level type change event (world={}, pos={}, oldLevelType={}, newLevelType={})", world, chunk.getPos(), oldLevelType, newLevelType, t);
2563
}
2664
}
2765

c2me-rewrites-chunk-system/src/main/java/com/ishland/c2me/rewrites/chunksystem/common/statuses/ServerAccessible.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.ishland.c2me.rewrites.chunksystem.common.statuses;
22

33
import com.google.common.base.Preconditions;
4+
import com.ishland.c2me.base.common.config.LateModStatuses;
45
import com.ishland.c2me.base.common.config.ModStatuses;
56
import com.ishland.c2me.base.mixin.access.IThreadedAnvilChunkStorage;
67
import com.ishland.c2me.base.mixin.access.IWorldChunk;
@@ -22,6 +23,7 @@
2223
import net.minecraft.nbt.NbtCompound;
2324
import net.minecraft.server.world.ChunkLevels;
2425
import net.minecraft.server.world.ServerChunkLoadingManager;
26+
import net.minecraft.server.world.ChunkLevelType;
2527
import net.minecraft.server.world.ServerWorld;
2628
import net.minecraft.util.math.BlockPos;
2729
import net.minecraft.util.math.ChunkPos;
@@ -105,7 +107,9 @@ public CompletionStage<Void> upgradeToThis(ChunkLoadingContext context, Cancella
105107
}
106108
}
107109

108-
((IThreadedAnvilChunkStorage) context.tacs()).getCurrentChunkHolders().put(context.holder().getKey().toLong(), context.holder().getUserData().get());
110+
if (LateModStatuses.fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE) {
111+
LifecycleEventInvoker.invokeChunkLevelTypeChange(serverWorld, worldChunk, ChunkLevelType.INACCESSIBLE, ChunkLevelType.FULL);
112+
}((IThreadedAnvilChunkStorage) context.tacs()).getCurrentChunkHolders().put(context.holder().getKey().toLong(), context.holder().getUserData().get());
109113
((IThreadedAnvilChunkStorage) context.tacs()).setChunkHolderListDirty(true);
110114

111115
if (needSendChunks()) {
@@ -154,10 +158,16 @@ public CompletionStage<Void> downgradeFromThis(ChunkLoadingContext context, Canc
154158
((IThreadedAnvilChunkStorage) context.tacs()).getCurrentChunkHolders().remove(context.holder().getKey().toLong());
155159
((IThreadedAnvilChunkStorage) context.tacs()).setChunkHolderListDirty(true);
156160
final WorldChunk worldChunk = (WorldChunk) chunk;
161+
ServerWorld serverWorld = ((IThreadedAnvilChunkStorage) context.tacs()).getWorld();
157162
// worldChunk.setLoadedToWorld(false);
158163
// worldChunk.removeChunkTickSchedulers(((IThreadedAnvilChunkStorage) context.tacs()).getWorld());
159-
worldChunk.setLevelTypeProvider(null);
164+
165+
if (LateModStatuses.fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE) {
166+
LifecycleEventInvoker.invokeChunkLevelTypeChange(serverWorld, worldChunk, ChunkLevelType.FULL, ChunkLevelType.INACCESSIBLE);
167+
}
160168
LithiumChunkStatusTrackerInvoker.invokeOnChunkInaccessible(((IThreadedAnvilChunkStorage) context.tacs()).getWorld(), context.holder().getKey());
169+
170+
worldChunk.setLevelTypeProvider(null);
161171
context.holder().getItem().set(new ChunkState(state.protoChunk(), state.protoChunk(), ChunkStatus.FULL));
162172
}, ((IThreadedAnvilChunkStorage) context.tacs()).getMainThreadExecutor());
163173
}

c2me-rewrites-chunk-system/src/main/java/com/ishland/c2me/rewrites/chunksystem/common/statuses/ServerBlockTicking.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.ishland.c2me.rewrites.chunksystem.common.statuses;
22

3+
import com.ishland.c2me.base.common.config.LateModStatuses;
34
import com.ishland.c2me.base.mixin.access.IThreadedAnvilChunkStorage;
45
import com.ishland.c2me.rewrites.chunksystem.common.ChunkLoadingContext;
56
import com.ishland.c2me.rewrites.chunksystem.common.ChunkState;
67
import com.ishland.c2me.rewrites.chunksystem.common.NewChunkStatus;
8+
import com.ishland.c2me.rewrites.chunksystem.common.fapi.LifecycleEventInvoker;
79
import com.ishland.flowsched.scheduler.Cancellable;
810
import com.ishland.flowsched.scheduler.ItemHolder;
911
import com.ishland.flowsched.scheduler.KeyStatusPair;
12+
import net.minecraft.server.world.ChunkLevelType;
13+
import net.minecraft.server.world.ServerWorld;
1014
import net.minecraft.util.math.ChunkPos;
1115
import net.minecraft.world.chunk.ChunkStatus;
1216
import net.minecraft.world.chunk.WorldChunk;
@@ -40,9 +44,13 @@ public CompletionStage<Void> upgradeToThis(ChunkLoadingContext context, Cancella
4044
return CompletableFuture.runAsync(() -> {
4145
final WorldChunk chunk = (WorldChunk) context.holder().getItem().get().chunk();
4246
chunk.runPostProcessing();
43-
((IThreadedAnvilChunkStorage) context.tacs()).getWorld().disableTickSchedulers(chunk);
47+
ServerWorld serverWorld = ((IThreadedAnvilChunkStorage) context.tacs()).getWorld();
48+
serverWorld.disableTickSchedulers(chunk);
4449
sendChunkToPlayer(context);
4550
((IThreadedAnvilChunkStorage) context.tacs()).getTotalChunksLoadedCount().incrementAndGet(); // never decremented in vanilla
51+
if (LateModStatuses.fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE) {
52+
LifecycleEventInvoker.invokeChunkLevelTypeChange(serverWorld, chunk, ChunkLevelType.FULL, ChunkLevelType.BLOCK_TICKING);
53+
}
4654
}, ((IThreadedAnvilChunkStorage) context.tacs()).getMainThreadExecutor());
4755
}
4856

@@ -58,6 +66,13 @@ private static void sendChunkToPlayer(ChunkLoadingContext context) {
5866

5967
@Override
6068
public CompletionStage<Void> downgradeFromThis(ChunkLoadingContext context, Cancellable cancellable) {
69+
ServerWorld serverWorld = ((IThreadedAnvilChunkStorage) context.tacs()).getWorld();
70+
final WorldChunk chunk = (WorldChunk) context.holder().getItem().get().chunk();
71+
if (LateModStatuses.fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE && LifecycleEventInvoker.needsInvokeChunkLevelTypeChange()) {
72+
return CompletableFuture.runAsync(() -> {
73+
LifecycleEventInvoker.invokeChunkLevelTypeChange(serverWorld, chunk, ChunkLevelType.BLOCK_TICKING, ChunkLevelType.FULL);
74+
}, ((IThreadedAnvilChunkStorage) context.tacs()).getMainThreadExecutor());
75+
}
6176
return CompletableFuture.completedStage(null);
6277
}
6378

c2me-rewrites-chunk-system/src/main/java/com/ishland/c2me/rewrites/chunksystem/common/statuses/ServerEntityTicking.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package com.ishland.c2me.rewrites.chunksystem.common.statuses;
22

3+
import com.ishland.c2me.base.common.config.LateModStatuses;
4+
import com.ishland.c2me.base.mixin.access.IThreadedAnvilChunkStorage;
35
import com.ishland.c2me.rewrites.chunksystem.common.ChunkLoadingContext;
46
import com.ishland.c2me.rewrites.chunksystem.common.ChunkState;
57
import com.ishland.c2me.rewrites.chunksystem.common.NewChunkStatus;
8+
import com.ishland.c2me.rewrites.chunksystem.common.fapi.LifecycleEventInvoker;
69
import com.ishland.flowsched.scheduler.Cancellable;
710
import com.ishland.flowsched.scheduler.ItemHolder;
811
import com.ishland.flowsched.scheduler.KeyStatusPair;
12+
import net.minecraft.server.world.ChunkLevelType;
13+
import net.minecraft.server.world.ServerWorld;
914
import net.minecraft.util.math.ChunkPos;
1015
import net.minecraft.world.chunk.ChunkStatus;
16+
import net.minecraft.world.chunk.WorldChunk;
1117

1218
import java.util.concurrent.CompletableFuture;
1319
import java.util.concurrent.CompletionStage;
@@ -35,11 +41,25 @@ public ServerEntityTicking(int ordinal) {
3541

3642
@Override
3743
public CompletionStage<Void> upgradeToThis(ChunkLoadingContext context, Cancellable cancellable) {
44+
if (LateModStatuses.fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE && LifecycleEventInvoker.needsInvokeChunkLevelTypeChange()) {
45+
return CompletableFuture.runAsync(() -> {
46+
ServerWorld serverWorld = ((IThreadedAnvilChunkStorage) context.tacs()).getWorld();
47+
final WorldChunk chunk = (WorldChunk) context.holder().getItem().get().chunk();
48+
LifecycleEventInvoker.invokeChunkLevelTypeChange(serverWorld, chunk, ChunkLevelType.BLOCK_TICKING, ChunkLevelType.ENTITY_TICKING);
49+
}, ((IThreadedAnvilChunkStorage) context.tacs()).getMainThreadExecutor());
50+
}
3851
return CompletableFuture.completedStage(null);
3952
}
4053

4154
@Override
4255
public CompletionStage<Void> downgradeFromThis(ChunkLoadingContext context, Cancellable cancellable) {
56+
if (LateModStatuses.fabric_lifecycle_events_v1_CHUNK_LEVEL_TYPE_CHANGE && LifecycleEventInvoker.needsInvokeChunkLevelTypeChange()) {
57+
return CompletableFuture.runAsync(() -> {
58+
ServerWorld serverWorld = ((IThreadedAnvilChunkStorage) context.tacs()).getWorld();
59+
final WorldChunk chunk = (WorldChunk) context.holder().getItem().get().chunk();
60+
LifecycleEventInvoker.invokeChunkLevelTypeChange(serverWorld, chunk, ChunkLevelType.ENTITY_TICKING, ChunkLevelType.BLOCK_TICKING);
61+
}, ((IThreadedAnvilChunkStorage) context.tacs()).getMainThreadExecutor());
62+
}
4363
return CompletableFuture.completedStage(null);
4464
}
4565

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fabric.loom.multiProjectOptimisation=true
88
minecraft_version=1.21.1
99
yarn_mappings=1.21.1+build.1
1010
loader_version=0.16.3
11-
fabric_version=0.107.0+1.21.1
11+
fabric_version=0.116.0+1.21.1
1212
# Mod Properties
1313
mod_version=0.3.0+alpha.0
1414
maven_group=com.ishland.c2me

0 commit comments

Comments
 (0)