SurvivalGuideListener.PAGE_KEY NPE on startup — static final NamespacedKey PAGE_KEY
was initialised at class-load time before the plugin instance existed, causing a
NullPointerException on every server start. PAGE_KEY is now an instance field
initialised in the constructor. (BF-01)
InfectionListener ignored infection.enabled config — infection spread on every
zombie hit regardless of infection.enabled: false in config.yml. ZombieBehaviorService
already checked the flag but InfectionListener did not, making the config option
partially ineffective. (BF-02a)
InfectionListener ignored zapoc.immune permission — players with zapoc.immune
could still receive infection points. The permission is now checked in both
InfectionListener and ZombieBehaviorService. (BF-02b)
Day-based spawn-rate (shouldSpawn()) was completely bypassed — ZombieBehaviorService
runs at EventPriority.HIGH and cancelled natural spawns before SpawnListener ran,
so the phase-based rates (40% / 70% / 90% / 100%) never took effect — zombies always
spawned at 100% regardless of server age. shouldSpawn() is now called directly inside
ZombieBehaviorService.onCreatureSpawn. (BF-03)
TurretManager could permanently delete turrets_data.yml — the save code called
dataFile.delete() before renameTo(). If the rename failed the data file was gone
permanently. Replaced with Files.move(ATOMIC_MOVE) and a non-atomic fallback. (BF-04)
Sanity config multipliers loaded but never applied — sanityDrainBase,
nightMultiplier, infectedMultiplier, lowHealthMultiplier, and
nearbyZombiesMultiplier were read from mechanics.yml but updateSanity() used
hardcoded constants. Editing these values in config had no visible effect. All five
multipliers are now applied correctly. (BF-05)
whisperPhrases config key loaded but never used — handleWhispers() used an
internal hardcoded array instead of the phrases from mechanics.yml. Player-configured
phrases including phrases-vi / phrases-en are now displayed correctly. (BF-06)
hg.no-netherite-drop bypass via corpse zombie — the death handler stripped netherite
from event.getDrops() but then re-equipped the corpse zombie with raw armour including
netherite. A player could kill the corpse to recover the items. Netherite is now stripped
from the corpse's equipment when the option is enabled. (BF-07)
Tank zombie ENTITY_RAVAGER_STEP sound spam — handleTank() fired a full-volume step
sound every 0.5 s with no throttle, flooding clients when multiple Tank zombies were
active. A 10% per-call chance now limits the frequency. (BF-08)
panicCooldowns HashMap memory leak — UUID entries were added on /zapoc panic but
never removed on disconnect. Entries are now removed in onPlayerQuit. (BF-09)
Stalker spawn used zombie's world for player's Y lookup — getHighestBlockYAt() was
called on the zombie's world; if the target player had recently changed worlds the Y
could be wrong. Player's own world is now used for the lookup. (BF-10)
handleSunEffect() YAML reads inside per-zombie loop eliminated — seven
FileConfiguration.get*() calls per zombie per tick removed. All sun-effect config
values are now cached at task level and refreshed every 5 s. Eliminates ~1,400
redundant map lookups per second at 200 tracked zombies. (BF-11)
Math.random() replaced with ThreadLocalRandom throughout — 20+ usages replaced
across CampfireManager, ZombieApoc, ZombieBehaviorService, ZombieBehaviorTask,
PlayerStatusTask, WorldEventTask, ZombieEvolutionService, and
SpecialZombieListener. (BF-12)
data.yml, campfires.yml, and
turrets_data.yml are fully compatible.
ZombieApocalypseSSS is a comprehensive Minecraft plugin that transforms your server into a thrilling zombie survival apocalypse. Featuring advanced zombie AI, evolving variants, player infection mechanics, psychological horror elements, and dynamic events