refactor: update structure handling and context management in dungeon generation

This commit is contained in:
Chipperfluff 2025-12-19 01:01:33 +01:00
parent dbaf8a6c0f
commit 8b2ebafe56
5 changed files with 176 additions and 87 deletions

View File

@ -16,26 +16,37 @@ import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications; import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors; import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.structure.StructurePlacementData; import net.minecraft.structure.StructurePlacementData;
import net.minecraft.structure.StructureTemplate; import net.minecraft.structure.StructureTemplate;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.gen.GenerationStep; import net.minecraft.world.gen.GenerationStep;
public class ChipiMod implements ModInitializer { public class ChipiMod implements ModInitializer {
public static final String MOD_ID = "chipi"; public static final String MOD_ID = "chipi";
private static final Identifier CHIPI_DIM = new Identifier("chipi", "chipi_dimension"); public static final RegistryKey<World> CHIPI_DIMENSION_KEY =
RegistryKey.of(
RegistryKeys.WORLD,
new Identifier("chipi", "chipi_dimension")
);
private static final Identifier SPAWN_STRUCTURE = new Identifier("chipi", "spawn"); private static final Identifier SPAWN_STRUCTURE =
new Identifier("chipi", "spawn");
private static MinecraftServer SERVER;
@Override @Override
public void onInitialize() { public void onInitialize() {
@ -49,43 +60,64 @@ public class ChipiMod implements ModInitializer {
ChipiBlessingEvents.register(); ChipiBlessingEvents.register();
ChipiHungerHandler.register(); ChipiHungerHandler.register();
FabricDefaultAttributeRegistry.register(ModEntities.MEP, MepEntity.createMepAttributes()); FabricDefaultAttributeRegistry.register(
ModEntities.MEP,
MepEntity.createMepAttributes()
);
BiomeModifications.addFeature( BiomeModifications.addFeature(
BiomeSelectors.foundInOverworld(), BiomeSelectors.foundInOverworld(),
GenerationStep.Feature.UNDERGROUND_ORES, GenerationStep.Feature.UNDERGROUND_ORES,
RegistryKey.of( RegistryKey.of(
RegistryKeys.PLACED_FEATURE, new Identifier("chipi", "chipper_ore"))); RegistryKeys.PLACED_FEATURE,
new Identifier("chipi", "chipper_ore")
)
);
CommandRegistrationCallback.EVENT.register( CommandRegistrationCallback.EVENT.register(
(dispatcher, registryAccess, environment) -> ChpCommand.register(dispatcher)); (dispatcher, registryAccess, environment) -> {
ChpCommand.register(dispatcher);
}
);
ServerTickEvents.END_WORLD_TICK.register( ServerLifecycleEvents.SERVER_STARTED.register(server -> {
world -> { SERVER = server;
if (!world.getRegistryKey().getValue().equals(CHIPI_DIM)) return; });
ServerTickEvents.END_WORLD_TICK.register(world -> {
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) {
return;
}
for (PlayerEntity player : world.getPlayers()) { for (PlayerEntity player : world.getPlayers()) {
if (player.getBlockY() >= 50) continue; if (player.getBlockY() >= 50) {
continue;
}
ChipperPortalBlock.teleportToChipiSpawn(world, player); ChipperPortalBlock.teleportToChipiSpawn(world, player);
} }
}); });
ServerWorldEvents.LOAD.register( ServerWorldEvents.LOAD.register((server, world) -> {
(server, world) -> { if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) {
if (!world.getRegistryKey().getValue().equals(CHIPI_DIM)) return; return;
}
world.setTimeOfDay(18000); world.setTimeOfDay(18000);
world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(false, server); world.getGameRules()
.get(GameRules.DO_DAYLIGHT_CYCLE)
.set(false, server);
SpawnPlacedState state = SpawnPlacedState state =
world.getPersistentStateManager() world.getPersistentStateManager().getOrCreate(
.getOrCreate(
SpawnPlacedState::fromNbt, SpawnPlacedState::fromNbt,
SpawnPlacedState::new, SpawnPlacedState::new,
"chipi_spawn"); "chipi_spawn"
);
if (state.placed) return; if (state.placed) {
return;
}
StructureTemplate spawnTemplate = StructureTemplate spawnTemplate =
world.getStructureTemplateManager() world.getStructureTemplateManager()
@ -105,7 +137,8 @@ public class ChipiMod implements ModInitializer {
spawnCenter, spawnCenter,
new StructurePlacementData(), new StructurePlacementData(),
world.getRandom(), world.getRandom(),
2); 2
);
world.setSpawnPos(spawnCenter.up(), 0.0f); world.setSpawnPos(spawnCenter.up(), 0.0f);
@ -117,4 +150,12 @@ public class ChipiMod implements ModInitializer {
System.out.println("[CHIPI] Spawn + initial dungeon generated"); System.out.println("[CHIPI] Spawn + initial dungeon generated");
}); });
} }
public static ServerWorld getChipiWorld() {
if (SERVER == null) {
return null;
}
return SERVER.getWorld(CHIPI_DIMENSION_KEY);
}
} }

