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 0000000..c519712 Binary files /dev/null and b/src/main/resources/assets/szar/textures/item/bean.png differ 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 0000000..8aa5699 Binary files /dev/null and b/src/main/resources/assets/szar/textures/item/can_of_beans.png differ 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