diff --git a/src/main/java/com/livingworld/LivingWorldMod.java b/src/main/java/com/livingworld/LivingWorldMod.java index 2bb6885..12fe0c0 100644 --- a/src/main/java/com/livingworld/LivingWorldMod.java +++ b/src/main/java/com/livingworld/LivingWorldMod.java @@ -14,6 +14,8 @@ import com.livingworld.core.LivingWorldConstants; import com.livingworld.debug.DiagnosticCategory; import com.livingworld.debug.LivingWorldLogger; import com.livingworld.platform.neoforge.NeoForgePlatformAdapter; +import com.livingworld.platform.neoforge.NeoForgeWorldEffectExecutor; +import net.minecraft.server.MinecraftServer; /** * Mod entrypoint for Living World. @@ -26,6 +28,7 @@ public class LivingWorldMod { public static final String MOD_ID = LivingWorldConstants.MOD_ID; private final LivingWorldBootstrap bootstrap; + private MinecraftServer minecraftServer; public LivingWorldMod(IEventBus eventBus) { LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "Living World mod starting..."); @@ -43,10 +46,16 @@ public class LivingWorldMod { ServerStartingEvent.class, event -> bootstrap.onServerStarting( event.getServer().getWorldPath(LevelResource.ROOT))); - NeoForge.EVENT_BUS.addListener( - ServerStartedEvent.class, event -> bootstrap.onServerStarted()); - NeoForge.EVENT_BUS.addListener( - ServerStoppingEvent.class, event -> bootstrap.onServerStopping()); + NeoForge.EVENT_BUS.addListener(ServerStartedEvent.class, event -> { + this.minecraftServer = event.getServer(); + bootstrap.onServerStarted(); + bootstrap.getWorldEffectsModule().registerConsumer( + new NeoForgeWorldEffectExecutor(() -> minecraftServer)); + }); + NeoForge.EVENT_BUS.addListener(ServerStoppingEvent.class, event -> { + bootstrap.onServerStopping(); + this.minecraftServer = null; + }); LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "Living World Bootstrap initialized successfully."); } diff --git a/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java b/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java index caaba28..45fc9df 100644 --- a/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java +++ b/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java @@ -125,16 +125,6 @@ public final class LivingWorldBootstrap { requireServerReady(); ServerContext context = new ServerContext(); moduleRegistry.getEnabledModules().forEach(module -> module.onServerStarted(context)); - - // Register the world-effects consumer now that services are live. - // Logs what would be applied; actual block manipulation is Track C. - worldEffectsModule.registerConsumer(request -> - LivingWorldLogger.info( - DiagnosticCategory.SIMULATION, - "WorldEffect: " + request.type() - + " region=" + request.region() - + " intensity=" + String.format("%.2f", request.intensity()))); - LivingWorldLogger.info( DiagnosticCategory.BOOTSTRAP, "onServerStarted - server started."); diff --git a/src/main/java/com/livingworld/platform/neoforge/NeoForgeWorldEffectExecutor.java b/src/main/java/com/livingworld/platform/neoforge/NeoForgeWorldEffectExecutor.java new file mode 100644 index 0000000..1f729c8 --- /dev/null +++ b/src/main/java/com/livingworld/platform/neoforge/NeoForgeWorldEffectExecutor.java @@ -0,0 +1,122 @@ +package com.livingworld.platform.neoforge; + +import com.livingworld.core.LivingWorldConstants; +import com.livingworld.debug.DiagnosticCategory; +import com.livingworld.debug.LivingWorldLogger; +import com.livingworld.modules.worldeffects.WorldEffectConsumer; +import com.livingworld.modules.worldeffects.WorldEffectRequest; +import java.util.Random; +import java.util.function.Supplier; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.levelgen.Heightmap; + +/** + * Translates {@link WorldEffectRequest}s from the ecosystem simulation into + * concrete Minecraft block operations and particle effects. + * + *
Called on the server tick thread. Block writes are guarded by a + * {@link ServerLevel#isLoaded} check to avoid force-loading chunks.
+ */ +public final class NeoForgeWorldEffectExecutor implements WorldEffectConsumer { + + private static final int REGION_BLOCKS = + LivingWorldConstants.DEFAULT_REGION_SIZE_CHUNKS * 16; + private static final int BLOCK_ATTEMPTS = 8; + private static final int MIN_GRASS_LIGHT = 9; + + private final Supplier