Список изменений
[4.3] — Stabilization Patch 3
Fixed
High
-
H-04 ·
FeastManager— double announce + possible double-spawn (FeastManager.java) Theannounce-minuteslist inconfig.ymlpreviously included both20and19, causing two broadcasts in the very first minute of the match. Even after the config was corrected in v4.1, a subtler edge still remained:timerSeconds == 0at the moment the PLAYING state begins, andfeastSeconds - 0 * 60 == 0— meaning any 0-minute entry in the list would fire instantly. Fix: GuardtimerSeconds <= 0returns immediately. AddedfeastSpawnedset (ConcurrentHashMap-backed) so the feast spawns exactly once per match regardless of how many scheduler ticks land on the boundary second. AddedresetArena(name)to clear the flag between matches. -
H-06 ·
DungeonManager.getMobHP()fallback40.0vs config60.0(DungeonManager.java) Theconfig.ymldeclareddungeons.mob-hp: 60.0as the intended default, but the code fallback was40.0. When the key was absent the generic dungeon mobs (Spider Queen, Crypt Stalker, Gold Miner, Temple Guardian) spawned with 40 HP — one-third weaker than designed. Fallback corrected to60.0.
Medium
-
M-04 ·
Excalibur— reflection hit dungeon mobs, bypassed team system (Excalibur.java)performDamagedreflected against anyLivingEntityattacker. When a dungeon mob hit the Excalibur holder, the reflected damage still had the player as the source, which could splash into nearby arena players and bypassed team friendly-fire checks entirely (the team check only ran forPlayerattackers). Reflection is a PvP mechanic; mob attacks should not trigger it. Changed the guard frominstanceof LivingEntity attackertoinstanceof Player attacker. The projectile deflect block remains unchanged (projectiles can originate from any source). Also added a self-damage guard (attacker.equals(player)) for defensive robustness. -
M-05 ·
Mjolnir—rotationAnglefloat unbounded, overflows after ~18 h (Mjolnir.java)rotationAnglewas incremented byrotationSpeedon every passive tick with no upper bound. A 32-bit float mantissa has 24-bit precision; at 25°/tick × 20 ticks/s the angle exceeds2²⁴in roughly 18 hours of continuous operation, after whichrotateY(Math.toRadians(angle))silently produces garbage rotation matrices and the thrown hammer stops orbiting correctly. Both increment sites now use% 360fto keep the angle in[0, 360). -
M-06 ·
VeinMinerListener—maxVeinSizenot hot-reloadable (VeinMinerListener.java) The field was read once in the constructor and cached for the lifetime of the plugin./perf reload(or any config reload) had no effect on vein size until the next server restart. Removed the cached field;maxVeinSizeis now read from config on everyBlockBreakEventand passed as a parameter tofindVein(). -
M-08 ·
ArenaListener— duplicate no-arg constructor using staticMain.getInstance()(ArenaListener.java) A second constructorpublic ArenaListener()accessedMain.getInstance()— a static singleton call that fails during class initialisation if the plugin is not fully loaded, and couples the listener to the static instance rather than the injected one. The no-arg constructor was a leftover comment artifact; removed. -
M-09 ·
DatabaseManager.getPlayerStats()— synchronous query on main thread (DatabaseManager.java) The method opened a JDBC connection and ran aSELECTon whichever thread called it. When called from command handlers or event listeners on the main thread this blocked the server tick for the entire round-trip. Replaced withgetPlayerStatsAsync(UUID)returningCompletableFuture<Map<String,Object>>dispatched to the Bukkit async scheduler. The original synchronous method is kept as@Deprecated getPlayerStats()(delegates togetPlayerStatsSync) for any call-sites that already run on async threads. -
M-10 ·
PerformanceOptimizer.toggleMonitoring()always returnedtrue(PerformanceOptimizer.java) The implementation wasreturn activeTasks.get() >= 0— anAtomicIntegeris always ≥ 0, so the method always returnedtrueregardless of monitoring state. AddedAtomicBoolean monitoringEnabled(defaulttrue);toggleMonitoring()now inverts the flag and returns the new state.
Low
-
L-06 ·
AbilityDispatcher.LEGEND_KEYstatic field initialised beforeonEnable()(AbilityDispatcher.java) The fieldprivate static final NamespacedKey LEGEND_KEY = new NamespacedKey(Main.getInstance(), "hg_ability")is evaluated when the class is first loaded. If any class (e.g. a command tab-completer) causedAbilityDispatcherto be loaded beforeMain.onEnable()completed,getInstance()returnednulland every subsequent ability dispatch threw NPE. Changed to lazy initialisation via a privategetLegendKey()method that constructs the key on first use. -
L-07 · Hardcoded test-item blacklist
gerald_sniffer/gruntilda/tim_enchanter(ArenaManager.java,config.yml) Three internal test legendary IDs were hard-coded instartCornucopiaPhase2(). Replacing them requires a recompile. Moved to config:legendary.excluded-ids: [](default empty). Server owners can now exclude any legendary from the active pool without touching source code. -
L-09 ·
buildCornucopia()calledoriginalBlocks.clear()destroying prior tracking (ArenaManager.java) Spawn cages and dungeon structures calloriginalBlocks.put()to record every block they place, enabling full restoration on arena reset.buildCornucopia()calledarena.originalBlocks.clear()before building the Cornucopia, erasing all prior entries. On reset, only blocks placed after the clear were restored — cages and dungeons were left as permanent terrain edits. Theclear()call is removed;CornucopiaBuilderalready appends to the map with individualput()calls. -
L-10 ·
GameTaskextendsBukkitRunnablebut is never scheduled — double-tick risk (GameTask.java)GameTaskwas a deadBukkitRunnablesubclass. The arena tick is driven entirely byArenaManager.tick()via the global loop inMain.onEnable(). If a future developer saw the class and scheduled it directly, every arena would tick twice per second.GameTask.run()now throwsUnsupportedOperationExceptionimmediately, surfacing the bug during development rather than silently corrupting timer state.

