diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/DynmapPlugin.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/DynmapPlugin.java index 2588f6f0..fe96ec5d 100644 --- a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/DynmapPlugin.java +++ b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/DynmapPlugin.java @@ -2,8 +2,6 @@ package org.dynmap.fabric_1_18; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; @@ -20,8 +18,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ChunkHolder; -import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.collection.IdList; @@ -46,11 +42,10 @@ import org.dynmap.fabric_1_18.command.DmarkerCommand; import org.dynmap.fabric_1_18.command.DynmapCommand; import org.dynmap.fabric_1_18.command.DynmapExpCommand; import org.dynmap.fabric_1_18.event.BlockEvents; -import org.dynmap.fabric_1_18.event.ChunkDataEvents; +import org.dynmap.fabric_1_18.event.CustomServerChunkEvents; import org.dynmap.fabric_1_18.event.CustomServerLifecycleEvents; import org.dynmap.fabric_1_18.event.PlayerEvents; import org.dynmap.fabric_1_18.mixin.BiomeEffectsAccessor; -import org.dynmap.fabric_1_18.mixin.ThreadedAnvilChunkStorageAccessor; import org.dynmap.fabric_1_18.permissions.FilePermissions; import org.dynmap.fabric_1_18.permissions.OpPermissions; import org.dynmap.fabric_1_18.permissions.PermissionProvider; @@ -126,32 +121,6 @@ public class DynmapPlugin { public static DynmapBlockState[] stateByID; - private Map knownloadedchunks = new HashMap(); - - private void addKnownChunk(FabricWorld fw, ChunkPos pos) { - LongOpenHashSet cset = knownloadedchunks.get(fw.getName()); - if (cset == null) { - cset = new LongOpenHashSet(); - knownloadedchunks.put(fw.getName(), cset); - } - cset.add(pos.toLong()); - } - - private void removeKnownChunk(FabricWorld fw, ChunkPos pos) { - LongOpenHashSet cset = knownloadedchunks.get(fw.getName()); - if (cset != null) { - cset.remove(pos.toLong()); - } - } - - private boolean checkIfKnownChunk(FabricWorld fw, ChunkPos pos) { - LongOpenHashSet cset = knownloadedchunks.get(fw.getName()); - if (cset != null) { - return cset.contains(pos.toLong()); - } - return false; - } - /** * Initialize block states (org.dynmap.blockstate.DynmapBlockState) */ @@ -658,69 +627,25 @@ public class DynmapPlugin { } } - public void handleChunkLoad(ServerWorld world, WorldChunk chunk) { + public void handleChunkGenerate(ServerWorld world, Chunk chunk) { if (!onchunkgenerate) return; - if ((chunk != null) && (chunk.getStatus() == ChunkStatus.FULL)) { - FabricWorld fw = getWorld(world, false); - if (fw != null) { - addKnownChunk(fw, chunk.getPos()); + FabricWorld fw = getWorld(world, false); + ChunkPos chunkPos = chunk.getPos(); + + int yMax = 0; + ChunkSection[] sections = chunk.getSectionArray(); + for (int i = 0; i < sections.length; i++) { + if ((sections[i] != null) && (!sections[i].isEmpty())) { + yMax = 16 * (i + 1); } } - } - - public void handleChunkUnload(ServerWorld world, WorldChunk chunk) { - if (!onchunkgenerate) return; - - if ((chunk != null) && (chunk.getStatus() == ChunkStatus.FULL)) { - FabricWorld fw = getWorld(world, false); - ChunkPos cp = chunk.getPos(); - if (fw != null) { - if (!checkIfKnownChunk(fw, cp)) { - int ymax = 0; - ChunkSection[] sections = chunk.getSectionArray(); - for (int i = 0; i < sections.length; i++) { - if ((sections[i] != null) && (!sections[i].isEmpty())) { - ymax = 16 * (i + 1); - } - } - int x = cp.x << 4; - int z = cp.z << 4; - // If not empty AND not initial scan - if (ymax > 0) { - Log.info("New generated chunk detected at " + cp + " for " + fw.getName()); - mapManager.touchVolume(fw.getName(), x, 0, z, x + 15, ymax, z + 16, "chunkgenerate"); - } - } - removeKnownChunk(fw, cp); - } - } - } - - public void handleChunkDataSave(ServerWorld world, Chunk chunk) { - if (!onchunkgenerate) return; - - if ((chunk != null) && (chunk.getStatus() == ChunkStatus.FULL)) { - FabricWorld fw = getWorld(world, false); - ChunkPos cp = chunk.getPos(); - if (fw != null) { - if (!checkIfKnownChunk(fw, cp)) { - int ymax = 0; - ChunkSection[] sections = chunk.getSectionArray(); - for (int i = 0; i < sections.length; i++) { - if ((sections[i] != null) && (!sections[i].isEmpty())) { - ymax = 16 * (i + 1); - } - } - int x = cp.x << 4; - int z = cp.z << 4; - // If not empty AND not initial scan - if (ymax > 0) { - mapManager.touchVolume(fw.getName(), x, 0, z, x + 15, ymax, z + 16, "chunkgenerate"); - } - addKnownChunk(fw, cp); - } - } + if (yMax > 0) { + mapManager.touchVolume(fw.getName(), + chunkPos.getStartX(), 0, chunkPos.getStartZ(), + chunkPos.getEndX(), yMax, chunkPos.getEndZ(), + "chunkgenerate"); + //Log.info("New generated chunk detected at %s[%s]".formatted(fw.getName(), chunkPos.getStartPos())); } } @@ -755,39 +680,17 @@ public class DynmapPlugin { onblockchange_with_id = core.isTrigger("blockupdate-with-id"); if (onblockchange_with_id) onblockchange = true; - if ((worldTracker == null) && (onblockchange || onchunkpopulate || onchunkgenerate)) { + if (worldTracker == null) worldTracker = new WorldTracker(); - ServerWorldEvents.LOAD.register((server, world) -> worldTracker.handleWorldLoad(server, world)); - ServerWorldEvents.UNLOAD.register((server, world) -> worldTracker.handleWorldUnload(server, world)); - ServerChunkEvents.CHUNK_LOAD.register((world, chunk) -> worldTracker.handleChunkLoad(world, chunk)); - ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> worldTracker.handleChunkUnload(world, chunk)); - ChunkDataEvents.SAVE.register((world, chunk) -> worldTracker.handleChunkDataSave(world, chunk)); + if (onchunkpopulate || onchunkgenerate) { + CustomServerChunkEvents.CHUNK_GENERATE.register((world, chunk) -> worldTracker.handleChunkGenerate(world, chunk)); + } + if (onblockchange) { BlockEvents.BLOCK_EVENT.register((world, pos) -> worldTracker.handleBlockEvent(world, pos)); } - // Prime the known full chunks - if (onchunkgenerate && (server.getWorlds() != null)) { - for (ServerWorld world : server.getWorlds()) { - FabricWorld fw = getWorld(world); - if (fw == null) continue; - ServerChunkManager chunkManager = world.getChunkManager(); - Long2ObjectLinkedOpenHashMap chunks = ((ThreadedAnvilChunkStorageAccessor) chunkManager.threadedAnvilChunkStorage).getChunkHolders(); - for (Map.Entry k : chunks.long2ObjectEntrySet()) { - ChunkHolder ch = k.getValue(); - Chunk c = null; - try { - c = ch.getSavingFuture().getNow(null); - } catch (Exception x) { - } - if (c == null) continue; - ChunkStatus cs = c.getStatus(); - ChunkPos pos = ch.getPos(); - if (cs == ChunkStatus.FULL) { // Cooked? - // Add it as known - addKnownChunk(fw, pos); - } - } - } - } + + ServerWorldEvents.LOAD.register((server, world) -> worldTracker.handleWorldLoad(server, world)); + ServerWorldEvents.UNLOAD.register((server, world) -> worldTracker.handleWorldUnload(server, world)); } FabricWorld getWorldByName(String name) { @@ -890,5 +793,4 @@ public class DynmapPlugin { } } } -} - +} \ No newline at end of file diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/access/ProtoChunkAccessor.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/access/ProtoChunkAccessor.java new file mode 100644 index 00000000..e0408808 --- /dev/null +++ b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/access/ProtoChunkAccessor.java @@ -0,0 +1,5 @@ +package org.dynmap.fabric_1_18.access; + +public interface ProtoChunkAccessor { + boolean getTouchedByWorldGen(); +} diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/event/ChunkDataEvents.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/event/ChunkDataEvents.java deleted file mode 100644 index d50f50b8..00000000 --- a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/event/ChunkDataEvents.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.dynmap.fabric_1_18.event; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.world.chunk.Chunk; - -public class ChunkDataEvents { - private ChunkDataEvents() { - } - - public static Event SAVE = EventFactory.createArrayBacked(Save.class, - (listeners) -> (world, chunk) -> { - for (Save callback : listeners) { - callback.onSave(world, chunk); - } - } - ); - - @FunctionalInterface - public interface Save { - void onSave(ServerWorld world, Chunk chunk); - } -} diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/event/CustomServerChunkEvents.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/event/CustomServerChunkEvents.java new file mode 100644 index 00000000..13e0cf85 --- /dev/null +++ b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/event/CustomServerChunkEvents.java @@ -0,0 +1,21 @@ +package org.dynmap.fabric_1_18.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.chunk.Chunk; + +public class CustomServerChunkEvents { + public static Event CHUNK_GENERATE = EventFactory.createArrayBacked(ChunkGenerate.class, + (listeners) -> (world, chunk) -> { + for (ChunkGenerate callback : listeners) { + callback.onChunkGenerate(world, chunk); + } + } + ); + + @FunctionalInterface + public interface ChunkGenerate { + void onChunkGenerate(ServerWorld world, Chunk chunk); + } +} \ No newline at end of file diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ProtoChunkMixin.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ProtoChunkMixin.java new file mode 100644 index 00000000..60fd0ca3 --- /dev/null +++ b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ProtoChunkMixin.java @@ -0,0 +1,30 @@ +package org.dynmap.fabric_1_18.mixin; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.ProtoChunk; +import org.dynmap.fabric_1_18.access.ProtoChunkAccessor; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ProtoChunk.class) +public class ProtoChunkMixin implements ProtoChunkAccessor { + private boolean touchedByWorldGen = false; + + @Inject( + method = "setBlockState", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/chunk/ChunkSection;setBlockState(IIILnet/minecraft/block/BlockState;)Lnet/minecraft/block/BlockState;" + ) + ) + public void setBlockState(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable info) { + touchedByWorldGen = true; + } + + public boolean getTouchedByWorldGen() { + return touchedByWorldGen; + } +} \ No newline at end of file diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageAccessor.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageAccessor.java deleted file mode 100644 index 3cb7c9c3..00000000 --- a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.dynmap.fabric_1_18.mixin; - -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import net.minecraft.server.world.ChunkHolder; -import net.minecraft.server.world.ThreadedAnvilChunkStorage; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(ThreadedAnvilChunkStorage.class) -public interface ThreadedAnvilChunkStorageAccessor { - @Accessor - Long2ObjectLinkedOpenHashMap getChunkHolders(); -} diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageMixin.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageMixin.java index cecee77d..4f2a8c22 100644 --- a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageMixin.java +++ b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/mixin/ThreadedAnvilChunkStorageMixin.java @@ -1,9 +1,11 @@ package org.dynmap.fabric_1_18.mixin; +import net.minecraft.server.world.ChunkHolder; import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ThreadedAnvilChunkStorage; import net.minecraft.world.chunk.Chunk; -import org.dynmap.fabric_1_18.event.ChunkDataEvents; +import org.dynmap.fabric_1_18.access.ProtoChunkAccessor; +import org.dynmap.fabric_1_18.event.CustomServerChunkEvents; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -11,16 +13,20 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(ThreadedAnvilChunkStorage.class) +@Mixin(value = ThreadedAnvilChunkStorage.class, priority = 666 /* fire before Fabric API CHUNK_LOAD event */) public abstract class ThreadedAnvilChunkStorageMixin { - @Shadow @Final - private ServerWorld world; + @Shadow + ServerWorld world; - @Inject(method = "save(Lnet/minecraft/world/chunk/Chunk;)Z", at = @At("RETURN")) - private void save(Chunk chunk, CallbackInfoReturnable info) { - if (info.getReturnValueZ()) { - ChunkDataEvents.SAVE.invoker().onSave(this.world, chunk); + @Inject( + /* Same place as fabric-lifecycle-events-v1 event CHUNK_LOAD (we will fire before it) */ + method = "method_17227", + at = @At("TAIL") + ) + private void onChunkGenerate(ChunkHolder chunkHolder, Chunk protoChunk, CallbackInfoReturnable callbackInfoReturnable) { + if (((ProtoChunkAccessor)protoChunk).getTouchedByWorldGen()) { + CustomServerChunkEvents.CHUNK_GENERATE.invoker().onChunkGenerate(this.world, callbackInfoReturnable.getReturnValue()); } } -} +} \ No newline at end of file diff --git a/fabric-1.18/src/main/resources/configuration.txt b/fabric-1.18/src/main/resources/configuration.txt index ea7f54a4..5d5b44a9 100644 --- a/fabric-1.18/src/main/resources/configuration.txt +++ b/fabric-1.18/src/main/resources/configuration.txt @@ -301,8 +301,6 @@ compass-mode: newnorth render-triggers: - blockupdate #- blockupdate-with-id - #- lightingupdate - - chunkpopulate - chunkgenerate #- none diff --git a/fabric-1.18/src/main/resources/dynmap.mixins.json b/fabric-1.18/src/main/resources/dynmap.mixins.json index 9e8d2f97..1b99931d 100644 --- a/fabric-1.18/src/main/resources/dynmap.mixins.json +++ b/fabric-1.18/src/main/resources/dynmap.mixins.json @@ -7,9 +7,9 @@ "BiomeEffectsAccessor", "MinecraftServerMixin", "PlayerManagerMixin", + "ProtoChunkMixin", "ServerPlayerEntityMixin", "ServerPlayNetworkHandlerMixin", - "ThreadedAnvilChunkStorageAccessor", "ThreadedAnvilChunkStorageMixin", "WorldChunkMixin" ],