View File

@ -71,9 +71,9 @@ public class ChipiDungeonGenerator {
ROOM_Y, ROOM_Y,
firstGeneratedRoomCenter.getZ() + (row * STEP_Z)); firstGeneratedRoomCenter.getZ() + (row * STEP_Z));
RoomBaseStructure room = WorldMaster.resolveRoom(ctx(gridX, gridY, center, null)); RoomBaseStructure room = WorldMaster.resolveRoom(ctx(world, gridX, gridY, center, null));
room.placeAt(world, center); room.placeAt(world, center);
WorldMaster.afterPlaceRoom(ctx(gridX, gridY, center, room)); WorldMaster.afterPlaceRoom(ctx(world, gridX, gridY, center, room));
} }
} }
@ -97,9 +97,9 @@ public class ChipiDungeonGenerator {
currentCenter.getZ() + ROOM_EXTENT_SOUTH); currentCenter.getZ() + ROOM_EXTENT_SOUTH);
CorridorNSStructure corridorNS = CorridorNSStructure corridorNS =
WorldMaster.resolveCorridorNS(ctx(gridX, gridY, anchorSouth, null)); WorldMaster.resolveCorridorNS(ctx(world, gridX, gridY, anchorSouth, null));
corridorNS.placeAt(world, anchorSouth); corridorNS.placeAt(world, anchorSouth);
WorldMaster.afterPlaceCorridorNS(ctx(gridX, gridY, anchorSouth, corridorNS)); WorldMaster.afterPlaceCorridorNS(ctx(world, gridX, gridY, anchorSouth, corridorNS));
} }
} }
@ -122,9 +122,9 @@ public class ChipiDungeonGenerator {
currentCenter.getZ()); currentCenter.getZ());
CorridorEWStructure corridorEW = CorridorEWStructure corridorEW =
WorldMaster.resolveCorridorEW(ctx(gridX, gridY, anchorEast, null)); WorldMaster.resolveCorridorEW(ctx(world, gridX, gridY, anchorEast, null));
corridorEW.placeAt(world, anchorEast); corridorEW.placeAt(world, anchorEast);
WorldMaster.afterPlaceCorridorEW(ctx(gridX, gridY, anchorEast, corridorEW)); WorldMaster.afterPlaceCorridorEW(ctx(world, gridX, gridY, anchorEast, corridorEW));
} }
} }
@ -188,7 +188,7 @@ public class ChipiDungeonGenerator {
} }
private static DungeonContext ctx( private static DungeonContext ctx(
int gridX, int gridY, BlockPos origin, ChipiStructure structure) { ServerWorld world, int gridX, int gridY, BlockPos origin, ChipiStructure structure) {
return DungeonContext.of(gridX, gridY, origin, structure); return DungeonContext.of(world, gridX, gridY, origin, structure);
} }
} }

View File

@ -1,5 +1,7 @@
package net.Chipperfluff.chipi.world.gen; package net.Chipperfluff.chipi.world.gen;
import java.util.Optional;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.entity.StructureBlockBlockEntity; import net.minecraft.block.entity.StructureBlockBlockEntity;
import net.minecraft.block.enums.StructureBlockMode; import net.minecraft.block.enums.StructureBlockMode;
@ -10,15 +12,10 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.Vec3i;
import java.util.Optional;
public abstract class ChipiStructure { public abstract class ChipiStructure {
protected final Identifier id; protected final Identifier id;
/** Offset from STRUCTURE BLOCK → actual structure origin */
protected final int deltaX; protected final int deltaX;
protected final int deltaY; protected final int deltaY;
protected final int deltaZ; protected final int deltaZ;
@ -29,41 +26,30 @@ public abstract class ChipiStructure {
this.deltaZ = deltaZ; this.deltaZ = deltaZ;
} }
/** REAL size from NBT */
public BlockPos getSize(ServerWorld world) { public BlockPos getSize(ServerWorld world) {
Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id); Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id);
if (opt.isEmpty()) return BlockPos.ORIGIN; if (opt.isEmpty()) return BlockPos.ORIGIN;
Vec3i size = opt.get().getSize(); Vec3i size = opt.get().getSize();
return new BlockPos(size.getX(), size.getY(), size.getZ()); return new BlockPos(size.getX(), size.getY(), size.getZ());
} }
/** Pure structure placement */
public void placeAt(ServerWorld world, BlockPos centerPos) { public void placeAt(ServerWorld world, BlockPos centerPos) {
Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id); Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id);
if (opt.isEmpty()) { if (opt.isEmpty()) {
System.out.println("[CHIPI] Missing structure: " + id); System.out.println("[CHIPI] Missing structure: " + id);
return; return;
} }
BlockPos origin = centerPos.add(new BlockPos(deltaX, deltaY, deltaZ)); BlockPos origin = centerPos.add(deltaX, deltaY, deltaZ);
opt.get().place(world, origin, origin, new StructurePlacementData(), world.getRandom(), 2);
StructureTemplate template = opt.get();
template.place(world, origin, origin, new StructurePlacementData(), world.getRandom(), 2);
} }
/** Command placement (structure + optional marker) */
public void placeCommand(ServerWorld world, BlockPos placePos, boolean marker) { public void placeCommand(ServerWorld world, BlockPos placePos, boolean marker) {
placeAt(world, placePos); placeAt(world, placePos);
BlockPos origin = placePos.add(new BlockPos(deltaX, deltaY, deltaZ));
if (!marker) return; if (!marker) return;
BlockPos origin = placePos.add(deltaX, deltaY, deltaZ);
world.setBlockState(origin, Blocks.STRUCTURE_BLOCK.getDefaultState(), 3); world.setBlockState(origin, Blocks.STRUCTURE_BLOCK.getDefaultState(), 3);
if (world.getBlockEntity(origin) instanceof StructureBlockBlockEntity be) { if (world.getBlockEntity(origin) instanceof StructureBlockBlockEntity be) {
@ -76,4 +62,48 @@ public abstract class ChipiStructure {
be.markDirty(); be.markDirty();
} }
} }
public BlockPos local(BlockPos centerPos, BlockPos localPos) {
return centerPos.add(deltaX + localPos.getX(), deltaY + localPos.getY(), deltaZ + localPos.getZ());
}
public void setBlock(
ServerWorld world,
BlockPos centerPos,
BlockPos localPos,
BlockState state,
Integer gridX,
Integer gridY) {
BlockPos worldPos = local(centerPos, localPos);
System.out.println(
"[CHIPI] setBlock grid=("
+ gridX
+ ","
+ gridY
+ ") worldPos="
+ worldPos);
world.setBlockState(worldPos, state, 3);
}
public void fillBlocks(
ServerWorld world,
BlockPos centerPos,
BlockPos from,
BlockPos to,
BlockState state,
Integer gridX,
Integer gridY) {
BlockPos start = local(centerPos, from);
BlockPos end = local(centerPos, to);
System.out.println(
"[CHIPI] fillBlocks grid=("
+ gridX
+ ","
+ gridY
+ ") from="
+ start
+ " to="
+ end);
BlockPos.stream(start, end).forEach(pos -> world.setBlockState(pos, state, 3));
}
} }

