From 63369076aee02dcf4dd0252142757073ca4e9abe Mon Sep 17 00:00:00 2001 From: TGGamesYT Date: Wed, 18 Mar 2026 16:19:06 +0100 Subject: [PATCH] backrooms 2 --- gradle.properties | 2 +- .../dev/tggamesyt/szar/client/SzarClient.java | 1 + .../szar/client/WallBlockRenderer.java | 91 ++++++++++++++++++ .../szar/BackroomsChunkGenerator.java | 62 ++++++++++++ .../szar/BackroomsChunkGeneratorConfig.java | 21 ---- .../dev/tggamesyt/szar/CanOfBeansItem.java | 39 ++++++++ .../szar/OverworldPortalFeature.java | 50 ++++++++++ .../java/dev/tggamesyt/szar/PortalBlock.java | 58 +++++------ .../dev/tggamesyt/szar/PortalDataState.java | 23 +++++ src/main/java/dev/tggamesyt/szar/Szar.java | 33 ++++++- .../java/dev/tggamesyt/szar/WallBlock.java | 33 +++++++ .../dev/tggamesyt/szar/WallBlockEntity.java | 76 +++++++++++++++ .../resources/assets/szar/lang/en_us.json | 5 +- .../assets/szar/models/item/bean.json | 6 ++ .../assets/szar/models/item/can_of_beans.json | 6 ++ .../assets/szar/textures/item/bean.png | Bin 0 -> 804 bytes .../szar/textures/item/can_of_beans.png | Bin 0 -> 2367 bytes .../textures/{item => }/walltext/arrow1.png | Bin .../textures/{item => }/walltext/arrow2.png | Bin .../textures/{item => }/walltext/arrow3.png | Bin .../textures/{item => }/walltext/arrow4.png | Bin .../{item => }/walltext/door_drawing.png | Bin .../{item => }/walltext/wall_small_1.png | Bin .../{item => }/walltext/wall_small_2.png | Bin .../{item => }/walltext/window_drawing.png | Bin .../configured_feature/overworld_portal.json | 4 + .../placed_feature/overworld_portal.json | 19 ++++ 27 files changed, 477 insertions(+), 52 deletions(-) create mode 100644 src/client/java/dev/tggamesyt/szar/client/WallBlockRenderer.java delete mode 100644 src/main/java/dev/tggamesyt/szar/BackroomsChunkGeneratorConfig.java create mode 100644 src/main/java/dev/tggamesyt/szar/CanOfBeansItem.java create mode 100644 src/main/java/dev/tggamesyt/szar/OverworldPortalFeature.java create mode 100644 src/main/java/dev/tggamesyt/szar/WallBlock.java create mode 100644 src/main/java/dev/tggamesyt/szar/WallBlockEntity.java create mode 100644 src/main/resources/assets/szar/models/item/bean.json create mode 100644 src/main/resources/assets/szar/models/item/can_of_beans.json create mode 100644 src/main/resources/assets/szar/textures/item/bean.png create mode 100644 src/main/resources/assets/szar/textures/item/can_of_beans.png rename src/main/resources/assets/szar/textures/{item => }/walltext/arrow1.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/arrow2.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/arrow3.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/arrow4.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/door_drawing.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/wall_small_1.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/wall_small_2.png (100%) rename src/main/resources/assets/szar/textures/{item => }/walltext/window_drawing.png (100%) create mode 100644 src/main/resources/data/szar/worldgen/configured_feature/overworld_portal.json create mode 100644 src/main/resources/data/szar/worldgen/placed_feature/overworld_portal.json diff --git a/gradle.properties b/gradle.properties index 01a69ca..750aac5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 loader_version=0.18.3 # Mod Properties -mod_version=26.3.18 +mod_version=26.3.18.1 maven_group=dev.tggamesyt archives_base_name=szar # Dependencies diff --git a/src/client/java/dev/tggamesyt/szar/client/SzarClient.java b/src/client/java/dev/tggamesyt/szar/client/SzarClient.java index e4dd2ae..3926f00 100644 --- a/src/client/java/dev/tggamesyt/szar/client/SzarClient.java +++ b/src/client/java/dev/tggamesyt/szar/client/SzarClient.java @@ -362,6 +362,7 @@ public class SzarClient implements ClientModInitializer { }); } ); + BlockEntityRendererFactories.register(Szar.WALL_BLOCK_ENTITY, WallBlockRenderer::new); BlockEntityRendererFactories.register( Szar.TRACKER_BLOCK_ENTITY, TGTrackerBlockRenderer::new diff --git a/src/client/java/dev/tggamesyt/szar/client/WallBlockRenderer.java b/src/client/java/dev/tggamesyt/szar/client/WallBlockRenderer.java new file mode 100644 index 0000000..756dccd --- /dev/null +++ b/src/client/java/dev/tggamesyt/szar/client/WallBlockRenderer.java @@ -0,0 +1,91 @@ +package dev.tggamesyt.szar.client; + +import dev.tggamesyt.szar.Szar; +import dev.tggamesyt.szar.WallBlockEntity; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.client.render.WorldRenderer; +import org.joml.Matrix4f; + +public class WallBlockRenderer implements BlockEntityRenderer { + static String base = "textures/walltext/"; + static String end = ".png"; + private static final Identifier[] TEXTURES = { + new Identifier(Szar.MOD_ID, base + "arrow1" + end), + new Identifier(Szar.MOD_ID, base + "arrow2" + end), + new Identifier(Szar.MOD_ID, base + "arrow3" + end), + new Identifier(Szar.MOD_ID, base + "arrow4" + end), + new Identifier(Szar.MOD_ID, base + "door_drawing" + end), + new Identifier(Szar.MOD_ID, base + "wall_small_1" + end), + new Identifier(Szar.MOD_ID, base + "wall_small_2" + end), + new Identifier(Szar.MOD_ID, base + "window_drawing" + end), + }; + + public WallBlockRenderer(BlockEntityRendererFactory.Context ctx) {} + + @Override + public void render(WallBlockEntity entity, float tickDelta, MatrixStack matrices, + VertexConsumerProvider vertexConsumers, int light, int overlay) { + + if (entity.drawingIndex < 0) return; // no drawing on this block + + BlockPos pos = entity.getPos(); + int lightLevel = WorldRenderer.getLightmapCoordinates(entity.getWorld(), pos); + + Identifier texture = TEXTURES[entity.drawingIndex]; + VertexConsumer consumer = vertexConsumers.getBuffer( + RenderLayer.getEntityCutoutNoCull(texture)); + + matrices.push(); + + // Offset and rotate based on which face the drawing is on + // 0=north, 1=south, 2=west, 3=east + switch (entity.drawingFace) { + //case 0 -> matrices.translate(0.5, 0.5, -0.001); + case 1 -> { // South face (positive Z) + matrices.translate(0.5, 0.5, 1.001); + matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(180)); + } + case 2 -> { // West face (negative X) + matrices.translate(-0.001, 0.5, 0.5); + matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(90)); + } + case 3 -> { // East face (positive X) + matrices.translate(1.001, 0.5, 0.5); + matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(-90)); + } + default -> matrices.translate(0.5, 0.5, -0.001); + } + + // Scale to fit on the face (0.8 leaves a small border) + matrices.scale(0.8f, 0.8f, 0.8f); + + Matrix4f matrix = matrices.peek().getPositionMatrix(); + + // Draw a simple quad + float u0 = 0f, u1 = 1f, v0 = 0f, v1 = 1f; + float s = 0.5f; // half size + + consumer.vertex(matrix, -s, -s, 0).color(255, 255, 255, 255) + .texture(u0, v1).overlay(overlay).light(lightLevel) + .normal(0, 0, -1).next(); + consumer.vertex(matrix, -s, s, 0).color(255, 255, 255, 255) + .texture(u0, v0).overlay(overlay).light(lightLevel) + .normal(0, 0, -1).next(); + consumer.vertex(matrix, s, s, 0).color(255, 255, 255, 255) + .texture(u1, v0).overlay(overlay).light(lightLevel) + .normal(0, 0, -1).next(); + consumer.vertex(matrix, s, -s, 0).color(255, 255, 255, 255) + .texture(u1, v1).overlay(overlay).light(lightLevel) + .normal(0, 0, -1).next(); + + matrices.pop(); + } +} \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java b/src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java index 6350866..80fab57 100644 --- a/src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java +++ b/src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java @@ -3,6 +3,7 @@ package dev.tggamesyt.szar; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import dev.tggamesyt.szar.Szar; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.registry.RegistryCodecs; @@ -12,6 +13,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.ChunkRegion; import net.minecraft.world.HeightLimitView; import net.minecraft.world.Heightmap; +import net.minecraft.world.StructureWorldAccess; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeKeys; import net.minecraft.world.biome.source.BiomeAccess; @@ -113,6 +115,8 @@ public class BackroomsChunkGenerator extends ChunkGenerator { Szar.WALL_BLOCK.getDefaultState(), false); } } + // After the lx/lz loop, still inside populateNoise: + placeBackroomsPortals(chunk, chunkX, chunkZ); } } @@ -232,4 +236,62 @@ public class BackroomsChunkGenerator extends ChunkGenerator { @Override public void getDebugHudText(List text, NoiseConfig noiseConfig, BlockPos pos) {} + + @Override + public void generateFeatures(StructureWorldAccess world, Chunk chunk, + StructureAccessor structureAccessor) { + // Initialize wall block entities after chunk is placed + BlockPos.Mutable mutable = new BlockPos.Mutable(); + int chunkX = chunk.getPos().getStartX(); + int chunkZ = chunk.getPos().getStartZ(); + + for (int lx = 0; lx < 16; lx++) { + for (int lz = 0; lz < 16; lz++) { + for (int y = 0; y < 64; y++) { + mutable.set(chunkX + lx, y, chunkZ + lz); + if (world.getBlockState(mutable).getBlock() instanceof WallBlock) { + if (world.getBlockEntity(mutable) == null) { + // Force block entity creation by re-setting the block + world.setBlockState(mutable, Szar.WALL_BLOCK.getDefaultState(), + Block.NOTIFY_LISTENERS); + } + if (world.getBlockEntity(mutable) instanceof WallBlockEntity wall) { + wall.initializeIfNeeded(); + } + } + } + mutable.set(chunkX + lx, CEILING_Y - 1, chunkZ + lz); // Y=8 + if (world.getBlockState(mutable).getBlock() instanceof TrackerBlock) { + if (world.getBlockEntity(mutable) == null) { + world.setBlockState(mutable, Szar.TRACKER_BLOCK.getDefaultState(), + Block.NOTIFY_ALL); + } + if (world.getBlockEntity(mutable) instanceof TrackerBlockEntity te) { + te.placedByPlayer = false; + te.originalPortalBlock = Szar.PLASTIC.getDefaultState(); + te.markDirty(); + } + } + } + } + } + + private void placeBackroomsPortals(Chunk chunk, int chunkX, int chunkZ) { + long chunkHash = hash(chunkX * 7 + 3, chunkZ * 13 + 7); + if ((chunkHash % 20) != 0) return; + + int lx = 4 + (int)(chunkHash >> 8 & 0x7); + int lz = 4 + (int)(chunkHash >> 12 & 0x7); + + if (!isOpenSpace(chunkX * 16 + lx, chunkZ * 16 + lz)) return; + + // Tracker hangs from ceiling (Y=8, top wall block level) + // Portal is 4 blocks below at Y=4 (floor level, replacing floor block) + // Gap between: Y=5, Y=6, Y=7 = 3 air blocks + tracker at 8 = exactly 4 apart + BlockPos trackerPos = new BlockPos(lx, CEILING_Y - 1, lz); // Y=8 + BlockPos portalPos = trackerPos.down(4); // Y=4 + + chunk.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState(), false); + chunk.setBlockState(trackerPos, Szar.TRACKER_BLOCK.getDefaultState(), false); + } } \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/BackroomsChunkGeneratorConfig.java b/src/main/java/dev/tggamesyt/szar/BackroomsChunkGeneratorConfig.java deleted file mode 100644 index 176c2ef..0000000 --- a/src/main/java/dev/tggamesyt/szar/BackroomsChunkGeneratorConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.tggamesyt.szar; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -public class BackroomsChunkGeneratorConfig { - - public static final Codec CODEC = - RecordCodecBuilder.create(instance -> instance.group( - Codec.INT.fieldOf("floor_y").forGetter(c -> c.floorY) - ).apply(instance, BackroomsChunkGeneratorConfig::new)); - - public static final BackroomsChunkGeneratorConfig DEFAULT = - new BackroomsChunkGeneratorConfig(4); - - public final int floorY; - - public BackroomsChunkGeneratorConfig(int floorY) { - this.floorY = floorY; - } -} \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/CanOfBeansItem.java b/src/main/java/dev/tggamesyt/szar/CanOfBeansItem.java new file mode 100644 index 0000000..da358ee --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/CanOfBeansItem.java @@ -0,0 +1,39 @@ +package dev.tggamesyt.szar; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; + +public class CanOfBeansItem extends Item { + + public CanOfBeansItem(Settings settings) { + super(settings.maxCount(1).maxDamage(6)); + } + + @Override + public TypedActionResult use(World world, PlayerEntity player, Hand hand) { + ItemStack stack = player.getStackInHand(hand); + + if (world.isClient) return TypedActionResult.success(stack); + + // Give one bean + ItemStack bean = new ItemStack(Szar.BEAN); + if (!player.getInventory().insertStack(bean)) { + player.dropItem(bean, false); + } + + // Play a little sound + world.playSound(null, player.getBlockPos(), + SoundEvents.ITEM_BOTTLE_EMPTY, SoundCategory.PLAYERS, 1.0f, 1.0f); + + // Damage the item by 1 — if it breaks, replace with empty hand + stack.damage(1, player, p -> p.sendToolBreakStatus(hand)); + + return TypedActionResult.success(stack); + } +} \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/OverworldPortalFeature.java b/src/main/java/dev/tggamesyt/szar/OverworldPortalFeature.java new file mode 100644 index 0000000..b8487e4 --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/OverworldPortalFeature.java @@ -0,0 +1,50 @@ +package dev.tggamesyt.szar; + +import com.mojang.serialization.Codec; +import dev.tggamesyt.szar.PortalBlock; +import dev.tggamesyt.szar.Szar; +import dev.tggamesyt.szar.TrackerBlock; +import dev.tggamesyt.szar.TrackerBlockEntity; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.FeatureConfig; +import net.minecraft.world.gen.feature.util.FeatureContext; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; + +public class OverworldPortalFeature extends Feature { + + public OverworldPortalFeature(Codec codec) { + super(codec); + } + + @Override + public boolean generate(FeatureContext ctx) { + var world = ctx.getWorld(); + BlockPos origin = ctx.getOrigin(); + + int surfaceY = world.getTopY( + net.minecraft.world.Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, + origin.getX(), origin.getZ()); + + BlockPos trackerPos = new BlockPos(origin.getX(), surfaceY, origin.getZ()); + BlockPos portalPos = trackerPos.down(4); + + BlockState original = world.getBlockState(portalPos); + + world.setBlockState(trackerPos, Szar.TRACKER_BLOCK.getDefaultState(), + net.minecraft.block.Block.NOTIFY_ALL); + + if (world.getBlockEntity(trackerPos) instanceof TrackerBlockEntity te) { + te.placedByPlayer = false; + te.originalPortalBlock = original; + te.markDirty(); + } + + world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState(), + net.minecraft.block.Block.NOTIFY_ALL); + + return true; + } +} \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/PortalBlock.java b/src/main/java/dev/tggamesyt/szar/PortalBlock.java index d000511..af8c433 100644 --- a/src/main/java/dev/tggamesyt/szar/PortalBlock.java +++ b/src/main/java/dev/tggamesyt/szar/PortalBlock.java @@ -28,7 +28,6 @@ public class PortalBlock extends Block { // Cooldown tracker so players don't teleport 20x per second private static final java.util.Map cooldowns = new java.util.HashMap<>(); - public PortalBlock(Settings settings) { super(settings); } @@ -63,42 +62,47 @@ public class PortalBlock extends Block { teleportToOverworld(player, tracker, server); } } else { - // Non-player entity — just teleport, no inventory or tracker registration + // Non-player entity — teleport only, no inventory or tracker registration if (world.getRegistryKey() == World.OVERWORLD) { ServerWorld backrooms = server.getWorld(Szar.BACKROOMS_KEY); if (backrooms == null) return; + + // Save overworld entry coords for this entity + PortalDataState.getOrCreate(server.getWorld(World.OVERWORLD)) + .saveEntityEntry(entity.getUuid(), entity.getX(), entity.getY() + 6, entity.getZ()); + double safeY = findSafeY(backrooms, (int) entity.getX(), (int) entity.getZ()); entity.teleport(backrooms, entity.getX(), safeY, entity.getZ(), java.util.Set.of(), entity.getYaw(), entity.getPitch()); - } else { - // Non-player entity — just teleport, no inventory or tracker registration - if (world.getRegistryKey() == World.OVERWORLD) { - ServerWorld backrooms = server.getWorld(Szar.BACKROOMS_KEY); - if (backrooms == null) return; - double safeY = findSafeY(backrooms, (int) entity.getX(), (int) entity.getZ()); - entity.teleport(backrooms, entity.getX(), safeY, entity.getZ(), - java.util.Set.of(), entity.getYaw(), entity.getPitch()); - } else if (world.getRegistryKey() == Szar.BACKROOMS_KEY) { - ServerWorld overworld = server.getWorld(World.OVERWORLD); - if (overworld == null) return; - double baseX = tracker.returnX; - double baseY = tracker.returnY; - double baseZ = tracker.returnZ; + } else if (world.getRegistryKey() == Szar.BACKROOMS_KEY) { + ServerWorld overworld = server.getWorld(World.OVERWORLD); + if (overworld == null) return; - // If no player has used this portal yet, fallback - if (baseX == 0 && baseY == 0 && baseZ == 0) { - double safeY = findSafeY(overworld, (int) entity.getX(), (int) entity.getZ()); - entity.teleport(overworld, entity.getX(), safeY, entity.getZ(), - java.util.Set.of(), entity.getYaw(), entity.getPitch()); - return; - } + double rx, ry, rz; - // Search up to 10 blocks offset in XZ and Y for a safe spot not above a portal - BlockPos safePos = findSafeSpotNearEntry(overworld, baseX, baseY, baseZ); - entity.teleport(overworld, safePos.getX() + 0.5, safePos.getY(), safePos.getZ() + 0.5, - java.util.Set.of(), entity.getYaw(), entity.getPitch()); + double[] saved = PortalDataState.getOrCreate(server.getWorld(World.OVERWORLD)) + .getAndRemoveEntityEntry(entity.getUuid()); + if (saved != null) { + // Use entity's own saved entry coords + rx = saved[0]; + ry = saved[1]; + rz = saved[2]; + } else if (tracker.returnX != 0 || tracker.returnY != 0 || tracker.returnZ != 0) { + // Fall back to last player's entry coords on this tracker + rx = tracker.returnX; + ry = tracker.returnY; + rz = tracker.returnZ; + } else { + // Fall back to entity's current position + 6 + rx = entity.getX(); + ry = entity.getY() + 6; + rz = entity.getZ(); } + + BlockPos safePos = findSafeSpotNearEntry(overworld, rx, ry, rz); + entity.teleport(overworld, safePos.getX() + 0.5, safePos.getY(), safePos.getZ() + 0.5, + java.util.Set.of(), entity.getYaw(), entity.getPitch()); } } } diff --git a/src/main/java/dev/tggamesyt/szar/PortalDataState.java b/src/main/java/dev/tggamesyt/szar/PortalDataState.java index 4783b65..dbd4279 100644 --- a/src/main/java/dev/tggamesyt/szar/PortalDataState.java +++ b/src/main/java/dev/tggamesyt/szar/PortalDataState.java @@ -43,4 +43,27 @@ public class PortalDataState extends PersistentState { return overworld.getPersistentStateManager() .getOrCreate(PortalDataState::fromNbt, PortalDataState::new, KEY); } + + public void saveEntityEntry(UUID uuid, double x, double y, double z) { + NbtCompound entry = new NbtCompound(); + entry.putDouble("X", x); + entry.putDouble("Y", y); + entry.putDouble("Z", z); + data.put("entity_" + uuid, entry); + markDirty(); + } + + public double[] getAndRemoveEntityEntry(UUID uuid) { + String key = "entity_" + uuid; + if (!data.contains(key)) return null; + NbtCompound entry = data.getCompound(key); + double[] coords = new double[]{ + entry.getDouble("X"), + entry.getDouble("Y"), + entry.getDouble("Z") + }; + data.remove(key); + markDirty(); + return coords; + } } \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/Szar.java b/src/main/java/dev/tggamesyt/szar/Szar.java index a5a5e21..efc1398 100644 --- a/src/main/java/dev/tggamesyt/szar/Szar.java +++ b/src/main/java/dev/tggamesyt/szar/Szar.java @@ -368,6 +368,8 @@ public class Szar implements ModInitializer { entries.add(Szar.WALL_BOTTOM_ITEM); entries.add(Szar.CEILING_ITEM); entries.add(Szar.PLASTIC_ITEM); + entries.add(Szar.BEAN); + entries.add(Szar.CAN_OF_BEANS); // crazy weponary entries.add(Szar.BULLET_ITEM); entries.add(Szar.AK47); @@ -1079,6 +1081,12 @@ public class Szar implements ModInitializer { p -> p.sendToolBreakStatus(player.getActiveHand())); }); }); + BiomeModifications.addFeature( + BiomeSelectors.foundInOverworld(), + GenerationStep.Feature.SURFACE_STRUCTURES, + RegistryKey.of(RegistryKeys.PLACED_FEATURE, + new Identifier(MOD_ID, "overworld_portal")) + ); } // Blocks public static final TrackerBlock TRACKER_BLOCK = Registry.register( @@ -1115,9 +1123,13 @@ public class Szar implements ModInitializer { new Identifier(MOD_ID, "tracker"), FabricBlockEntityTypeBuilder.create(TrackerBlockEntity::new, TRACKER_BLOCK).build() ); - public static final Block WALL_BLOCK = Registry.register( + public static final WallBlock WALL_BLOCK = Registry.register( Registries.BLOCK, new Identifier(MOD_ID, "wall"), - new Block(AbstractBlock.Settings.create()) + new WallBlock(AbstractBlock.Settings.create()) + ); + public static final BlockEntityType WALL_BLOCK_ENTITY = Registry.register( + Registries.BLOCK_ENTITY_TYPE, new Identifier(MOD_ID, "wall"), + FabricBlockEntityTypeBuilder.create(WallBlockEntity::new, WALL_BLOCK).build() ); public static final Block WALL_BOTTOM_BLOCK = Registry.register( Registries.BLOCK, new Identifier(MOD_ID, "wall_bottom"), @@ -1317,6 +1329,11 @@ public class Szar implements ModInitializer { new Identifier(MOD_ID, "island"), () -> IslandStructure.CODEC ); + public static Feature OVERWORLD_PORTAL_FEATURE = Registry.register( + Registries.FEATURE, + new Identifier(MOD_ID, "overworld_portal"), + new OverworldPortalFeature(DefaultFeatureConfig.CODEC) + ); static VoxelShape shape0 = VoxelShapes.cuboid(0.1875f, 0f, 0.625f, 0.6875f, 0.5f, 1.125f); static VoxelShape shape1 = VoxelShapes.cuboid(0.1875f, 1.5f, 0.625f, 0.6875f, 2f, 1.125f); static VoxelShape shape2 = VoxelShapes.cuboid(0.5625f, 0f, 0.25f, 1.0625f, 2f, 0.75f); @@ -1685,6 +1702,18 @@ public class Szar implements ModInitializer { hunger((Math.random() < 0.5) ? 6 : 7) // SIX OR SEVEN .build()), 217) ); + + public static final Item BEAN = Registry.register( + Registries.ITEM, + new Identifier(MOD_ID, "bean"), + new Item(new Item.Settings() + .food(new FoodComponent.Builder().saturationModifier(0.6f).hunger(1).build())) + ); + public static final Item CAN_OF_BEANS = Registry.register( + Registries.ITEM, + new Identifier(MOD_ID, "can_of_beans"), + new CanOfBeansItem(new Item.Settings()) + ); public static final SoundEvent BAITER = SoundEvent.of(new Identifier(MOD_ID, "baiter")); public static final Item BAITER_DISC = Registry.register( diff --git a/src/main/java/dev/tggamesyt/szar/WallBlock.java b/src/main/java/dev/tggamesyt/szar/WallBlock.java new file mode 100644 index 0000000..f1393a5 --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/WallBlock.java @@ -0,0 +1,33 @@ +package dev.tggamesyt.szar; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityTicker; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +public class WallBlock extends Block implements BlockEntityProvider { + + public WallBlock(Settings settings) { + super(settings); + } + + @Nullable + @Override + public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new WallBlockEntity(pos, state); + } + + @Override + public BlockEntityTicker getTicker( + World world, BlockState state, BlockEntityType type) { + if (world.isClient) return null; + return type == Szar.WALL_BLOCK_ENTITY + ? (w, pos, s, be) -> WallBlockEntity.tick(w, pos, s, (WallBlockEntity) be) + : null; + } +} \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/WallBlockEntity.java b/src/main/java/dev/tggamesyt/szar/WallBlockEntity.java new file mode 100644 index 0000000..470f55e --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/WallBlockEntity.java @@ -0,0 +1,76 @@ +package dev.tggamesyt.szar; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class WallBlockEntity extends BlockEntity { + + // -1 = no drawing, 0-7 = which drawing + public int drawingIndex = -1; + // Which face the drawing is on (0=north, 1=south, 2=west, 3=east) + public int drawingFace = 0; + public boolean initialized = false; + + public WallBlockEntity(BlockPos pos, BlockState state) { + super(Szar.WALL_BLOCK_ENTITY, pos, state); + } + + public void initializeIfNeeded() { + if (initialized) return; + initialized = true; + + java.util.Random rand = new java.util.Random( + // Seed by position so it's deterministic per block + pos.getX() * 341873128712L ^ pos.getZ() * 132897987541L ^ pos.getY() + ); + + if (rand.nextInt(25) == 0) { + drawingIndex = rand.nextInt(8); + drawingFace = rand.nextInt(4); + } + + markDirty(); + } + + @Override + public void writeNbt(NbtCompound nbt) { + super.writeNbt(nbt); + nbt.putInt("DrawingIndex", drawingIndex); + nbt.putInt("DrawingFace", drawingFace); + nbt.putBoolean("Initialized", initialized); + } + + @Override + public void readNbt(NbtCompound nbt) { + super.readNbt(nbt); + drawingIndex = nbt.getInt("DrawingIndex"); + drawingFace = nbt.getInt("DrawingFace"); + initialized = nbt.getBoolean("Initialized"); + } + + public static void tick(World world, BlockPos pos, BlockState state, WallBlockEntity entity) { + if (!world.isClient && !entity.initialized) { + entity.initializeIfNeeded(); + } + } + + @Override + public Packet toUpdatePacket() { + return BlockEntityUpdateS2CPacket.create(this); + } + + // In WallBlockEntity.java — override this to auto-init when chunk data is requested + @Override + public NbtCompound toInitialChunkDataNbt() { + if (!initialized) { + initializeIfNeeded(); + } + return createNbt(); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/szar/lang/en_us.json b/src/main/resources/assets/szar/lang/en_us.json index 7776beb..a94745d 100644 --- a/src/main/resources/assets/szar/lang/en_us.json +++ b/src/main/resources/assets/szar/lang/en_us.json @@ -144,5 +144,8 @@ "block.szar.plastic": "Plastic", "block.szar.ceiling": "Ceiling", "block.szar.wall": "Wall", - "block.szar.wall_bottom": "Wall Bottom" + "block.szar.wall_bottom": "Wall Bottom", + + "item.szar.bean": "Bean", + "item.szar.can_of_beans": "Can of Beans" } diff --git a/src/main/resources/assets/szar/models/item/bean.json b/src/main/resources/assets/szar/models/item/bean.json new file mode 100644 index 0000000..81a0024 --- /dev/null +++ b/src/main/resources/assets/szar/models/item/bean.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "szar:item/bean" + } +} diff --git a/src/main/resources/assets/szar/models/item/can_of_beans.json b/src/main/resources/assets/szar/models/item/can_of_beans.json new file mode 100644 index 0000000..e0ed27a --- /dev/null +++ b/src/main/resources/assets/szar/models/item/can_of_beans.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "szar:item/can_of_beans" + } +} diff --git a/src/main/resources/assets/szar/textures/item/bean.png b/src/main/resources/assets/szar/textures/item/bean.png new file mode 100644 index 0000000000000000000000000000000000000000..c5197124f3be47580425066217064877575825ab GIT binary patch literal 804 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4egmB5hW46K32*3xq68y`AMmI6}bgK)eHls47YguJQ{>uF6ifOi{PD zbs{}UK3djZt>nqvW6s4qD1-ZCERRDRmN*N_31y=g{ z<>lpi<;HsXMd|v6mX?v90`zGE;%B09k2gXakl<5wp<;IRwdJb`TMuUx6%m z$bf1m&yH-eS<GqNad**bIcX33N5*l zm0>F`TiiYV`PnkHofEy=|GlWGVZ2~*lXb(_N}fr5EH^&hQ(Jwy`(s6u17Esh$^OcW zi*I>YA27t;vpxEmbIKM`eKw0bpE&1QFnDhHeON;=c7prXN6IH<8fLD%mviwQ|E0>- z88>enWVt$9pHuz6;${`qM0V>slVitj1v$O{#>P@)v;S*F?f;NvjE~I?XTJezR^L*! p*_G4qP*JwA2iJeQ&CJFR#pORGwEzEqXe}tIdb;|#taD0e0s!-WDjNU* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/szar/textures/item/can_of_beans.png b/src/main/resources/assets/szar/textures/item/can_of_beans.png new file mode 100644 index 0000000000000000000000000000000000000000..8aa5699f15cacb53478e366f04f750414c9d90e0 GIT binary patch literal 2367 zcmY*bc{~&RAD@}o3>hhn$C*gBnIkqsLZl|g+)A5`ZL!IQnVS{4$}vfbDCd(N2{}tS zD$z;@CEX=QNOI(O=K1w{e!t%zpYP{-f8U?a_x;!Rl(Un)j1)o&007ABcd&I8dG!s0 zfJG;p$NM32Vr*CYy@1*Qm9L@%6l6`X1_0_#!&XQVq8u9P;LQdAWbba6STC!RBD#=5 zCwg(b2nTTitPm85!Xi^q+>lTa8UVmsaYIP~$EX~2GBt?Kw9uJuy``g0r&#ECnh*>K zp*B<+-GLWIb>le^19-;*uoN9DOBpFV7bju}p>jy-+>l@<8^^WK{D&APiZ{w=O-pk`e|tz}tl#gq3@Q#^ST0^aqV`K^OBcD@ zPfT3*wSCLO!{)BQtBMTF&C;g+%aAI!79u| zn0GXto$_tU&I#8MN>&&D(sbkHJoRleKJ&H&$^Q7qk+8Novj;=@rQjqefS)7Z=Dfw; z!N~cN%Xev}H(`31-*Jk1bX0@a^%1YE)+w^hGyz!U(eIt7f?H3O_BCE^x z-6VY=hshYnxm_v35~FEdGT_~L@Z+>lVthQ5=oJxdm8`=mrRH7rUzdu0J_3fpz2a#} zt_cZYlV8=|?+h^3l4>tvws*ZJB!5KQ3kHlY9=EHrT@dVH3sddTqp2`ix#jB_{jI9q zL*O3W=ocf)KS9B|m$h}RRnmf729LiT)-jO!^sMGotkVG_vVulo_Uc4pakV)sFLDSkUre4Vm-YO0NLe%v}-%#d#Lqb zNl0{y94%-(ykzfWXY}c&{JaE{EeH5Y=_V&0YUt&{bKwf`ONhV=;`IZqmui3jd48gC z>9)jchu;_bFH84u3L;M+gx9Ha^|!$4HqIfW%lFEgr8wGh2+y%oT5F9T>Qkjg5r3Ay zC`3VOlFmvS=>9cz`qAJ`=Q5v0d_&+A5G395?JfMst0jO7!#O(k>nJn>1DYO=S!}|u zCHjt9f{B6$Pd5u3Pi)_x`k`R^{z{_WK_@5Is~)qXx!a-DY1KK~p`%-~i?>4uuzCV1 z!Gmo(bQF?EM{>y;KqVzrRf&?}VBnpZ8C@G28);ct5!&?i59UBoRQ)QN#9*Wu6T~$7 ze3b&=aF1HQ`|sBhvu+nzdjgG4?$0s6874L4C*%<2Gceufefqwx7wzCD)a`{NzIzNW zuc)9e6}gUxgN$_rM$iVItCdK$P>_Hq=-^&d_SF9})E95<9yK><+?V1}Qq7%?ns|>r zc`}7Nv4RDRwsBP5sWe(@dV}6P?}A{L=k*wxM8&RL_Th)6yTmXTeY~-=<9+;X&ppiI z#uc4b=Ba-|N~eHYX)Xrk7LBmeitoCrJU3drNyR5z*|pxfigA@5M=0=k-y?Gr`&H%ii#U0mSYi4i$dEvK+M`$`bt^UiF@MP@JpSW zZp9*cIu(4v869JD5j%LVV$~G&^9dF*mTMJ&&TyLa(#m*-Es!ccbPe#m*-#2vqLig_6 zC(8o154^*3p;H3$$LEx`w6kM?_UiTq)gYGl@=W_=ECuOQ7V#oE)(Us0cF;5|GG+@a z-KLuMw)?pzC|!{h9HXLj!RgD-q*|$>s44f42scn(QfjSf$y?@?uVgoJ{aI?yQoeOk9hnxTiJo&;ikdu!+8I4A$5kPa zR)6J>Yj;zs*z?YY$<0!JX92gnP1gpVWSdaT3a`Ws#FJqSVeOT9J3bH4(t6dJ19pP} zPn9BqS1_yn?_V87jlvVWf()Kt z+bT@KUP)P53*9mJ89tVg_|{nge#)lqW+NL==6C>~=}>hJJTL6}+2xmwSnY>wHFWH8 zg>B0mtNtm1(Q1~y;bww*LmfFisc4Vqfq@PMYsUT;=68oJ8X_p zo*5EhnmwD(9nE+*e;;Od5=7-vFr^`P^vnpu?1>QJxHw~OrT_d`f*rxPA9Zy_?`6&A jlt%+?rxTw8znJ}YPPVmsk0$*Mx;Plk literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/szar/textures/item/walltext/arrow1.png b/src/main/resources/assets/szar/textures/walltext/arrow1.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/arrow1.png rename to src/main/resources/assets/szar/textures/walltext/arrow1.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/arrow2.png b/src/main/resources/assets/szar/textures/walltext/arrow2.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/arrow2.png rename to src/main/resources/assets/szar/textures/walltext/arrow2.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/arrow3.png b/src/main/resources/assets/szar/textures/walltext/arrow3.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/arrow3.png rename to src/main/resources/assets/szar/textures/walltext/arrow3.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/arrow4.png b/src/main/resources/assets/szar/textures/walltext/arrow4.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/arrow4.png rename to src/main/resources/assets/szar/textures/walltext/arrow4.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/door_drawing.png b/src/main/resources/assets/szar/textures/walltext/door_drawing.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/door_drawing.png rename to src/main/resources/assets/szar/textures/walltext/door_drawing.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/wall_small_1.png b/src/main/resources/assets/szar/textures/walltext/wall_small_1.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/wall_small_1.png rename to src/main/resources/assets/szar/textures/walltext/wall_small_1.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/wall_small_2.png b/src/main/resources/assets/szar/textures/walltext/wall_small_2.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/wall_small_2.png rename to src/main/resources/assets/szar/textures/walltext/wall_small_2.png diff --git a/src/main/resources/assets/szar/textures/item/walltext/window_drawing.png b/src/main/resources/assets/szar/textures/walltext/window_drawing.png similarity index 100% rename from src/main/resources/assets/szar/textures/item/walltext/window_drawing.png rename to src/main/resources/assets/szar/textures/walltext/window_drawing.png diff --git a/src/main/resources/data/szar/worldgen/configured_feature/overworld_portal.json b/src/main/resources/data/szar/worldgen/configured_feature/overworld_portal.json new file mode 100644 index 0000000..5683afb --- /dev/null +++ b/src/main/resources/data/szar/worldgen/configured_feature/overworld_portal.json @@ -0,0 +1,4 @@ +{ + "type": "szar:overworld_portal", + "config": {} +} \ No newline at end of file diff --git a/src/main/resources/data/szar/worldgen/placed_feature/overworld_portal.json b/src/main/resources/data/szar/worldgen/placed_feature/overworld_portal.json new file mode 100644 index 0000000..7370d47 --- /dev/null +++ b/src/main/resources/data/szar/worldgen/placed_feature/overworld_portal.json @@ -0,0 +1,19 @@ +{ + "feature": "szar:overworld_portal", + "placement": [ + { + "type": "minecraft:rarity_filter", + "chance": 20 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:heightmap", + "heightmap": "MOTION_BLOCKING_NO_LEAVES" + }, + { + "type": "minecraft:biome" + } + ] +} \ No newline at end of file