Unofficial site, not affiliated with modrinth.com.What is this?
Плагины/HungerGameSSS
Все версииHungerGameSSS 4.6.2

HungerGameSSS 4.6.2

Release3 нед. назад

Список изменений

[4.6.2] — Gameplay Bug Fix Patch (2026-05-23)

Fixed — 9 bugs across 4 files

These bugs were identified through source-code analysis of v4.6.1. None require a database migration or config change.


🔴 Critical — Broken every match

  • BUG-1 · GameTask — PLAYING→DEATHMATCH transition bypasses FSM (GameTask.java)

    GameTask.handlePhaseTransitions() called arena.setState(MatchState.DEATHMATCH) directly instead of plugin.getMatchService().transition(arena, MatchState.DEATHMATCH). Bypassing transition() meant:

    • ArenaDeathmatchEvent was never fired — external plugins received no notification.
    • scheduleDeathmatchTask() was never called — players were not teleported to the Cornucopia centre at Deathmatch start.
    • The rapid border collapse to 10 × 10 over 60 s never happened.
    • Scoreboard was not refreshed via updateScoreboards().

    Fix: replaced arena.setState(MatchState.DEATHMATCH) with plugin.getMatchService().transition(arena, MatchState.DEATHMATCH).

  • BUG-2 · GameTask — three different config keys used for the same border size (GameTask.java)

    Three separate code paths read the "initial border size" value using three different config keys:

    • config.yml declares: game.border-initial-size: 2000 (the canonical key)
    • MatchService.java reads: "game.border-initial-size" ✅ correct
    • GameTask.java line 90 read: "game.initial-border-size" ❌ key does not exist → fallback 1000.0
    • GameTask.java line 100 read: "game.border.initial-size" ❌ key does not exist → fallback 1000.0

    Effect: the game loop always set the initial border to 1 000 blocks regardless of the admin's configured value. Any server with border-initial-size set above or below 1 000 saw unexpected border behaviour from the very first second of a match.

    Fix: unified both GameTask reads to use "game.border-initial-size".

  • BUG-3 · MatchService.startMatch(Arena, int) — countdown BukkitRunnable not stored (MatchService.java)

    The overload startMatch(Arena arena, int countdownSeconds) created a countdown BukkitRunnable but discarded the returned BukkitTask. The task was never added to countdownTasks, so cancelAllTasksFor() could not cancel it. Calling startMatch() twice on the same arena (e.g. two rapid /hg start commands, or a player join triggering auto-start while a manual start was in progress) launched two concurrent countdowns. Both reached zero and each called startArena(), resulting in the match starting twice — players teleported twice, inventory cleared twice, cage system entered an inconsistent state.

    Fix: stored the returned BukkitTask in countdownTasks.put(arena.getName(), task).


🟡 Medium — Visible gameplay defects

  • BUG-4 · MatchService + GameTask — WorldBorder controlled by two systems simultaneously (MatchService.java)

    MatchService.transition() (called when entering PLAYING) scheduled scheduleBorderTask(), a periodic timer that shrank the border every N minutes. At the same time, GameTask.handleWorldBorder() ran every server tick during PLAYING and recalculated the border size via smooth linear interpolation, then called WorldBorder.setSize(). The per-tick recalculation fired every second and silently overrode the periodic task's setSize(size, duration) smooth animation, causing the border to visibly flicker or jump rather than shrink smoothly.

    Fix: removed the scheduleBorderTask(arena) call from MatchService.transition(PLAYING). GameTask.handleWorldBorder() is now the sole authority for border size — it provides smoother and more precise interpolation than the coarse periodic approach.

  • BUG-5 · Arena.getActiveLegendaryLocations() — hologram names always show material ID (Arena.java)

    The method read recipe.getItemMeta().getDisplayName() (legacy Bukkit API). All legendary items in this plugin have their display names set via the Adventure Component API (meta.displayName(Component)). The legacy getDisplayName() method returns "" for any such item, so hasDisplayName() was always false, and every legendary hologram fell back to showing recipe.getType().name() — raw material names like WOODEN_SWORD instead of the intended weapon name (e.g. Excalibur).

    Fix: replaced getDisplayName() / hasDisplayName() with Adventure's PlainTextComponentSerializer to extract the plain-text string from the Component display name.

  • BUG-6 · MatchService.checkWin() — game doesn't end when a full team is the last survivor (MatchService.java)

    checkWin() ended the game when aliveCount == 1. In team mode, if the final two (or more) surviving players were all on the same team, aliveCount was ≥ 2, so no win was declared and the game ran indefinitely or until the Deathmatch timer expired — forcing teammates to kill each other.

    Fix: after counting alive players, if aliveCount > 1 the method now checks whether all surviving players share a single team identifier. If every alive player belongs to the same team (or all are solo/no-team and there is only one unique identity), endGame() is called immediately.


🟢 Minor — Low-severity improvements

  • BUG-7 · TeamManager — deprecated ChatColor usage produces compile warnings (TeamManager.java)

    TeamManager and TeamData use org.bukkit.ChatColor for team color storage, which is deprecated on Paper 1.21 in favour of net.kyori.adventure.text.format.NamedTextColor. Migrating the underlying storage type would require a database schema change and DatabaseManager migration; that is deferred to a future version. Added @SuppressWarnings("deprecation") on loadColors() with a TODO comment documenting the planned migration path, silencing the compiler warnings without any behaviour change.

  • BUG-8 · MatchService.startCountdown() — countdown task not stored, leaks on arena reset (MatchService.java)

    startCountdown(Arena, List<Player>) (called from the main startMatch(Arena, List<Player>) flow) created a countdown BukkitRunnable but did not add the task to countdownTasks. If the arena was reset before the countdown finished (e.g. all players left), the orphaned task continued ticking until it reached zero and called releasePlayers() on a now-empty arena — potentially transitioning a WAITING arena to PLAYING with no players.

    Fix: stored the returned task in countdownTasks.put(arena.getName(), taskRef[0]).

  • BUG-9 · MatchService — cage cleanup stores Block objects instead of Location (MatchService.java)

    arenaCages was declared Map<String, List<Block>>. Block objects hold a direct reference to the chunk at the time they were obtained. If chunks unload and reload before breakGlassCages() runs, the stale Block reference may report an incorrect getType() — the GLASS check would fail and the cage blocks would not be cleared, leaving orphaned glass geometry in the arena world.

    Fix: changed arenaCages to Map<String, List<Location>>. breakGlassCages() now calls l.getBlock() at removal time, always querying the current (guaranteed-loaded) chunk state. Both createJoinCage() and teleportPlayersAndCreateCages() updated to store l.clone().


Changed

  • pom.xml — version 4.6.14.6.2
  • plugin.yml — version 4.6.14.6.2; description updated
  • paper-plugin.yml — version 4.6.14.6.2

Метаданные

Канал релиза

Release

Номер версии

4.6.2

Загрузчики

Bukkit
Paper
Purpur
Spigot

Версии игры

1.21–1.21.11

Загрузок

49

Дата публикации

3 нед. назад

Загрузил

ID версии

Главная