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.BiomeSelectors;
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.ServerWorldEvents;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.registry.RegistryKey;
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.StructureTemplate;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.gen.GenerationStep;
public class ChipiMod implements ModInitializer {
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
public void onInitialize() {
@ -49,43 +60,64 @@ public class ChipiMod implements ModInitializer {
ChipiBlessingEvents.register();
ChipiHungerHandler.register();
FabricDefaultAttributeRegistry.register(ModEntities.MEP, MepEntity.createMepAttributes());
FabricDefaultAttributeRegistry.register(
ModEntities.MEP,
MepEntity.createMepAttributes()
);
BiomeModifications.addFeature(
BiomeSelectors.foundInOverworld(),
GenerationStep.Feature.UNDERGROUND_ORES,
RegistryKey.of(
RegistryKeys.PLACED_FEATURE, new Identifier("chipi", "chipper_ore")));
RegistryKeys.PLACED_FEATURE,
new Identifier("chipi", "chipper_ore")
)
);
CommandRegistrationCallback.EVENT.register(
(dispatcher, registryAccess, environment) -> ChpCommand.register(dispatcher));
(dispatcher, registryAccess, environment) -> {
ChpCommand.register(dispatcher);
}
);
ServerTickEvents.END_WORLD_TICK.register(
world -> {
if (!world.getRegistryKey().getValue().equals(CHIPI_DIM)) return;
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
SERVER = server;
});
ServerTickEvents.END_WORLD_TICK.register(world -> {
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) {
return;
}
for (PlayerEntity player : world.getPlayers()) {
if (player.getBlockY() >= 50) continue;
if (player.getBlockY() >= 50) {
continue;
}
ChipperPortalBlock.teleportToChipiSpawn(world, player);
}
});
ServerWorldEvents.LOAD.register(
(server, world) -> {
if (!world.getRegistryKey().getValue().equals(CHIPI_DIM)) return;
ServerWorldEvents.LOAD.register((server, world) -> {
if (!world.getRegistryKey().equals(CHIPI_DIMENSION_KEY)) {
return;
}
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 =
world.getPersistentStateManager()
.getOrCreate(
world.getPersistentStateManager().getOrCreate(
SpawnPlacedState::fromNbt,
SpawnPlacedState::new,
"chipi_spawn");
"chipi_spawn"
);
if (state.placed) return;
if (state.placed) {
return;
}
StructureTemplate spawnTemplate =
world.getStructureTemplateManager()
@ -105,7 +137,8 @@ public class ChipiMod implements ModInitializer {
spawnCenter,
new StructurePlacementData(),
world.getRandom(),
2);
2
);
world.setSpawnPos(spawnCenter.up(), 0.0f);
@ -117,4 +150,12 @@ public class ChipiMod implements ModInitializer {
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,
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);
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);
CorridorNSStructure corridorNS =
WorldMaster.resolveCorridorNS(ctx(gridX, gridY, anchorSouth, null));
WorldMaster.resolveCorridorNS(ctx(world, gridX, gridY, anchorSouth, null));
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());
CorridorEWStructure corridorEW =
WorldMaster.resolveCorridorEW(ctx(gridX, gridY, anchorEast, null));
WorldMaster.resolveCorridorEW(ctx(world, gridX, gridY, anchorEast, null));
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(
int gridX, int gridY, BlockPos origin, ChipiStructure structure) {
return DungeonContext.of(gridX, gridY, origin, structure);
ServerWorld world, int gridX, int gridY, BlockPos origin, ChipiStructure structure) {
return DungeonContext.of(world, gridX, gridY, origin, structure);
}
}

View File

@ -1,5 +1,7 @@
package net.Chipperfluff.chipi.world.gen;
import java.util.Optional;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.StructureBlockBlockEntity;
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.Vec3i;
import java.util.Optional;
public abstract class ChipiStructure {
protected final Identifier id;
/** Offset from STRUCTURE BLOCK → actual structure origin */
protected final int deltaX;
protected final int deltaY;
protected final int deltaZ;
@ -29,41 +26,30 @@ public abstract class ChipiStructure {
this.deltaZ = deltaZ;
}
/** REAL size from NBT */
public BlockPos getSize(ServerWorld world) {
Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id);
if (opt.isEmpty()) return BlockPos.ORIGIN;
Vec3i size = opt.get().getSize();
return new BlockPos(size.getX(), size.getY(), size.getZ());
}
/** Pure structure placement */
public void placeAt(ServerWorld world, BlockPos centerPos) {
Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id);
if (opt.isEmpty()) {
System.out.println("[CHIPI] Missing structure: " + id);
return;
}
BlockPos origin = centerPos.add(new BlockPos(deltaX, deltaY, deltaZ));
StructureTemplate template = opt.get();
template.place(world, origin, origin, new StructurePlacementData(), world.getRandom(), 2);
BlockPos origin = centerPos.add(deltaX, deltaY, deltaZ);
opt.get().place(world, origin, origin, new StructurePlacementData(), world.getRandom(), 2);
}
/** Command placement (structure + optional marker) */
public void placeCommand(ServerWorld world, BlockPos placePos, boolean marker) {
placeAt(world, placePos);
BlockPos origin = placePos.add(new BlockPos(deltaX, deltaY, deltaZ));
if (!marker) return;
BlockPos origin = placePos.add(deltaX, deltaY, deltaZ);
world.setBlockState(origin, Blocks.STRUCTURE_BLOCK.getDefaultState(), 3);
if (world.getBlockEntity(origin) instanceof StructureBlockBlockEntity be) {
@ -76,4 +62,48 @@ public abstract class ChipiStructure {
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;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
public final class DungeonContext {
public static final DungeonContext EMPTY = new DungeonContext();
private Integer grid_x = null;
private Integer grid_y = null;
private BlockPos structure_origin = null;
private ChipiStructure structure = null;
private Integer grid_x;
private Integer grid_y;
private BlockPos structure_origin;
private ChipiStructure structure;
private ServerWorld world;
private DungeonContext() {}
private DungeonContext(
Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) {
private DungeonContext(ServerWorld world, Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) {
this.world = world;
this.grid_x = grid_x;
this.grid_y = grid_y;
this.structure_origin = structure_origin;
this.structure = structure;
}
public static DungeonContext of(
Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) {
return new DungeonContext(grid_x, grid_y, structure_origin, structure);
public static DungeonContext of(ServerWorld world, Integer grid_x, Integer grid_y, BlockPos structure_origin, ChipiStructure structure) {
return new DungeonContext(world, grid_x, grid_y, structure_origin, structure);
}
public ServerWorld getWorld() {
return world;
}
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.CorridorNSStructure;
import net.Chipperfluff.chipi.world.gen.struct.RoomBaseStructure;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
public final class WorldMaster {
@ -21,7 +23,6 @@ public final class WorldMaster {
}
public static RoomBaseStructure resolveRoom(DungeonContext ctx) {
return getDefaultRoom();
}
@ -35,6 +36,17 @@ public final class WorldMaster {
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();
}