diff --git a/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveSpecialAbilities.java b/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveSpecialAbilities.java index d135954..d0810f8 100644 --- a/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveSpecialAbilities.java +++ b/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveSpecialAbilities.java @@ -132,15 +132,14 @@ public final class AdaptiveSpecialAbilities { if (event.phase != TickEvent.Phase.END || event.getServer() == null) { return; } - long now = event.getServer().overworld().getGameTime(); Iterator blockIterator = TEMPORARY_BLOCKS.iterator(); while (blockIterator.hasNext()) { TemporaryBlock block = blockIterator.next(); - if (now < block.expireTick) { + ServerLevel level = block.server == event.getServer() ? event.getServer().getLevel(block.dimension) : null; + if (level == null || level.getGameTime() < block.expireTick) { continue; } - ServerLevel level = block.server == event.getServer() ? event.getServer().getLevel(block.dimension) : null; - if (level != null && level.getBlockState(block.pos).is(Blocks.COBWEB)) { + if (level.getBlockState(block.pos).is(Blocks.COBWEB)) { level.removeBlock(block.pos, false); } blockIterator.remove(); @@ -149,12 +148,12 @@ public final class AdaptiveSpecialAbilities { Iterator reappearIterator = DELAYED_REAPPEARS.iterator(); while (reappearIterator.hasNext()) { DelayedReappear pending = reappearIterator.next(); - if (now < pending.tick) { + ServerLevel level = pending.server == event.getServer() ? event.getServer().getLevel(pending.dimension) : null; + if (level == null || level.getGameTime() < pending.tick) { continue; } - ServerLevel level = pending.server == event.getServer() ? event.getServer().getLevel(pending.dimension) : null; - Entity mobEntity = level == null ? null : level.getEntity(pending.mobId); - Entity targetEntity = level == null ? null : level.getEntity(pending.targetId); + Entity mobEntity = level.getEntity(pending.mobId); + Entity targetEntity = level.getEntity(pending.targetId); if (mobEntity instanceof Silverfish mob && targetEntity instanceof LivingEntity target && mob.isAlive() && AdaptiveAIGoalUtils.isValidAdaptiveTarget(target) && mob.canAttack(target)) { Vec3 side = AdaptivePositioningUtils.sidePosition(mob, target, 1.6D, diff --git a/src/main/java/net/fretux/adaptivemobs/commands/AdaptiveMobsCommands.java b/src/main/java/net/fretux/adaptivemobs/commands/AdaptiveMobsCommands.java index be016bd..a2815b4 100644 --- a/src/main/java/net/fretux/adaptivemobs/commands/AdaptiveMobsCommands.java +++ b/src/main/java/net/fretux/adaptivemobs/commands/AdaptiveMobsCommands.java @@ -56,8 +56,9 @@ public final class AdaptiveMobsCommands { } private static int setTier(CommandSourceStack source, int tier) { - AdaptiveSavedData.get(source.getLevel()).setManualGlobalTier(Math.min(tier, AMConfig.maxTier)); - source.sendSuccess(() -> Component.literal("Adaptive Mobs: manual global tier set to " + tier), true); + int appliedTier = Math.min(tier, AMConfig.maxTier); + AdaptiveSavedData.get(source.getLevel()).setManualGlobalTier(appliedTier); + source.sendSuccess(() -> Component.literal("Adaptive Mobs: manual global tier set to " + appliedTier), true); return 1; } diff --git a/src/main/java/net/fretux/adaptivemobs/config/AMConfig.java b/src/main/java/net/fretux/adaptivemobs/config/AMConfig.java index a7d4626..5cf0c50 100644 --- a/src/main/java/net/fretux/adaptivemobs/config/AMConfig.java +++ b/src/main/java/net/fretux/adaptivemobs/config/AMConfig.java @@ -268,12 +268,10 @@ public final class AMConfig { } public static int tierValueInt(List list, int tier1based) { - if (list == null || list.isEmpty()) { + if (list == null || tier1based <= 0 || tier1based > list.size()) { return Integer.MAX_VALUE; } - int idx = Math.min(tier1based, list.size()) - 1; - idx = Math.max(0, idx); - return list.get(idx); + return list.get(tier1based - 1); } public static int aiScanCooldown(net.minecraft.util.RandomSource random) { diff --git a/src/main/java/net/fretux/adaptivemobs/difficulty/AdaptiveDifficultyManager.java b/src/main/java/net/fretux/adaptivemobs/difficulty/AdaptiveDifficultyManager.java index 8550eb7..7c76097 100644 --- a/src/main/java/net/fretux/adaptivemobs/difficulty/AdaptiveDifficultyManager.java +++ b/src/main/java/net/fretux/adaptivemobs/difficulty/AdaptiveDifficultyManager.java @@ -86,7 +86,8 @@ public final class AdaptiveDifficultyManager { private static int tierFromDay(long day) { int tier = 0; - for (int t = 1; t <= 5; t++) { + int configuredTiers = Math.min(5, AMConfig.DAY_THRESHOLDS.get().size()); + for (int t = 1; t <= configuredTiers; t++) { if (day >= AMConfig.tierValueInt(AMConfig.DAY_THRESHOLDS.get(), t)) { tier = t; } @@ -96,7 +97,8 @@ public final class AdaptiveDifficultyManager { private static int tierFromKills(long kills) { int tier = 0; - for (int t = 1; t <= 5; t++) { + int configuredTiers = Math.min(5, AMConfig.KILL_THRESHOLDS.get().size()); + for (int t = 1; t <= configuredTiers; t++) { if (kills >= AMConfig.tierValueInt(AMConfig.KILL_THRESHOLDS.get(), t)) { tier = t; } diff --git a/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java b/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java index 3b1d9eb..ebb2434 100644 --- a/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java +++ b/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java @@ -31,13 +31,14 @@ import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.event.level.BlockEvent.EntityPlaceEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.server.ServerStoppingEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; public class AdaptiveMobsEvents { - private static final String FRIENDLY_FIRE_SOURCE_KEY = "am_friendly_fire_source"; private static final String FRIENDLY_FIRE_COUNT_KEY = "am_friendly_fire_count"; private static final String FRIENDLY_FIRE_EXPIRES_KEY = "am_friendly_fire_expires"; + private static final String PENDING_SPAWN_PROCESSING_KEY = "am_pending_spawn_processing"; private static final int FRIENDLY_FIRE_WINDOW_TICKS = 100; @SubscribeEvent @@ -69,13 +70,10 @@ public class AdaptiveMobsEvents { } long now = level.getGameTime(); - String source = attacker.getUUID().toString(); - boolean sameVolley = source.equals(victim.getPersistentData().getString(FRIENDLY_FIRE_SOURCE_KEY)) - && victim.getPersistentData().getLong(FRIENDLY_FIRE_EXPIRES_KEY) >= now; + boolean sameVolley = victim.getPersistentData().getLong(FRIENDLY_FIRE_EXPIRES_KEY) >= now; int hits = sameVolley ? victim.getPersistentData().getInt(FRIENDLY_FIRE_COUNT_KEY) + 1 : 1; int toleratedHits = Math.min(4, tier - 1); if (hits <= toleratedHits) { - victim.getPersistentData().putString(FRIENDLY_FIRE_SOURCE_KEY, source); victim.getPersistentData().putInt(FRIENDLY_FIRE_COUNT_KEY, hits); victim.getPersistentData().putLong(FRIENDLY_FIRE_EXPIRES_KEY, now + FRIENDLY_FIRE_WINDOW_TICKS); event.setCanceled(true); @@ -85,7 +83,7 @@ public class AdaptiveMobsEvents { clearFriendlyFireTolerance(victim); } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = false) public void onLivingHurt(LivingHurtEvent event) { AdaptiveSpecialAbilities.onLivingHurt(event); if (!AMConfig.enabled || !AMConfig.ENABLE_THREAT_MEMORY_AI.get()) { @@ -128,7 +126,7 @@ public class AdaptiveMobsEvents { } } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = false) public void onFinalizeSpawn(MobSpawnEvent.FinalizeSpawn event) { if (!AMConfig.enabled || !(event.getLevel() instanceof ServerLevel level)) { return; @@ -138,10 +136,8 @@ public class AdaptiveMobsEvents { return; } + mob.getPersistentData().putBoolean(PENDING_SPAWN_PROCESSING_KEY, true); int tier = AdaptiveDifficultyManager.getMobTier(level, mob.getType()); - MobStatScaler.applyScaling(mob, tier); - GearScaler.applyGear(mob, tier); - AdaptiveGoalInjector.inject(mob, level, tier); SpawnPressureHelper.maybeSpawnExtra(level, mob, tier, event.getSpawnType()); } @@ -153,6 +149,14 @@ public class AdaptiveMobsEvents { return; } Entity entity = event.getEntity(); + if (AMConfig.enabled && entity instanceof Mob mob && mob instanceof Enemy + && AMConfig.isMobEnabled(mob.getType()) + && mob.getPersistentData().getBoolean(PENDING_SPAWN_PROCESSING_KEY)) { + mob.getPersistentData().remove(PENDING_SPAWN_PROCESSING_KEY); + int tier = AdaptiveDifficultyManager.getMobTier(level, mob.getType()); + MobStatScaler.applyScaling(mob, tier); + GearScaler.applyGear(mob, tier); + } // Install dormant, config-gated goals on every supported hostile so a later config reload // can enable them without requiring the entity to unload and join again. if (entity instanceof Mob mob && mob instanceof Enemy) { @@ -192,7 +196,6 @@ public class AdaptiveMobsEvents { } private static void clearFriendlyFireTolerance(Mob mob) { - mob.getPersistentData().remove(FRIENDLY_FIRE_SOURCE_KEY); mob.getPersistentData().remove(FRIENDLY_FIRE_COUNT_KEY); mob.getPersistentData().remove(FRIENDLY_FIRE_EXPIRES_KEY); } diff --git a/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java b/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java index 7146927..c44ea0e 100644 --- a/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java +++ b/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java @@ -21,6 +21,8 @@ import net.minecraft.world.item.enchantment.Enchantments; */ public final class GearScaler { + private static final String GEAR_APPLIED_KEY = "am_gear_applied"; + // Material ranks (low -> high) used both to pick new gear and to compare against existing gear. private static final Item[] HELMETS = {Items.LEATHER_HELMET, Items.GOLDEN_HELMET, Items.CHAINMAIL_HELMET, Items.IRON_HELMET, Items.DIAMOND_HELMET}; private static final Item[] CHESTS = {Items.LEATHER_CHESTPLATE, Items.GOLDEN_CHESTPLATE, Items.CHAINMAIL_CHESTPLATE, Items.IRON_CHESTPLATE, Items.DIAMOND_CHESTPLATE}; @@ -32,6 +34,10 @@ public final class GearScaler { } public static void applyGear(Mob mob, int tier) { + if (mob.getPersistentData().getBoolean(GEAR_APPLIED_KEY)) { + return; + } + mob.getPersistentData().putBoolean(GEAR_APPLIED_KEY, true); if (!AMConfig.GEAR_SCALING_ENABLED.get() || tier <= 0) { return; } diff --git a/src/main/java/net/fretux/adaptivemobs/spawn/SpawnPressureHelper.java b/src/main/java/net/fretux/adaptivemobs/spawn/SpawnPressureHelper.java index 1d1a4d0..67540d1 100644 --- a/src/main/java/net/fretux/adaptivemobs/spawn/SpawnPressureHelper.java +++ b/src/main/java/net/fretux/adaptivemobs/spawn/SpawnPressureHelper.java @@ -2,8 +2,6 @@ package net.fretux.adaptivemobs.spawn; import net.fretux.adaptivemobs.AdaptiveMobs; import net.fretux.adaptivemobs.config.AMConfig; -import net.fretux.adaptivemobs.gear.GearScaler; -import net.fretux.adaptivemobs.scaling.MobStatScaler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -13,6 +11,7 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.phys.AABB; +import net.minecraftforge.event.ForgeEventFactory; /** * Adds modest spawn pressure: on a natural hostile spawn there is a tier-scaled chance to spawn @@ -75,12 +74,10 @@ public final class SpawnPressureHelper { random.nextFloat() * 360.0F, 0.0F); // Honour collision, light/biome spawn rules and obstruction checks. if (level.noCollision(extra) - && extra.checkSpawnRules(level, MobSpawnType.NATURAL) + && extra.checkSpawnRules(level, spawnType) && extra.checkSpawnObstruction(level)) { - extra.finalizeSpawn(level, level.getCurrentDifficultyAt(extra.blockPosition()), - MobSpawnType.NATURAL, null, null); - MobStatScaler.applyScaling(extra, tier); - GearScaler.applyGear(extra, tier); + ForgeEventFactory.onFinalizeSpawn(extra, level, + level.getCurrentDifficultyAt(extra.blockPosition()), spawnType, null, null); level.addFreshEntity(extra); if (AMConfig.debug) { AdaptiveMobs.LOGGER.info("[AdaptiveMobs] Extra spawn ({}) at tier {} near {}",