From 4f455ead5f3e97c673fd3f2fe092c26a9f571e60 Mon Sep 17 00:00:00 2001 From: TGGamesYT Date: Wed, 18 Mar 2026 18:29:31 +0100 Subject: [PATCH] barrels --- gradle.properties | 2 +- .../szar/BackroomsBarrelManager.java | 215 ++++++++++++++++++ .../szar/BackroomsChunkGenerator.java | 69 +++--- src/main/java/dev/tggamesyt/szar/Szar.java | 1 + 4 files changed, 250 insertions(+), 37 deletions(-) create mode 100644 src/main/java/dev/tggamesyt/szar/BackroomsBarrelManager.java diff --git a/gradle.properties b/gradle.properties index 28d7946..a9f9785 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.2 +mod_version=26.3.18.3 maven_group=dev.tggamesyt archives_base_name=szar # Dependencies diff --git a/src/main/java/dev/tggamesyt/szar/BackroomsBarrelManager.java b/src/main/java/dev/tggamesyt/szar/BackroomsBarrelManager.java new file mode 100644 index 0000000..c297524 --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/BackroomsBarrelManager.java @@ -0,0 +1,215 @@ +package dev.tggamesyt.szar; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.block.entity.BarrelBlockEntity; +import net.minecraft.entity.player.HungerManager; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; + +import java.util.*; + +public class BackroomsBarrelManager { + + private static final Map lastX = new HashMap<>(); + private static final Map lastZ = new HashMap<>(); + private static final Map walkAccumulator = new HashMap<>(); + private static final Map walkThreshold = new HashMap<>(); + private static final Map> trackerBarrels = new HashMap<>(); + private static final Map> foodBarrels = new HashMap<>(); + + public static void register() { + ServerTickEvents.END_SERVER_TICK.register(BackroomsBarrelManager::tick); + } + + private static void tick(MinecraftServer server) { + ServerWorld backrooms = server.getWorld(Szar.BACKROOMS_KEY); + if (backrooms == null) return; + + for (ServerPlayerEntity player : backrooms.getPlayers()) { + UUID uuid = player.getUuid(); + + // --- Walk tracking --- + double px = player.getX(); + double pz = player.getZ(); + + if (lastX.containsKey(uuid)) { + double dx = px - lastX.get(uuid); + double dz = pz - lastZ.get(uuid); + double dist = Math.sqrt(dx * dx + dz * dz); + walkAccumulator.merge(uuid, dist, Double::sum); + } + lastX.put(uuid, px); + lastZ.put(uuid, pz); + + if (!walkThreshold.containsKey(uuid)) { + walkThreshold.put(uuid, randomThreshold(backrooms.random)); + } + + // --- Check if tracker barrels need clearing --- + if (trackerBarrels.containsKey(uuid)) { + checkAndClearTrackerBarrels(backrooms, uuid); + } + + // --- Check if food barrels need clearing --- + if (foodBarrels.containsKey(uuid)) { + checkAndClearFoodBarrels(backrooms, uuid); + } + + // --- Hunger check (every 20 ticks) --- + if (backrooms.getTime() % 20 == 0) { + HungerManager hunger = player.getHungerManager(); + if (hunger.getFoodLevel() <= 10 && !hasAnyFood(player)) { + if (!foodBarrels.containsKey(uuid)) { + List nearby = getNearbyBarrels(backrooms, player, 16); + if (!nearby.isEmpty()) { + Set positions = new HashSet<>(); + for (BarrelBlockEntity barrel : nearby) { + placeItemInBarrel(barrel, new ItemStack(Szar.CAN_OF_BEANS)); + positions.add(barrel.getPos().toImmutable()); + } + foodBarrels.put(uuid, positions); + } + } + } + } + + // --- Walk threshold check --- + double walked = walkAccumulator.getOrDefault(uuid, 0.0); + if (walked >= walkThreshold.getOrDefault(uuid, 500)) { + List nearby = getNearbyBarrels(backrooms, player, 16); + if (!nearby.isEmpty()) { + Set positions = new HashSet<>(); + for (BarrelBlockEntity barrel : nearby) { + placeItemInBarrel(barrel, new ItemStack(Szar.TRACKER_BLOCK_ITEM)); + positions.add(barrel.getPos().toImmutable()); + } + trackerBarrels.put(uuid, positions); + } + walkAccumulator.put(uuid, 0.0); + walkThreshold.put(uuid, randomThreshold(backrooms.random)); + } + } + + // Clean up data for players no longer in backrooms + Set activePlayers = new HashSet<>(); + for (ServerPlayerEntity p : backrooms.getPlayers()) activePlayers.add(p.getUuid()); + lastX.keySet().retainAll(activePlayers); + lastZ.keySet().retainAll(activePlayers); + walkAccumulator.keySet().retainAll(activePlayers); + walkThreshold.keySet().retainAll(activePlayers); + foodBarrels.keySet().retainAll(activePlayers); + trackerBarrels.keySet().retainAll(activePlayers); + } + + private static void checkAndClearTrackerBarrels(ServerWorld world, UUID uuid) { + Set positions = trackerBarrels.get(uuid); + if (positions == null) return; + + boolean anyTaken = false; + for (BlockPos pos : positions) { + if (world.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) { + if (!barrelHasItem(barrel, Szar.TRACKER_BLOCK_ITEM.asItem())) { + anyTaken = true; + break; + } + } + } + + if (anyTaken) { + for (BlockPos pos : positions) { + if (world.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) { + removeItemFromBarrel(barrel, Szar.TRACKER_BLOCK_ITEM.asItem()); + } + } + trackerBarrels.remove(uuid); + } + } + + private static void checkAndClearFoodBarrels(ServerWorld world, UUID uuid) { + Set positions = foodBarrels.get(uuid); + if (positions == null) return; + + boolean anyTaken = false; + for (BlockPos pos : positions) { + if (world.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) { + if (!barrelHasItem(barrel, Szar.CAN_OF_BEANS.asItem())) { + anyTaken = true; + break; + } + } + } + + if (anyTaken) { + for (BlockPos pos : positions) { + if (world.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) { + removeItemFromBarrel(barrel, Szar.CAN_OF_BEANS.asItem()); + } + } + foodBarrels.remove(uuid); + } + } + + private static boolean barrelHasItem(BarrelBlockEntity barrel, Item item) { + for (int i = 0; i < barrel.size(); i++) { + if (barrel.getStack(i).isOf(item)) return true; + } + return false; + } + + private static void removeItemFromBarrel(BarrelBlockEntity barrel, Item item) { + for (int i = 0; i < barrel.size(); i++) { + if (barrel.getStack(i).isOf(item)) { + barrel.setStack(i, ItemStack.EMPTY); + barrel.markDirty(); + return; + } + } + } + + private static boolean hasAnyFood(ServerPlayerEntity player) { + for (int i = 0; i < player.getInventory().size(); i++) { + ItemStack stack = player.getInventory().getStack(i); + if (!stack.isEmpty() && (stack.isFood() + || stack.isOf(Szar.CAN_OF_BEANS))) { + return true; + } + } + return false; + } + + private static void placeItemInBarrel(BarrelBlockEntity barrel, ItemStack item) { + for (int i = 0; i < barrel.size(); i++) { + if (barrel.getStack(i).isEmpty()) { + barrel.setStack(i, item.copy()); + barrel.markDirty(); + return; + } + } + } + + private static List getNearbyBarrels(ServerWorld world, + ServerPlayerEntity player, + int radius) { + List result = new ArrayList<>(); + Box box = player.getBoundingBox().expand(radius); + + BlockPos min = BlockPos.ofFloored(box.minX, box.minY, box.minZ); + BlockPos max = BlockPos.ofFloored(box.maxX, box.maxY, box.maxZ); + + for (BlockPos pos : BlockPos.iterate(min, max)) { + if (world.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) { + result.add(barrel); + } + } + return result; + } + + private static int randomThreshold(net.minecraft.util.math.random.Random random) { + return 500 + random.nextInt(501); + } +} \ 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 99c081d..19bf86a 100644 --- a/src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java +++ b/src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java @@ -101,11 +101,18 @@ public class BackroomsChunkGenerator extends ChunkGenerator { } if (isOpen) { - // Air inside the room for (int y = WALL_BASE_Y; y <= WALL_TOP_Y; y++) { chunk.setBlockState(new BlockPos(lx, y, lz), Blocks.AIR.getDefaultState(), false); } + + // 1 in 40 chance of a barrel on the floor + // With this — 1 per ~40x40 block area: + long barrelHash = hash(worldX * 31 + 17, worldZ * 29 + 11); + if ((barrelHash % 1600) == 0) { + chunk.setBlockState(new BlockPos(lx, FLOOR_Y + 1, lz), + Blocks.BARREL.getDefaultState(), false); + } } else { // Wall column chunk.setBlockState(new BlockPos(lx, WALL_BASE_Y, lz), @@ -115,8 +122,6 @@ public class BackroomsChunkGenerator extends ChunkGenerator { Szar.WALL_BLOCK.getDefaultState(), false); } } - // After the lx/lz loop, still inside populateNoise: - placeBackroomsPortals(chunk, chunkX, chunkZ); } } @@ -240,55 +245,47 @@ public class BackroomsChunkGenerator extends ChunkGenerator { @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(); + // Initialize wall block entities 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); - } + world.setBlockState(mutable, Szar.WALL_BLOCK.getDefaultState(), + Block.NOTIFY_ALL); 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(); - } + } + } + + // Place tracker portals + long chunkHash = hash((chunkX / 16) * 7 + 3, (chunkZ / 16) * 13 + 7); + if ((chunkHash % 20) == 0) { + int lx = 4 + (int)(chunkHash >> 8 & 0x7); + int lz = 4 + (int)(chunkHash >> 12 & 0x7); + + if (isOpenSpace(chunkX + lx, chunkZ + lz)) { + BlockPos trackerPos = new BlockPos(chunkX + lx, FLOOR_Y + 1, chunkZ + lz); + BlockPos portalPos = trackerPos.down(4); + + world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState(), + Block.NOTIFY_ALL); + world.setBlockState(trackerPos, Szar.TRACKER_BLOCK.getDefaultState(), + Block.NOTIFY_ALL); + + if (world.getBlockEntity(trackerPos) 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; - - BlockPos trackerPos = new BlockPos(lx, FLOOR_Y + 1, lz); // Y=5 - BlockPos portalPos = trackerPos.down(4); // Y=1, underground - - 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/Szar.java b/src/main/java/dev/tggamesyt/szar/Szar.java index efc1398..fcc79bd 100644 --- a/src/main/java/dev/tggamesyt/szar/Szar.java +++ b/src/main/java/dev/tggamesyt/szar/Szar.java @@ -1087,6 +1087,7 @@ public class Szar implements ModInitializer { RegistryKey.of(RegistryKeys.PLACED_FEATURE, new Identifier(MOD_ID, "overworld_portal")) ); + BackroomsBarrelManager.register(); } // Blocks public static final TrackerBlock TRACKER_BLOCK = Registry.register(