From 48586eb523479e633ac6a92a69e13612774493da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zo=C3=AB=20Gidiere?= Date: Sun, 5 Oct 2025 20:23:54 -0600 Subject: [PATCH] Fix SNBT writing --- .../mod/handle/MinecraftWorldHandle.java | 12 +++++ .../terra/chunk/ChunkRegionMixin.java | 43 ++++++++++++++++-- .../terra/chunk/WorldChunkMixin.java | 11 ++++- .../terra/world/ChunkRegionMixin.java | 34 +++++++++++--- .../terra/world/ServerWorldMixin.java | 44 +++++++++++++++++-- 5 files changed, 131 insertions(+), 13 deletions(-) diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java index 8342b8f9b..b3204c326 100644 --- a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java @@ -20,13 +20,16 @@ package com.dfsek.terra.mod.handle; import com.dfsek.terra.api.block.state.BlockStateExtended; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; import net.minecraft.command.argument.BlockArgumentParser; import net.minecraft.command.argument.BlockArgumentParser.BlockResult; import net.minecraft.command.argument.BlockStateArgument; import net.minecraft.nbt.NbtCompound; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +54,15 @@ public class MinecraftWorldHandle implements WorldHandle { if (blockResult.nbt() != null) { net.minecraft.block.BlockState state = blockResult.blockState(); NbtCompound nbtCompound = blockResult.nbt(); + if (state.hasBlockEntity()) { + BlockEntity blockEntity = ((BlockEntityProvider) state.getBlock()).createBlockEntity(new BlockPos(0, 0, 0), state); + + nbtCompound.putInt("x", 0); + nbtCompound.putInt("y", 0); + nbtCompound.putInt("z", 0); + + nbtCompound.put("id", BlockEntity.TYPE_CODEC, blockEntity.getType()); + } blockState = (BlockStateExtended) new BlockStateArgument(state, blockResult.properties().keySet(), nbtCompound); } else { blockState = (BlockState) blockResult.blockState(); diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java index af74cca54..cc222054c 100644 --- a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java @@ -18,20 +18,30 @@ package com.dfsek.terra.mod.mixin.implementations.terra.chunk; import com.dfsek.seismic.math.coord.CoordFunctions; + +import com.dfsek.terra.api.block.state.BlockStateExtended; + import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.render.DimensionEffects.End; import net.minecraft.command.argument.BlockStateArgument; import net.minecraft.fluid.Fluid; +import net.minecraft.nbt.NbtCompound; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.random.Random; import net.minecraft.world.ChunkRegion; +import net.minecraft.world.StructureWorldAccess; import net.minecraft.world.WorldProperties; import net.minecraft.world.biome.source.BiomeAccess; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.feature.EndGatewayFeature; import net.minecraft.world.tick.MultiTickScheduler; import net.minecraft.world.tick.OrderedTick; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; @@ -44,7 +54,7 @@ import com.dfsek.terra.api.world.chunk.Chunk; @Mixin(ChunkRegion.class) @Implements(@Interface(iface = Chunk.class, prefix = "terraChunk$")) -public abstract class ChunkRegionMixin { +public abstract class ChunkRegionMixin implements StructureWorldAccess { @Shadow @Final @@ -62,14 +72,41 @@ public abstract class ChunkRegionMixin { @Final private MultiTickScheduler fluidTickScheduler; + @Shadow + public abstract net.minecraft.block.BlockState getBlockState(BlockPos pos); + + @Shadow + @Nullable + public abstract boolean setBlockState(BlockPos pos, net.minecraft.block.BlockState state, int flags, int maxUpdateDepth); + + public void terraChunk$setBlock(int x, int y, int z, @NotNull BlockState data, boolean physics) { ChunkPos pos = centerPos.getPos(); BlockPos blockPos = new BlockPos(CoordFunctions.chunkAndRelativeToAbsolute(pos.x, x), y, CoordFunctions.chunkAndRelativeToAbsolute(pos.z, z)); boolean isExtended = data.isExtended() && data.getClass().equals(BlockStateArgument.class); if (isExtended) { - ((BlockStateArgument) data).setBlockState(world, blockPos, 0); + BlockStateArgument arg = ((BlockStateArgument) data); + net.minecraft.block.BlockState state = arg.getBlockState(); + setBlockState(blockPos, state, 0, 512); + net.minecraft.world.chunk.Chunk chunk = getChunk(blockPos); + BlockEntity blockEntity; + NbtCompound nbt = ((NbtCompound) (Object) ((BlockStateExtended)data).getData()); + if ("DUMMY".equals(nbt.getString("id", ""))) { + if (state.hasBlockEntity()) { + blockEntity = ((BlockEntityProvider)state.getBlock()).createBlockEntity(blockPos, state); + } else { + blockEntity = null; + } + } else { + blockEntity = BlockEntity.createFromNbt(blockPos, state, nbt, this.world.getRegistryManager()); + } + + if (blockEntity != null) { + blockEntity.setWorld(this.world); + chunk.setBlockEntity(blockEntity); + } } else { - ((ChunkRegion) (Object) this).setBlockState(blockPos, (net.minecraft.block.BlockState) data, 0); + setBlockState(blockPos, (net.minecraft.block.BlockState) data, 0, 512); } if(physics) { diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java index 7ff36a78b..5e0047f25 100644 --- a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java @@ -17,6 +17,9 @@ package com.dfsek.terra.mod.mixin.implementations.terra.chunk; +import com.dfsek.terra.api.block.state.BlockStateExtended; + +import net.minecraft.block.entity.BlockEntity; import net.minecraft.command.argument.BlockStateArgument; import net.minecraft.nbt.NbtCompound; import net.minecraft.server.command.SetBlockCommand; @@ -52,12 +55,18 @@ public abstract class WorldChunkMixin { @Nullable public abstract net.minecraft.block.BlockState setBlockState(BlockPos pos, net.minecraft.block.BlockState state, int flags); + @Shadow + protected abstract BlockEntity loadBlockEntity(BlockPos pos, NbtCompound nbt); + @SuppressWarnings("ConstantValue") public void terra$setBlock(int x, int y, int z, BlockState data, boolean physics) { BlockPos blockPos = new BlockPos(x, y, z); boolean isExtended = data.isExtended() && data.getClass().equals(BlockStateArgument.class); if (isExtended) { - ((BlockStateArgument) data).setBlockState((net.minecraft.server.world.ServerWorld) world, blockPos, 0); + BlockStateArgument arg = ((BlockStateArgument) data); + net.minecraft.block.BlockState state = arg.getBlockState(); + setBlockState(blockPos, state, 0); + loadBlockEntity(blockPos, ((NbtCompound) (Object) ((BlockStateExtended)data).getData())); } else { setBlockState(blockPos, (net.minecraft.block.BlockState) data, 0); } diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java index 3439ad4be..9f67a7c12 100644 --- a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java @@ -17,14 +17,19 @@ package com.dfsek.terra.mod.mixin.implementations.terra.world; +import com.dfsek.terra.api.block.state.BlockStateExtended; + import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.FluidBlock; import net.minecraft.command.argument.BlockStateArgument; import net.minecraft.entity.SpawnReason; import net.minecraft.fluid.Fluid; +import net.minecraft.nbt.NbtCompound; import net.minecraft.util.collection.BoundedRegionArray; import net.minecraft.util.math.BlockPos; import net.minecraft.world.ChunkRegion; +import net.minecraft.world.StructureWorldAccess; import net.minecraft.world.WorldAccess; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkGenerationStep; @@ -56,7 +61,7 @@ import com.dfsek.terra.mod.util.MinecraftUtil; @Mixin(ChunkRegion.class) @Implements(@Interface(iface = ProtoWorld.class, prefix = "terraWorld$")) -public abstract class ChunkRegionMixin { +public abstract class ChunkRegionMixin implements StructureWorldAccess { private ConfigPack terra$config; @@ -95,17 +100,36 @@ public abstract class ChunkRegionMixin { int flags = physics ? 3 : 1042; boolean isExtended = data.isExtended() && data.getClass().equals(BlockStateArgument.class); if (isExtended) { - ((BlockStateArgument) data).setBlockState(world, blockPos, flags); + BlockStateArgument arg = ((BlockStateArgument) data); + net.minecraft.block.BlockState state = arg.getBlockState(); + setBlockState(blockPos, state, flags); + net.minecraft.world.chunk.Chunk chunk = getChunk(blockPos); + net.minecraft.block.entity.BlockEntity blockEntity; + NbtCompound nbt = ((NbtCompound) (Object) ((BlockStateExtended)data).getData()); + if ("DUMMY".equals(nbt.getString("id", ""))) { + if (state.hasBlockEntity()) { + blockEntity = ((BlockEntityProvider)state.getBlock()).createBlockEntity(blockPos, state); + } else { + blockEntity = null; + } + } else { + blockEntity = net.minecraft.block.entity.BlockEntity.createFromNbt(blockPos, state, nbt, getRegistryManager()); + } + + if (blockEntity != null) { + blockEntity.setWorld(world); + chunk.setBlockEntity(blockEntity); + } } else { - ((ChunkRegion) (Object) this).setBlockState(blockPos, (net.minecraft.block.BlockState) data, flags); + setBlockState(blockPos, (net.minecraft.block.BlockState) data, flags); } if(physics) { net.minecraft.block.BlockState state = isExtended ? ((BlockStateArgument) data).getBlockState() : ((net.minecraft.block.BlockState) data); if(state.isLiquid()) { - fluidTickScheduler.scheduleTick(OrderedTick.create(state.getFluidState().getFluid(), blockPos)); + getFluidTickScheduler().scheduleTick(OrderedTick.create(state.getFluidState().getFluid(), blockPos)); } else { - blockTickScheduler.scheduleTick(OrderedTick.create(state.getBlock(), blockPos)); + getBlockTickScheduler().scheduleTick(OrderedTick.create(state.getBlock(), blockPos)); } } } diff --git a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java index bfee2674b..8b5333257 100644 --- a/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java +++ b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java @@ -17,16 +17,25 @@ package com.dfsek.terra.mod.mixin.implementations.terra.world; +import com.dfsek.terra.api.block.state.BlockStateExtended; import com.dfsek.terra.mod.mixin.invoke.FluidBlockInvoker; import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.FluidBlock; import net.minecraft.command.argument.BlockStateArgument; import net.minecraft.entity.SpawnReason; import net.minecraft.fluid.Fluid; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.util.math.BlockPos; import net.minecraft.world.ChunkRegion; +import net.minecraft.world.MutableWorldProperties; +import net.minecraft.world.World; import net.minecraft.world.WorldAccess; +import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.tick.MultiTickScheduler; import net.minecraft.world.tick.OrderedTick; import net.minecraft.world.tick.WorldTickScheduler; @@ -54,17 +63,24 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(net.minecraft.server.world.ServerWorld.class) @Implements(@Interface(iface = ServerWorld.class, prefix = "terra$")) -public abstract class ServerWorldMixin { +public abstract class ServerWorldMixin extends World { + protected ServerWorldMixin(MutableWorldProperties properties, RegistryKey registryRef, DynamicRegistryManager registryManager, + RegistryEntry dimensionEntry, boolean isClient, boolean debugWorld, long seed, + int maxChainedNeighborUpdates) { + super(properties, registryRef, registryManager, dimensionEntry, isClient, debugWorld, seed, maxChainedNeighborUpdates); + } + @Shadow public abstract WorldTickScheduler getBlockTickScheduler(); @Shadow public abstract WorldTickScheduler getFluidTickScheduler(); + public Entity terra$spawnEntity(double x, double y, double z, EntityType entityType) { net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) entityType).create(null, SpawnReason.CHUNK_GENERATION); entity.setPos(x, y, z); - ((net.minecraft.server.world.ServerWorld) (Object) this).spawnEntity(entity); + spawnEntity(entity); return (Entity) entity; } @@ -73,10 +89,30 @@ public abstract class ServerWorldMixin { int flags = physics ? 3 : 1042; boolean isExtended = data.isExtended() && data.getClass().equals(BlockStateArgument.class); if (isExtended) { - ((BlockStateArgument) data).setBlockState(((net.minecraft.server.world.ServerWorld) (Object) this), blockPos, flags); + BlockStateArgument arg = ((BlockStateArgument) data); + net.minecraft.block.BlockState state = arg.getBlockState(); + setBlockState(blockPos, state, flags); + net.minecraft.world.chunk.Chunk chunk = getChunk(blockPos); + net.minecraft.block.entity.BlockEntity blockEntity; + NbtCompound nbt = ((NbtCompound) (Object) ((BlockStateExtended)data).getData()); + if ("DUMMY".equals(nbt.getString("id", ""))) { + if (state.hasBlockEntity()) { + blockEntity = ((BlockEntityProvider)state.getBlock()).createBlockEntity(blockPos, state); + } else { + blockEntity = null; + } + } else { + blockEntity = net.minecraft.block.entity.BlockEntity.createFromNbt(blockPos, state, nbt, getRegistryManager()); + } + + if (blockEntity != null) { + blockEntity.setWorld(this); + chunk.setBlockEntity(blockEntity); + } } else { - ((net.minecraft.server.world.ServerWorld) (Object) this).setBlockState(blockPos, (net.minecraft.block.BlockState) data, flags); + setBlockState(blockPos, (net.minecraft.block.BlockState) data, flags); } + if(physics) { net.minecraft.block.BlockState state = isExtended ? ((BlockStateArgument) data).getBlockState() : ((net.minecraft.block.BlockState) data); if(state.isLiquid()) {