Refactor ProtectionAuraHandler: improve energy calculation and armor damage handling

This commit is contained in:
Chipperfluff 2025-12-19 23:53:30 +01:00
parent 4d35361b28
commit ed8c4433be

View File

@ -20,147 +20,149 @@ public final class ProtectionAuraHandler {
private static final float BASE_RECHARGE_RATE = 0.0005f; private static final float BASE_RECHARGE_RATE = 0.0005f;
private static final float BASE_DRAIN_RATE = 0.0008f; private static final float BASE_DRAIN_RATE = 0.0008f;
private static final float CASCADE_LOSS = 0.30f; // 30% relative private static final float CASCADE_LOSS = 0.30f;
private static final int CRITICAL_PCT = 10; private static final int CRITICAL_PCT = 10;
private ProtectionAuraHandler() {} private ProtectionAuraHandler() {}
/* ========================================================== /* ==========================================================
ENTRY POINT SERVER SIDE ENTRY POINT
========================================================== */ ========================================================== */
public static void tick(PlayerEntity player) { public static void tick(PlayerEntity player) {
if (!hasFullChipperArmor(player)) return; if (!hasFullChipperArmor(player)) return;
Float value = player.getDataTracker().get(CHIPI_ENERGY); Float energy = player.getDataTracker().get(CHIPI_ENERGY);
if (value == null) return; if (energy == null) return;
float durabilityFactor = getDurabilityFactor(player); float durabilityFactor = getDurabilityFactor(player);
if (durabilityFactor <= 0f) return; if (durabilityFactor <= 0f) return;
boolean inChipi = isInChipi(player.getWorld()); float nextEnergy = calculateNextEnergy(player, energy, durabilityFactor);
boolean protectedAura = isOnProtectedBlock(player); if (nextEnergy == energy) return;
float rechargeRate = BASE_RECHARGE_RATE * durabilityFactor; applyEnergyDelta(player, energy, nextEnergy);
float drainRate = BASE_DRAIN_RATE * (1.0f + (1.0f - durabilityFactor)); player.getDataTracker().set(CHIPI_ENERGY, nextEnergy);
}
float next = (!inChipi || protectedAura) /* ==========================================================
? Math.min(1.0f, value + rechargeRate) ENERGY
: Math.max(0.0f, value - drainRate); ========================================================== */
if (next == value) return; private static float calculateNextEnergy(PlayerEntity player, float current, float durabilityFactor) {
boolean recharge = !isInChipi(player.getWorld()) || isOnProtectedBlock(player);
int oldPercent = (int) (value * 100f); float rate = recharge
int newPercent = (int) (next * 100f); ? BASE_RECHARGE_RATE * durabilityFactor
int delta = Math.abs(newPercent - oldPercent); : 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) { if (delta > 0) {
damageArmor(player, delta); applyArmorDamage(player, delta);
} }
player.getDataTracker().set(CHIPI_ENERGY, next);
} }
/* ========================================================== /* ==========================================================
ARMOR CHECK ARMOR DAMAGE
========================================================== */ ========================================================== */
public static boolean hasFullChipperArmor(PlayerEntity player) { private static void applyArmorDamage(PlayerEntity player, int amount) {
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);
}
/* ==========================================================
DURABILITY LOGIC
========================================================== */
private static float getDurabilityFactor(PlayerEntity player) {
int max = 0, current = 0;
for (ItemStack stack : player.getArmorItems()) {
if (!stack.isEmpty()) {
max += stack.getMaxDamage();
current += stack.getMaxDamage() - stack.getDamage();
}
}
if (max <= 0) return 0f;
return Math.min(1f, (float) current / max);
}
private static void damageArmor(PlayerEntity player, int amount) {
int[] before = getArmorPercents(player); 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; boolean broke = false;
for (ItemStack stack : player.getArmorItems()) {
if (!stack.isEmpty()) {
stack.damage(amount, player, p -> {});
if (stack.getDamage() >= stack.getMaxDamage()) {
broke = true;
}
}
}
if (broke) {
applyCascadeDamage(player, before);
} else {
sendWarningIfNeeded(player, before, getArmorPercents(player));
}
}
private static void applyCascadeDamage(PlayerEntity player, int[] before) {
for (ItemStack stack : player.getArmorItems()) { for (ItemStack stack : player.getArmorItems()) {
if (stack.isEmpty()) continue; if (stack.isEmpty()) continue;
int max = stack.getMaxDamage(); stack.damage(amount, player, p -> {});
int current = max - stack.getDamage(); if (stack.getDamage() >= stack.getMaxDamage()) {
if (current <= 0) continue; broke = true;
}
int extra = Math.round(current * CASCADE_LOSS);
stack.setDamage(Math.min(max, stack.getDamage() + extra));
} }
return broke;
}
/* ==========================================================
CASCADE
========================================================== */
private static void handleCascade(PlayerEntity player, int[] before) {
applyCascadeLoss(player);
player.getDataTracker().set(CHIPI_ENERGY, 0f); player.getDataTracker().set(CHIPI_ENERGY, 0f);
sendCollapseMessage(player, before, getArmorPercents(player)); 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));
}
}
/* ========================================================== /* ==========================================================
CHAT MESSAGES (PLAYER ONLY) WARNINGS
========================================================== */ ========================================================== */
private static void sendWarningIfNeeded(PlayerEntity player, int[] before, int[] after) { private static void handleWarnings(PlayerEntity player, int[] before, int[] after) {
boolean trigger = false; 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++) { for (int i = 0; i < 4; i++) {
if (before[i] > CRITICAL_PCT && after[i] <= CRITICAL_PCT) { if (before[i] > CRITICAL_PCT && after[i] <= CRITICAL_PCT) {
trigger = true; return true;
} }
} }
if (!trigger) return; return false;
}
player.sendMessage(Text.literal(buildWarningMessage(after)), 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) { private static void sendCollapseMessage(PlayerEntity player, int[] before, int[] after) {
StringBuilder sb = new StringBuilder("§c[AURA COLLAPSE]\n"); StringBuilder sb = new StringBuilder("§c[AURA COLLAPSE]\n");
appendPiece(sb, "Head", before[3], after[3]); appendPiece(sb, "Head", before[3], after[3]);
appendPiece(sb, "Body", before[2], after[2]); appendPiece(sb, "Body", before[2], after[2]);
appendPiece(sb, "Legs", before[1], after[1]); appendPiece(sb, "Legs", before[1], after[1]);
appendPiece(sb, "Feet", before[0], after[0]); appendPiece(sb, "Feet", before[0], after[0]);
player.sendMessage(Text.literal(sb.toString()), false); player.sendMessage(Text.literal(sb.toString()), false);
} }
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 appendPiece(StringBuilder sb, String name, int pct) { private static void appendPiece(StringBuilder sb, String name, int pct) {
sb.append("§7").append(name).append(": ").append(pct).append("%"); sb.append("§7").append(name).append(": ").append(pct).append("%");
if (pct <= CRITICAL_PCT) sb.append(" §c!!!"); if (pct <= CRITICAL_PCT) sb.append(" §c!!!");
@ -172,9 +174,14 @@ public final class ProtectionAuraHandler {
.append(after).append("% (was ").append(before).append("%)\n"); .append(after).append("% (was ").append(before).append("%)\n");
} }
/* ==========================================================
UTIL
========================================================== */
private static int[] getArmorPercents(PlayerEntity player) { private static int[] getArmorPercents(PlayerEntity player) {
int[] out = new int[4]; int[] out = new int[4];
int i = 0; int i = 0;
for (ItemStack stack : player.getArmorItems()) { for (ItemStack stack : player.getArmorItems()) {
if (stack.isEmpty()) { if (stack.isEmpty()) {
out[i++] = 0; out[i++] = 0;
@ -187,20 +194,38 @@ public final class ProtectionAuraHandler {
return out; 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);
}
/* ========================================================== /* ==========================================================
AURA CONDITIONS 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) { private static boolean isOnProtectedBlock(PlayerEntity player) {
BlockPos pos = player.getBlockPos(); BlockPos pos = player.getBlockPos();
BlockState state = player.getWorld().getBlockState(pos); BlockState state = player.getWorld().getBlockState(pos);
if (!state.contains(Properties.WATERLOGGED) || !state.get(Properties.WATERLOGGED)) { return state.contains(Properties.WATERLOGGED)
return false; && state.get(Properties.WATERLOGGED)
} && (state.getBlock() instanceof StairsBlock
|| state.getBlock() instanceof SlabBlock);
return state.getBlock() instanceof StairsBlock
|| state.getBlock() instanceof SlabBlock;
} }
private static boolean isInChipi(World world) { private static boolean isInChipi(World world) {
@ -209,7 +234,7 @@ public final class ProtectionAuraHandler {
public static boolean hasAura(PlayerEntity player) { public static boolean hasAura(PlayerEntity player) {
if (!hasFullChipperArmor(player)) return false; if (!hasFullChipperArmor(player)) return false;
Float value = player.getDataTracker().get(CHIPI_ENERGY); Float v = player.getDataTracker().get(CHIPI_ENERGY);
return value != null && value > 0f && getDurabilityFactor(player) > 0f; return v != null && v > 0f && getDurabilityFactor(player) > 0f;
} }
} }