continue/armor_aura #1
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<Biome> VOID_BIOME =
|
||||
RegistryKey.of(RegistryKeys.BIOME, new Identifier("chipi", "void"));
|
||||
|
||||
@ -46,16 +52,48 @@ public final class SpawnLogic {
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean canSpawn(EntityType<? extends MobEntity> type, ServerWorldAccess world, SpawnReason reason, BlockPos pos, Random random) {
|
||||
private static boolean canSpawn(
|
||||
EntityType<? extends MobEntity> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 =====
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@ public class ChipperArmorMaterial implements ArmorMaterial {
|
||||
|
||||
@Override
|
||||
public int getDurability(ArmorItem.Type type) {
|
||||
return 10_000;
|
||||
return 1_000;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
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.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 ProtectionAuraHandler() {}
|
||||
|
||||
/* ==========================================================
|
||||
ENTRY POINT — CALLED SERVER SIDE
|
||||
========================================================== */
|
||||
|
||||
public static void tick(PlayerEntity player) {
|
||||
if (!hasFullChipperArmor(player)) return;
|
||||
|
||||
Float value = player.getDataTracker().get(CHIPI_ENERGY);
|
||||
if (value == null) return;
|
||||
|
||||
float durabilityFactor = getDurabilityFactor(player);
|
||||
if (durabilityFactor <= 0f) return;
|
||||
|
||||
boolean inChipi = isInChipi(player.getWorld());
|
||||
boolean protectedAura = isOnProtectedBlock(player);
|
||||
|
||||
float rechargeRate = BASE_RECHARGE_RATE * durabilityFactor;
|
||||
float drainRate = BASE_DRAIN_RATE * (1.0f + (1.0f - durabilityFactor));
|
||||
|
||||
float next = value;
|
||||
|
||||
if (!inChipi || protectedAura) {
|
||||
next = Math.min(1.0f, value + rechargeRate);
|
||||
} else {
|
||||
next = Math.max(0.0f, value - drainRate);
|
||||
}
|
||||
|
||||
if (next == value) return;
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// PERCENT-BASED DURABILITY LOGIC
|
||||
// ─────────────────────────────────────────────
|
||||
int oldPercent = (int) Math.floor(value * 100f);
|
||||
int newPercent = (int) Math.floor(next * 100f);
|
||||
|
||||
int delta = Math.abs(newPercent - oldPercent);
|
||||
|
||||
if (delta > 0) {
|
||||
damageArmor(player, delta);
|
||||
}
|
||||
|
||||
player.getDataTracker().set(CHIPI_ENERGY, next);
|
||||
}
|
||||
|
||||
/* ==========================================================
|
||||
ARMOR CHECK
|
||||
========================================================== */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ==========================================================
|
||||
DURABILITY LOGIC
|
||||
========================================================== */
|
||||
|
||||
private static float getDurabilityFactor(PlayerEntity player) {
|
||||
int max = 0;
|
||||
int 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.max(0f, Math.min(1f, (float) current / max));
|
||||
}
|
||||
|
||||
private static void damageArmor(PlayerEntity player, int amount) {
|
||||
for (ItemStack stack : player.getArmorItems()) {
|
||||
if (!stack.isEmpty()) {
|
||||
stack.damage(amount, player, p -> {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================
|
||||
AURA CONDITIONS
|
||||
========================================================== */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 value = player.getDataTracker().get(CHIPI_ENERGY);
|
||||
if (value == null || value <= 0f) return false;
|
||||
|
||||
return getDurabilityFactor(player) > 0f;
|
||||
}
|
||||
}
|
||||
@ -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,22 +15,16 @@ 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<World> 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;
|
||||
|
||||
private static final Identifier SPAWN_STRUCTURE =
|
||||
new Identifier("chipi", "spawn");
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,24 +69,16 @@ public final class ChipiServerEvents {
|
||||
|
||||
if (state.placed) return;
|
||||
|
||||
StructureTemplate spawnTemplate =
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user