View File

@ -1,28 +1,34 @@
package net.Chipperfluff.chipi.world.gen; package net.Chipperfluff.chipi.world.gen;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
public final class DungeonContext { public final class DungeonContext {
public static final DungeonContext EMPTY = new DungeonContext(); public static final DungeonContext EMPTY = new DungeonContext();
private Integer grid_x = null; private Integer grid_x;
private Integer grid_y = null; private Integer grid_y;
private BlockPos structure_origin = null; private BlockPos structure_origin;
private ChipiStructure structure = null; private ChipiStructure structure;
private ServerWorld world;
private DungeonContext() {} private DungeonContext() {}
private DungeonContext( private DungeonContext(ServerWorld world, Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) {
Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) { this.world = world;
this.grid_x = grid_x; this.grid_x = grid_x;
this.grid_y = grid_y; this.grid_y = grid_y;
this.structure_origin = structure_origin; this.structure_origin = structure_origin;
this.structure = structure; this.structure = structure;
} }
public static DungeonContext of( public static DungeonContext of(ServerWorld world, Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) {
Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) { return new DungeonContext(world, grid_x, grid_y, structure_origin, structure);
return new DungeonContext(grid_x, grid_y, structure_origin, structure); }
public ServerWorld getWorld() {
return world;
} }
public Integer getGridX() { public Integer getGridX() {

View File

@ -3,6 +3,8 @@ package net.Chipperfluff.chipi.world.gen;
import net.Chipperfluff.chipi.world.gen.struct.CorridorEWStructure; import net.Chipperfluff.chipi.world.gen.struct.CorridorEWStructure;
import net.Chipperfluff.chipi.world.gen.struct.CorridorNSStructure; import net.Chipperfluff.chipi.world.gen.struct.CorridorNSStructure;
import net.Chipperfluff.chipi.world.gen.struct.RoomBaseStructure; import net.Chipperfluff.chipi.world.gen.struct.RoomBaseStructure;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
public final class WorldMaster { public final class WorldMaster {
@ -21,7 +23,6 @@ public final class WorldMaster {
} }
public static RoomBaseStructure resolveRoom(DungeonContext ctx) { public static RoomBaseStructure resolveRoom(DungeonContext ctx) {
return getDefaultRoom(); return getDefaultRoom();
} }
@ -35,6 +36,17 @@ public final class WorldMaster {
public static RoomBaseStructure afterPlaceRoom(DungeonContext ctx) { public static RoomBaseStructure afterPlaceRoom(DungeonContext ctx) {
if (ctx.getGridX() == 1 && ctx.getGridY() == 1) {
ctx.getStructure().setBlock(
ctx.getWorld(),
ctx.getStructureOrigin(),
new BlockPos(0, 0, 0),
Blocks.REDSTONE_BLOCK.getDefaultState(),
ctx.getGridX(),
ctx.getGridY()
);
}
return getDefaultRoom(); return getDefaultRoom();
} }