diff --git a/src/main/java/net/Chipperfluff/chipi/client/hud/ChipiStatusBar.java b/src/main/java/net/Chipperfluff/chipi/client/hud/ChipiStatusBar.java index 01c595a..e4c4546 100644 --- a/src/main/java/net/Chipperfluff/chipi/client/hud/ChipiStatusBar.java +++ b/src/main/java/net/Chipperfluff/chipi/client/hud/ChipiStatusBar.java @@ -14,6 +14,7 @@ public class ChipiStatusBar { private static final int ORANGE = 0xFFFF8000; private static final int OUTLINE_LIGHT = 0xFFB0B0B0; private static final int OUTLINE_DARK = 0xFF404040; + private static final int TEXT_COLOR = 0xFFFFFFFF; private static final int BAR_HEIGHT = 6; public static void register() { @@ -33,17 +34,33 @@ public class ChipiStatusBar { int screenWidth = client.getWindow().getScaledWidth(); int screenHeight = client.getWindow().getScaledHeight(); - int barWidth = (int)(80 * 0.8f); int centerX = screenWidth / 2; - int left = centerX - barWidth / 2; - int right = left + barWidth; - int heartsY = screenHeight - 39; - int barY = heartsY - BAR_HEIGHT - 4; + // ============================================================ + // EXACT vanilla hunger bar bounds (pixel-perfect) + // ============================================================ + int hungerRight = centerX + 91; + int hungerLeft = hungerRight - 81; // vanilla width (10 * 8 + 1) + int barWidth = hungerRight - hungerLeft; + + // Base hunger Y + int hungerY = screenHeight - 39; + + // While air bar is visible, hunger (and us) move up + if (client.player.getAir() < client.player.getMaxAir()) { + hungerY -= 10; + } + + // Our bar sits directly above hunger + int barY = hungerY - BAR_HEIGHT - 2; int fillWidth = (int)(barWidth * value); - float alpha = value >= 1f ? 0.65f : + // ============================================================ + // Alpha behavior + // ============================================================ + float alpha = + value >= 1f ? 0.65f : value < 0.10f ? (float)(0.6f + 0.4f * Math.sin(System.currentTimeMillis() / 120.0)) : 1f; @@ -51,19 +68,36 @@ public class ChipiStatusBar { int outlineDark = applyAlpha(OUTLINE_DARK, alpha); int outlineLight = applyAlpha(OUTLINE_LIGHT, alpha); int fillColor = applyAlpha(ORANGE, alpha); + int textColor = applyAlpha(TEXT_COLOR, alpha); - ctx.fill(left - 1, barY - 1, right + 1, barY, outlineDark); - ctx.fill(left - 1, barY + BAR_HEIGHT, right + 1, barY + BAR_HEIGHT + 1, outlineLight); - ctx.fill(left - 1, barY, left, barY + BAR_HEIGHT, outlineDark); - ctx.fill(right, barY, right + 1, barY + BAR_HEIGHT, outlineLight); - ctx.fill(left, barY, left + fillWidth, barY + BAR_HEIGHT, fillColor); + // ============================================================ + // Draw outline + // ============================================================ + ctx.fill(hungerLeft - 1, barY - 1, hungerRight + 1, barY, outlineDark); + ctx.fill(hungerLeft - 1, barY + BAR_HEIGHT, hungerRight + 1, barY + BAR_HEIGHT + 1, outlineLight); + ctx.fill(hungerLeft - 1, barY, hungerLeft, barY + BAR_HEIGHT, outlineDark); + ctx.fill(hungerRight, barY, hungerRight + 1, barY + BAR_HEIGHT, outlineLight); + + // ============================================================ + // Draw fill + // ============================================================ + ctx.fill(hungerLeft, barY, hungerLeft + fillWidth, barY + BAR_HEIGHT, fillColor); + + // ============================================================ + // Percent text INSIDE bar, centered + // ============================================================ + String text = String.format("%03d%%", Math.round(value * 100f)); + int textWidth = client.textRenderer.getWidth(text); + + int textX = hungerLeft + (barWidth - textWidth) / 2; + int textY = barY - 1; ctx.drawText( client.textRenderer, - String.format("%03d%%", Math.round(value * 100f)), - right + 6, - barY - 2, - fillColor, + text, + textX, + textY, + textColor, true ); } diff --git a/src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java b/src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java index ea4ac78..2b2cfb1 100644 --- a/src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java +++ b/src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java @@ -5,12 +5,7 @@ import net.minecraft.block.SlabBlock; import net.minecraft.block.StairsBlock; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.ai.goal.ActiveTargetGoal; -import net.minecraft.entity.ai.goal.LookAroundGoal; -import net.minecraft.entity.ai.goal.LookAtEntityGoal; -import net.minecraft.entity.ai.goal.MeleeAttackGoal; -import net.minecraft.entity.ai.goal.SwimGoal; -import net.minecraft.entity.ai.goal.WanderAroundFarGoal; +import net.minecraft.entity.ai.goal.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; @@ -25,6 +20,7 @@ import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.Chipperfluff.chipi.armor.ProtectionAuraHandler; import net.Chipperfluff.chipi.item.ModItems; import net.Chipperfluff.chipi.sound.ModSounds; import net.Chipperfluff.chipi.util.TickScheduler; @@ -32,6 +28,7 @@ import net.Chipperfluff.chipi.util.TickScheduler; public class MepEntity extends PathAwareEntity { private static final int FORGET_TARGET_AFTER_TICKS = 100; + private static final int DESPAWN_DISTANCE = 300; private boolean angryAtPlayer = false; private int ticksSinceLastSeen = 0; @@ -56,7 +53,8 @@ public class MepEntity extends PathAwareEntity { this, PlayerEntity.class, true, - target -> target instanceof PlayerEntity player && !isPlayerProtected(player) + target -> target instanceof PlayerEntity player + && !isHardIgnored(player) ) ); } @@ -80,10 +78,28 @@ public class MepEntity extends PathAwareEntity { return super.damage(source, amount); } + // === ATTACK OVERRIDE (AURA IMMUNITY) === + + @Override + public boolean tryAttack(net.minecraft.entity.Entity target) { + if (target instanceof PlayerEntity player) { + if (ProtectionAuraHandler.hasAura(player)) { + return false; // chase but never hit + } + } + return super.tryAttack(target); + } + @Override public void tick() { super.tick(); + // --- DISTANCE DESPAWN ONLY --- + if (!this.getWorld().isClient && isTooFarFromAllPlayers()) { + this.discard(); + return; + } + LivingEntity target = this.getTarget(); if (!(target instanceof PlayerEntity player)) { @@ -92,7 +108,7 @@ public class MepEntity extends PathAwareEntity { return; } - if (isPlayerProtected(player)) { + if (isHardIgnored(player)) { clearTarget(); return; } @@ -118,7 +134,27 @@ public class MepEntity extends PathAwareEntity { this.getNavigation().stop(); } - private static boolean isPlayerProtected(PlayerEntity player) { + // === DISTANCE CHECK === + + private boolean isTooFarFromAllPlayers() { + double maxSq = DESPAWN_DISTANCE * DESPAWN_DISTANCE; + + for (PlayerEntity player : this.getWorld().getPlayers()) { + if (this.squaredDistanceTo(player) <= maxSq) { + return false; + } + } + return true; + } + + // === HARD IGNORE RULES === + + private static boolean isHardIgnored(PlayerEntity player) { + if (player.getZ() < 18) return true; + return isOnProtectedBlock(player); + } + + private static boolean isOnProtectedBlock(PlayerEntity player) { BlockPos pos = player.getBlockPos(); BlockState state = player.getWorld().getBlockState(pos); @@ -130,19 +166,7 @@ public class MepEntity extends PathAwareEntity { || state.getBlock() instanceof SlabBlock; } - // === Despawn prevention === - - @Override - public boolean cannotDespawn() { - return true; - } - - @Override - public boolean canImmediatelyDespawn(double distanceSquared) { - return false; - } - - // === MILKING (FEVER DREAM EDITION) === + // === MILKING === @Override public ActionResult interactMob(PlayerEntity player, Hand hand) { @@ -154,7 +178,6 @@ public class MepEntity extends PathAwareEntity { stack.decrement(1); player.giveItemStack(new ItemStack(ModItems.MEP_MILK)); - // ---- base sound ---- float basePitch = 0.3f + this.random.nextFloat() * 1.9f; float baseVolume = 0.9f + this.random.nextFloat() * 0.6f; @@ -167,10 +190,8 @@ public class MepEntity extends PathAwareEntity { basePitch ); - // ---- single delayed echo (10% chance) ---- if (this.random.nextFloat() < 0.10f) { - - int delay = 10 + this.random.nextInt(21); // 10–30 ticks + int delay = 10 + this.random.nextInt(21); float echoPitch = basePitch * 0.5f; float echoVolume = baseVolume * 0.5f; diff --git a/src/main/java/net/Chipperfluff/chipi/entity/SpawnLogic.java b/src/main/java/net/Chipperfluff/chipi/entity/SpawnLogic.java index 87580bf..b802018 100644 --- a/src/main/java/net/Chipperfluff/chipi/entity/SpawnLogic.java +++ b/src/main/java/net/Chipperfluff/chipi/entity/SpawnLogic.java @@ -18,9 +18,15 @@ import net.minecraft.util.math.random.Random; import net.minecraft.world.Heightmap; import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.biome.Biome; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.Box; + public final class SpawnLogic { + private static final int MAX_MEPS = 60; + private static final int SPAWN_RADIUS = 150; + private static final RegistryKey VOID_BIOME = RegistryKey.of(RegistryKeys.BIOME, new Identifier("chipi", "void")); @@ -46,16 +52,48 @@ public final class SpawnLogic { ); } - private static boolean canSpawn(EntityType type, ServerWorldAccess world, SpawnReason reason, BlockPos pos, Random random) { + private static boolean canSpawn( + EntityType type, + ServerWorldAccess world, + SpawnReason reason, + BlockPos pos, + Random random + ) { + // --- HEIGHT & Z RULES --- int y = pos.getY(); if (y < 87 || y > 90) return false; if (pos.getZ() < 18) return false; + // --- BLOCK CHECK --- BlockState below = world.getBlockState(pos.down()); - boolean can_spawn = below.isOf(Blocks.POLISHED_BLACKSTONE_BRICKS); + if (!below.isOf(Blocks.POLISHED_BLACKSTONE_BRICKS)) return false; - System.out.println("[MEP ENTITY] spawn check pos=" + pos + " below=" + below.getBlock()); + // --- GLOBAL CAP (DENY SPAWN, DO NOT DESPAWN) --- + int mepCount = world.getEntitiesByClass( + MepEntity.class, + new Box( + pos.getX() - 512, pos.getY() - 512, pos.getZ() - 512, + pos.getX() + 512, pos.getY() + 512, pos.getZ() + 512 + ), + e -> true + ).size(); - return can_spawn; + if (mepCount >= MAX_MEPS) return false; + + // --- PLAYER PROXIMITY --- + double maxSq = SPAWN_RADIUS * SPAWN_RADIUS; + + for (PlayerEntity player : world.getPlayers()) { + if (player.squaredDistanceTo( + pos.getX() + 0.5, + pos.getY(), + pos.getZ() + 0.5 + ) <= maxSq) { + return true; // ✔ valid spawn + } + } + + // No nearby player → no spawn + return false; } } diff --git a/src/main/java/net/Chipperfluff/chipi/item/ModItems.java b/src/main/java/net/Chipperfluff/chipi/item/ModItems.java index 6bf4ed6..a4e5ac3 100644 --- a/src/main/java/net/Chipperfluff/chipi/item/ModItems.java +++ b/src/main/java/net/Chipperfluff/chipi/item/ModItems.java @@ -11,8 +11,7 @@ import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; import net.Chipperfluff.chipi.item.tool.ChipperToolMaterial; import net.Chipperfluff.chipi.item.MepMilkItem; -import net.minecraft.item.Items; -import net.Chipperfluff.chipi.item.armor.ChipperArmorItem; + public class ModItems { @@ -95,25 +94,25 @@ public class ModItems { public static final Item CHIPPER_HELMET = Registry.register( Registries.ITEM, new Identifier(ChipiMod.MOD_ID, "chipper_helmet"), - new ChipperArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.HELMET, new Item.Settings()) + new ArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.HELMET, new Item.Settings()) ); public static final Item CHIPPER_CHESTPLATE = Registry.register( Registries.ITEM, new Identifier(ChipiMod.MOD_ID, "chipper_chestplate"), - new ChipperArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.CHESTPLATE, new Item.Settings()) + new ArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.CHESTPLATE, new Item.Settings()) ); public static final Item CHIPPER_LEGGINGS = Registry.register( Registries.ITEM, new Identifier(ChipiMod.MOD_ID, "chipper_leggings"), - new ChipperArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.LEGGINGS, new Item.Settings()) + new ArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.LEGGINGS, new Item.Settings()) ); public static final Item CHIPPER_BOOTS = Registry.register( Registries.ITEM, new Identifier(ChipiMod.MOD_ID, "chipper_boots"), - new ChipperArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.BOOTS, new Item.Settings()) + new ArmorItem(ChipperArmorMaterial.INSTANCE, ArmorItem.Type.BOOTS, new Item.Settings()) ); // ===== TOOLS ===== diff --git a/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorItem.java b/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorItem.java deleted file mode 100644 index 7704948..0000000 --- a/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorItem.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.Chipperfluff.chipi.item.armor; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.EquipmentSlot; -import net.minecraft.item.ArmorItem; -import net.minecraft.item.ArmorMaterial; -import net.minecraft.item.ItemStack; -import net.minecraft.world.World; - -public class ChipperArmorItem extends ArmorItem { - - public ChipperArmorItem( - ArmorMaterial material, - Type type, - Settings settings - ) { - super(material, type, settings); - } - - @Override - public void inventoryTick( - ItemStack stack, - World world, - Entity entity, - int slot, - boolean selected - ) { - if (slot >= EquipmentSlot.FEET.getEntitySlotId() - && slot <= EquipmentSlot.HEAD.getEntitySlotId()) { - - if (stack.getDamage() != 0) { - stack.setDamage(0); - } - } - } -} diff --git a/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorMaterial.java b/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorMaterial.java index d8ae7f9..65976cf 100644 --- a/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorMaterial.java +++ b/src/main/java/net/Chipperfluff/chipi/item/armor/ChipperArmorMaterial.java @@ -27,7 +27,7 @@ public class ChipperArmorMaterial implements ArmorMaterial { @Override public int getDurability(ArmorItem.Type type) { - return 10_000; + return 1_000; } @Override diff --git a/src/main/java/net/Chipperfluff/chipi/item/armor/ProtectionAuraHandler.java b/src/main/java/net/Chipperfluff/chipi/item/armor/ProtectionAuraHandler.java new file mode 100644 index 0000000..89be409 --- /dev/null +++ b/src/main/java/net/Chipperfluff/chipi/item/armor/ProtectionAuraHandler.java @@ -0,0 +1,240 @@ +package net.Chipperfluff.chipi.armor; + +import net.Chipperfluff.chipi.item.ModItems; +import net.minecraft.block.BlockState; +import net.minecraft.block.SlabBlock; +import net.minecraft.block.StairsBlock; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.state.property.Properties; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import static net.Chipperfluff.chipi.util.ChipiTrackedData.CHIPI_ENERGY; +import static net.Chipperfluff.chipi.server.ChipiServerEvents.CHIPI_DIMENSION_KEY; + +public final class ProtectionAuraHandler { + + private static final float BASE_RECHARGE_RATE = 0.0005f; + private static final float BASE_DRAIN_RATE = 0.0008f; + + private static final float CASCADE_LOSS = 0.30f; + private static final int CRITICAL_PCT = 10; + + private ProtectionAuraHandler() {} + + /* ========================================================== + ENTRY POINT + ========================================================== */ + + public static void tick(PlayerEntity player) { + if (!hasFullChipperArmor(player)) return; + + Float energy = player.getDataTracker().get(CHIPI_ENERGY); + if (energy == null) return; + + float durabilityFactor = getDurabilityFactor(player); + if (durabilityFactor <= 0f) return; + + float nextEnergy = calculateNextEnergy(player, energy, durabilityFactor); + if (nextEnergy == energy) return; + + applyEnergyDelta(player, energy, nextEnergy); + player.getDataTracker().set(CHIPI_ENERGY, nextEnergy); + } + + /* ========================================================== + ENERGY + ========================================================== */ + + private static float calculateNextEnergy(PlayerEntity player, float current, float durabilityFactor) { + boolean recharge = !isInChipi(player.getWorld()) || isOnProtectedBlock(player); + + float rate = recharge + ? BASE_RECHARGE_RATE * durabilityFactor + : BASE_DRAIN_RATE * (1.0f + (1.0f - durabilityFactor)); + + return recharge + ? Math.min(1.0f, current + rate) + : Math.max(0.0f, current - rate); + } + + private static void applyEnergyDelta(PlayerEntity player, float before, float after) { + int oldPct = (int) (before * 100f); + int newPct = (int) (after * 100f); + int delta = Math.abs(newPct - oldPct); + + if (delta > 0) { + applyArmorDamage(player, delta); + } + } + + /* ========================================================== + ARMOR DAMAGE + ========================================================== */ + + private static void applyArmorDamage(PlayerEntity player, int amount) { + int[] before = getArmorPercents(player); + boolean broke = damageAllPieces(player, amount); + + if (broke) { + handleCascade(player, before); + } else { + handleWarnings(player, before, getArmorPercents(player)); + } + } + + private static boolean damageAllPieces(PlayerEntity player, int amount) { + boolean broke = false; + + for (ItemStack stack : player.getArmorItems()) { + if (stack.isEmpty()) continue; + + stack.damage(amount, player, p -> {}); + if (stack.getDamage() >= stack.getMaxDamage()) { + broke = true; + } + } + return broke; + } + + /* ========================================================== + CASCADE + ========================================================== */ + + private static void handleCascade(PlayerEntity player, int[] before) { + applyCascadeLoss(player); + player.getDataTracker().set(CHIPI_ENERGY, 0f); + sendCollapseMessage(player, before, getArmorPercents(player)); + } + + private static void applyCascadeLoss(PlayerEntity player) { + for (ItemStack stack : player.getArmorItems()) { + if (stack.isEmpty()) continue; + + int max = stack.getMaxDamage(); + int remaining = max - stack.getDamage(); + if (remaining <= 0) continue; + + int extra = Math.round(remaining * CASCADE_LOSS); + stack.setDamage(Math.min(max, stack.getDamage() + extra)); + } + } + + /* ========================================================== + WARNINGS + ========================================================== */ + + private static void handleWarnings(PlayerEntity player, int[] before, int[] after) { + if (!enteredCritical(before, after)) return; + player.sendMessage(Text.literal(buildWarningMessage(after)), false); + } + + private static boolean enteredCritical(int[] before, int[] after) { + for (int i = 0; i < 4; i++) { + if (before[i] > CRITICAL_PCT && after[i] <= CRITICAL_PCT) { + return true; + } + } + return false; + } + + /* ========================================================== + CHAT BUILDERS + ========================================================== */ + + private static String buildWarningMessage(int[] pct) { + StringBuilder sb = new StringBuilder("§6[AURA WARNING]\n"); + appendPiece(sb, "Head", pct[3]); + appendPiece(sb, "Body", pct[2]); + appendPiece(sb, "Legs", pct[1]); + appendPiece(sb, "Feet", pct[0]); + return sb.toString(); + } + + private static void sendCollapseMessage(PlayerEntity player, int[] before, int[] after) { + StringBuilder sb = new StringBuilder("§c[AURA COLLAPSE]\n"); + appendPiece(sb, "Head", before[3], after[3]); + appendPiece(sb, "Body", before[2], after[2]); + appendPiece(sb, "Legs", before[1], after[1]); + appendPiece(sb, "Feet", before[0], after[0]); + player.sendMessage(Text.literal(sb.toString()), false); + } + + private static void appendPiece(StringBuilder sb, String name, int pct) { + sb.append("§7").append(name).append(": ").append(pct).append("%"); + if (pct <= CRITICAL_PCT) sb.append(" §c!!!"); + sb.append("\n"); + } + + private static void appendPiece(StringBuilder sb, String name, int before, int after) { + sb.append("§7").append(name).append(": ") + .append(after).append("% (was ").append(before).append("%)\n"); + } + + /* ========================================================== + UTIL + ========================================================== */ + + private static int[] getArmorPercents(PlayerEntity player) { + int[] out = new int[4]; + int i = 0; + + for (ItemStack stack : player.getArmorItems()) { + if (stack.isEmpty()) { + out[i++] = 0; + } else { + int max = stack.getMaxDamage(); + int cur = max - stack.getDamage(); + out[i++] = Math.max(0, (int) ((cur / (float) max) * 100f)); + } + } + return out; + } + + private static float getDurabilityFactor(PlayerEntity player) { + int max = 0, cur = 0; + + for (ItemStack stack : player.getArmorItems()) { + if (!stack.isEmpty()) { + max += stack.getMaxDamage(); + cur += stack.getMaxDamage() - stack.getDamage(); + } + } + return max <= 0 ? 0f : Math.min(1f, (float) cur / max); + } + + /* ========================================================== + CONDITIONS + ========================================================== */ + + public static boolean hasFullChipperArmor(PlayerEntity player) { + PlayerInventory inv = player.getInventory(); + return inv.getArmorStack(3).isOf(ModItems.CHIPPER_HELMET) + && inv.getArmorStack(2).isOf(ModItems.CHIPPER_CHESTPLATE) + && inv.getArmorStack(1).isOf(ModItems.CHIPPER_LEGGINGS) + && inv.getArmorStack(0).isOf(ModItems.CHIPPER_BOOTS); + } + + private static boolean isOnProtectedBlock(PlayerEntity player) { + BlockPos pos = player.getBlockPos(); + BlockState state = player.getWorld().getBlockState(pos); + + return state.contains(Properties.WATERLOGGED) + && state.get(Properties.WATERLOGGED) + && (state.getBlock() instanceof StairsBlock + || state.getBlock() instanceof SlabBlock); + } + + private static boolean isInChipi(World world) { + return world.getRegistryKey().equals(CHIPI_DIMENSION_KEY); + } + + public static boolean hasAura(PlayerEntity player) { + if (!hasFullChipperArmor(player)) return false; + Float v = player.getDataTracker().get(CHIPI_ENERGY); + return v != null && v > 0f && getDurabilityFactor(player) > 0f; + } +} diff --git a/src/main/java/net/Chipperfluff/chipi/server/ChipiServerEvents.java b/src/main/java/net/Chipperfluff/chipi/server/ChipiServerEvents.java index e116ef5..bc79f66 100644 --- a/src/main/java/net/Chipperfluff/chipi/server/ChipiServerEvents.java +++ b/src/main/java/net/Chipperfluff/chipi/server/ChipiServerEvents.java @@ -1,17 +1,13 @@ package net.Chipperfluff.chipi.server; import net.Chipperfluff.chipi.SpawnPlacedState; +import net.Chipperfluff.chipi.armor.ProtectionAuraHandler; import net.Chipperfluff.chipi.block.ChipperPortalBlock; -import net.Chipperfluff.chipi.item.ModItems; import net.Chipperfluff.chipi.world.gen.ChipiDungeonGenerator; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; -import net.minecraft.block.BlockState; -import net.minecraft.block.SlabBlock; -import net.minecraft.block.StairsBlock; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; import net.minecraft.server.MinecraftServer; @@ -19,24 +15,18 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.structure.StructurePlacementData; import net.minecraft.structure.StructureTemplate; -import net.minecraft.state.property.Properties; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.world.GameRules; import net.minecraft.world.World; -import static net.Chipperfluff.chipi.util.ChipiTrackedData.CHIPI_ENERGY; - public final class ChipiServerEvents { public static final RegistryKey CHIPI_DIMENSION_KEY = - RegistryKey.of(RegistryKeys.WORLD, new Identifier("chipi", "chipi_dimension")); - - private static final float RECHARGE_RATE = 0.0005f; - private static final float DRAIN_RATE = 0.0008f; + RegistryKey.of(RegistryKeys.WORLD, new Identifier("chipi", "chipi_dimension")); private static final Identifier SPAWN_STRUCTURE = - new Identifier("chipi", "spawn"); + new Identifier("chipi", "spawn"); private static MinecraftServer SERVER; @@ -44,33 +34,14 @@ public final class ChipiServerEvents { public static void register() { ServerLifecycleEvents.SERVER_STARTED.register(server -> SERVER = server); - ServerTickEvents.END_SERVER_TICK.register(ChipiServerEvents::tickEnergy); + ServerTickEvents.END_SERVER_TICK.register(ChipiServerEvents::tickPlayers); ServerTickEvents.END_WORLD_TICK.register(ChipiServerEvents::handleVoidFailsafe); ServerWorldEvents.LOAD.register(ChipiServerEvents::onWorldLoad); } - private static void tickEnergy(MinecraftServer server) { + private static void tickPlayers(MinecraftServer server) { for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) { - - if (!hasFullChipperArmor(player)) continue; - - Float value = player.getDataTracker().get(CHIPI_ENERGY); - if (value == null) continue; // ultra-safe, but should never happen now - - boolean inChipi = player.getWorld().getRegistryKey().equals(CHIPI_DIMENSION_KEY); - boolean onProtected = isOnProtectedBlock(player); - - float next = value; - - if (!inChipi || onProtected) { - next = Math.min(1.0f, value + RECHARGE_RATE); - } else { - next = Math.max(0.0f, value - DRAIN_RATE); - } - - if (next != value) { - player.getDataTracker().set(CHIPI_ENERGY, next); - } + ProtectionAuraHandler.tick(player); } } @@ -91,31 +62,23 @@ public final class ChipiServerEvents { world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(false, server); SpawnPlacedState state = world.getPersistentStateManager().getOrCreate( - SpawnPlacedState::fromNbt, - SpawnPlacedState::new, - "chipi_spawn" + SpawnPlacedState::fromNbt, + SpawnPlacedState::new, + "chipi_spawn" ); if (state.placed) return; - StructureTemplate spawnTemplate = - world.getStructureTemplateManager().getTemplate(SPAWN_STRUCTURE).orElse(null); + StructureTemplate template = + world.getStructureTemplateManager().getTemplate(SPAWN_STRUCTURE).orElse(null); - if (spawnTemplate == null) return; + if (template == null) return; - BlockPos spawnCenter = new BlockPos(0, 80, 0); + BlockPos spawn = new BlockPos(0, 80, 0); - spawnTemplate.place( - world, - spawnCenter, - spawnCenter, - new StructurePlacementData(), - world.getRandom(), - 2 - ); - - world.setSpawnPos(spawnCenter.up(), 0.0f); - ChipiDungeonGenerator.generateInitialLayout(world, spawnCenter); + template.place(world, spawn, spawn, new StructurePlacementData(), world.getRandom(), 2); + world.setSpawnPos(spawn.up(), 0f); + ChipiDungeonGenerator.generateInitialLayout(world, spawn); state.placed = true; state.markDirty(); @@ -124,24 +87,4 @@ public final class ChipiServerEvents { public static ServerWorld getChipiWorld() { return SERVER == null ? null : SERVER.getWorld(CHIPI_DIMENSION_KEY); } - - private static boolean hasFullChipperArmor(PlayerEntity player) { - PlayerInventory inv = player.getInventory(); - return inv.getArmorStack(3).isOf(ModItems.CHIPPER_HELMET) - && inv.getArmorStack(2).isOf(ModItems.CHIPPER_CHESTPLATE) - && inv.getArmorStack(1).isOf(ModItems.CHIPPER_LEGGINGS) - && inv.getArmorStack(0).isOf(ModItems.CHIPPER_BOOTS); - } - - private static boolean isOnProtectedBlock(PlayerEntity player) { - BlockPos pos = player.getBlockPos(); - BlockState state = player.getWorld().getBlockState(pos); - - if (!state.contains(Properties.WATERLOGGED) || !state.get(Properties.WATERLOGGED)) { - return false; - } - - return state.getBlock() instanceof StairsBlock - || state.getBlock() instanceof SlabBlock; - } }