barrels
This commit is contained in:
@@ -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
|
||||
|
||||
215
src/main/java/dev/tggamesyt/szar/BackroomsBarrelManager.java
Normal file
215
src/main/java/dev/tggamesyt/szar/BackroomsBarrelManager.java
Normal file
@@ -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<UUID, Double> lastX = new HashMap<>();
|
||||
private static final Map<UUID, Double> lastZ = new HashMap<>();
|
||||
private static final Map<UUID, Double> walkAccumulator = new HashMap<>();
|
||||
private static final Map<UUID, Integer> walkThreshold = new HashMap<>();
|
||||
private static final Map<UUID, Set<BlockPos>> trackerBarrels = new HashMap<>();
|
||||
private static final Map<UUID, Set<BlockPos>> 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<BarrelBlockEntity> nearby = getNearbyBarrels(backrooms, player, 16);
|
||||
if (!nearby.isEmpty()) {
|
||||
Set<BlockPos> 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<BarrelBlockEntity> nearby = getNearbyBarrels(backrooms, player, 16);
|
||||
if (!nearby.isEmpty()) {
|
||||
Set<BlockPos> 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<UUID> 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<BlockPos> 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<BlockPos> 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<BarrelBlockEntity> getNearbyBarrels(ServerWorld world,
|
||||
ServerPlayerEntity player,
|
||||
int radius) {
|
||||
List<BarrelBlockEntity> 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);
|
||||
}
|
||||
}
|
||||
@@ -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,33 +245,42 @@ 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);
|
||||
}
|
||||
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) {
|
||||
}
|
||||
|
||||
// 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();
|
||||
@@ -274,21 +288,4 @@ public class BackroomsChunkGenerator extends ChunkGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user