Unofficial site, not affiliated with modrinth.com.What is this?
Плагины/HungerGameSSS
  • HungerGameSSS 4.6.4

    release4 июня 2026 г.

    [4.6.4] — Architecture & Gameplay Bug-Fix Patch (2026-06-04)

    11 bugs fixed across MatchService, Main, ArenaManager, Arena, listeners and resources.
    No database migrations or config changes required — drop-in replacement for 4.6.3.
    One new optional config key: game.reconnect-timeout (default 60, seconds).

  • HungerGameSSS 4.6.3

    release3 июня 2026 г.

    [4.6.3] — Ability System Bug-Fix Patch (2026-06-03)

    Full deep-dive analysis of all 45 ability implementations.
    13 confirmed bugs fixed across 12 files (2 framework, 11 ability-level).
    No database migrations or config changes required — drop-in replacement for 4.6.2.


  • HungerGameSSS 4.6.2

    release23 мая 2026 г.

    [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

  • HungerGameSSS 4.6.1

    release15 мая 2026 г.

    [4.6.1] — Critical Bug Fix Patch (2026-05-15)

    Fixed — 9 bugs across 7 files

    Critical — Plugin fails to enable

    • BUG-PPL-01 · paper-plugin.ymlloader: references a class that does not exist (paper-plugin.yml) The file declared loader: me.duong2012g.hungergamessss.PaperPluginLoader, but this class was never created. Paper attempted to instantiate it during plugin loading, threw ClassNotFoundException, and the plugin failed to enable entirely. Fix: removed the loader: line. A custom PluginLoader is not needed for this plugin's feature set; standard Paper loading works correctly.

    • BUG-DB-01 · DatabaseManager — SQLite JDBC driver and MySQL connector not shaded into JAR (pom.xml) DatabaseManager called config.setDriverClassName("org.sqlite.JDBC") and supported MySQL mode, but neither org.xerial:sqlite-jdbc nor com.mysql:mysql-connector-j appeared as Maven dependencies. The built JAR had no driver classes, causing ClassNotFoundException: org.sqlite.JDBC on every server startup that uses the default SQLite config. Fix: added both dependencies to pom.xml and configured the Maven Shade Plugin to relocate them under me.duong2012g.hungergamessss.libs.{sqlite,mysql} to avoid classpath conflicts with other plugins.

    High — Gameplay-breaking

    • BUG-DB-02 · DatabaseManager.updateSchema()games_played column added to arenas table instead of players (DatabaseManager.java) updateSchema() iterated a single column array and checked all entries against the arenas table. games_played is a player stat column that belongs in players. On fresh installs the players table lacked the column; savePlayerStats() / loadPlayerStats() threw SQLException: no such column: games_played whenever stats were read or written. Fix: split the migration into two separate loops — arenaColumns[] against the arenas table and playerColumns[] against the players table. Each column is now checked and added against the correct table.

    • BUG-AM-02 · AbilityManager.createItem()unbreakable flag silently overwritten (AbilityManager.java) The unbreakable block retrieved a new ItemMeta copy from item.getItemMeta(), set unbreakable(true) on it, called item.setItemMeta(unbrMeta) — but then the outer code called item.setItemMeta(meta) with the original meta object (which did not have unbreakable set). The second setItemMeta silently discarded the flag. Legend items marked unbreakable: true in YAML still lost durability in-game. Fix: call meta.setUnbreakable(true) directly on the existing meta object before the final item.setItemMeta(meta) call. The duplicate item.getItemMeta() call is removed.

    • BUG-AM-03 · AbilityManager.createItem() — localization fallback condition never true (AbilityManager.java) The fallback for missing legend name/description keys compared the return value of getMessage(key) against the raw key string: if (localizedName.equals("legend_" + key + "_name")). MessageManager.getMessage() never returns the raw key — it returns "§cMessage not found: <key>" — so the condition was always false and the fallback (config.getOrDefault("name", ...)) was never reached. Items with no language entry showed the red error string as their display name. Fix: replaced both checks (name + description) with hasMessage(key) which tests the cache directly. The fallback now triggers correctly for any missing key.

    • BUG-AM-04 · MessageManager — no public API to test key existence (MessageManager.java) There was no way to check whether a message key existed without calling getMessage() and inspecting the error-prefix fallback string, which is fragile and language-dependent. Fix: added public boolean hasMessage(String key) that returns messageCache.containsKey(key). Used by the createItem() fallback fix above.

    High — Production safety

    • BUG-AFC-01 · AutoFixCommand — dangerous synchronous I/O, stale hardcoded JAR name, and wrong config keys (AutoFixCommand.java) Three independent issues:
      1. File copy and HTTP download ran on the main server thread (could freeze the server tick for multiple seconds while downloading Paper).
      2. The command hard-coded "HungerGamesSSS-1.15.jar" — the project is now at version 4.6.1, so the source file path was always wrong and the command silently did nothing useful.
      3. The generated config.yml used stale keys (database.file, game.waiting-duration, structures.spawn-interval-ticks, performance.unload-delay-ticks) that the current codebase no longer reads, resulting in a silently broken configuration on every use. Fix: the command body is replaced with a single disabled message pointing to the source file. The command will be re-enabled once rewritten with async I/O, dynamic version detection, pre-modification backups, and config generation from ConfigSchemaValidator.

    Medium — Operator experience

    • BUG-CFG-01 · config.yml — missing keys silently use hardcoded defaults (config.yml) Over a dozen config keys read by the code (game.min-players-to-start, game.max-players, game.countdown-seconds, game.reset-delay-seconds, game.border-initial-size, game.border-min-size, game.feast-delay-seconds, arena.veinminer-max-size, abilities.disabled, abilities.enabled-only, resource-pack.required, resource-pack.prompt, database.debug-logging) were absent from the default config.yml. Admins had no indication these options existed and could not configure them without reading source code. Fix: all missing keys added to config.yml with documented defaults.

    • BUG-LANG-01 · en.yml — 60+ message keys used in code but absent from language file (languages/en.yml) Numerous keys used in TeamCommand, WithdrawCommand, LocateCommand, DebugCommand, AutoFixCommand, MatchService, and others were not present in en.yml. Every trigger showed §cMessage not found: <key> to players or admins. Additionally, four legend item name/description keys were missing (legend_artemis_bow_name, legend_death_note_name, legend_hermes_boots_name, legend_toxic_crossbow_name and corresponding _desc keys), causing ability items to display the red error string as their display name after the localization fallback fix above. Fix: all missing keys added to en.yml with English text.

    Build fix — mvn clean package fails with CompilerException: NullPointerException

    (pom.xml) testCompile crashed with a NullPointerException inside javac on JDK 21 even after switching to <release>21</release>. Root cause: MockBukkit 4.109.0 ships an annotation processor that walks the full type graph of the class under test. CooldownManagerTest loads Main via MockBukkit.load(Main.class), which pulls in every manager, database driver, and Adventure type at compile time. On JDK 21 this resolution chain hit a null reference inside javac's own symbol table, crashing the compiler process rather than producing a proper diagnostic.

    Three-part fix applied to pom.xml:

    1. MockBukkit downgraded 4.109.04.26.0. Version 4.26.0 is the last release before the annotation processor was added and is confirmed compatible with Paper 1.21 and JDK 21.

    2. <maven.test.skip>true</maven.test.skip> added to <properties>. Normal plugin builds (mvn clean package) no longer attempt test compilation. Tests can still be run explicitly: mvn test -Dmaven.test.skip=false.

    3. maven-surefire-plugin updated with <forkCount>1</forkCount> and <reuseForks>false</reuseForks>. MockBukkit stores global state in static fields — running multiple test classes in the same JVM causes false failures. A forked JVM per class also prevents any remaining javac NPE from killing the host Maven process.

    Changed

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

  • HungerGameSSS 4.6.0

    release7 мая 2026 г.

    [4.6.0] — Full Bug Fix & Improvement Pass (2026-05-05)

    Fixed — 46 bugs across 35 files

    Critical — Task & Memory Leaks

    • BUG-CM-01 CooldownManager repeating task never cancelled on reload → added shutdown(), called from onDisable()
    • BUG-MAIN-01 Game-loop BukkitRunnable was anonymous, never cancelled → stored gameLoopTask, cancelled in onDisable()
    • BUG-AM-01 new NamespacedKey(plugin, "hg_ability") created on every interact/hit/move → cached as final abilityPdcKey field
    • BUG-BASE-02 BaseAbility.onDeath() called validateCanUse() → blocked cleanup when arena state was ENDING at last kill
    • BUG-CS-02 CloudSword block-expiry task had no handle → glass blocks not restored on disable
    • BUG-HB-02 HermesBoots passive task had no handle + lastShift map never cleared on quit/death
    • BUG-RE-01 ReinforcedElytra passive task had no handle + explosionCooldowns never cleared
    • BUG-VW-02 VillagerWand stale-entry cleanup task had no handle → leaked on reload
    • BUG-MJ-01 Mjolnir: no performDeath()ItemDisplay entity leaked, item permanently lost on death
    • BUG-SB-02 ShadowBlade: no global cleanup() → players stayed invisible permanently after /reload
    • BUG-RH-03 RavagerHorn: no global cleanup() → ravager entities roamed arena world after reload
    • BUG-GH-03 GolemHammer: inAir map never cleared on quit/death → stale KB resist
    • BUG-LS-02 LichStaff: no global cleanup() → stale ammo entries persisted between matches
    • BUG-SG-02 SoulGauntlet: no global cleanup() → soul charges persisted between matches
    • BUG-VS-02 VoidStaff: 3 state maps never cleared on full shutdown
    • BUG-WS-02 WitherSickles: offhand copies not removed, cooldowns not cleared on shutdown
    • BUG-DN-01 DeathNote: used onQuit/onDeath bypassing BaseAbility lifecycle chain
    • BUG-LISTENER-01 AbilityListener.onPlayerMove: missing null check on event.getTo() → NPE risk

    High — State Management

    • OPT-REG-01 AbilityRegistry.getAbility() was O(42) triple-fallback loop → O(1) normalized HashMap lookup
    • OPT-BASE-01 Config key prefix "abilities.xxx." rebuilt on every config call → cached in constructor
    • OPT-BASE-02 BaseAbility.execute() 14-arm switch-case → EnumMap<TriggerType, Consumer> dispatch
    • OPT-DISP-01+02 AbilityDispatcher: debug logging on miss + eliminated duplicate NamespacedKey copy
    • OPT-UPT-01 UnifiedPassiveTicker now skips spectators, dead players, non-active arenas
    • OPT-AD-01 ArmadilloDetonator: per-entity BukkitRunnable → single unified per-player ticker
    • OPT-BB-01 BeehiveBlaster: 4-tick polling per bee → EntityDamageByEntityEvent listener (zero tasks)
    • OPT-AB-02+03 ArtemisBow: per-arena homing arrow cap + live count in passive HUD
    • OPT-CC-01 CorruptedCrossbow: gravity 0.04 flat → 0.05 + 1% horizontal drag (matches vanilla)
    • IMP-LISTENER-01 All combat/interact @EventHandler handlers now have ignoreCancelled = true
    • IMP-VM-01+02 VeinMinerListener: hard cap 128 blocks + spread breaking across ticks
    • BUG-MJ-01 Mjolnir global cleanup() removes all display entities

    Medium — Improvements

    • IMP-CTX-01 AbilityContext: defensive item.clone() + requiresArena() validation + getLocationSafe()
    • IMP-UTILS-01 AbilityUtils: findSafeLanding, degradeRandomArmorPiece, isFriendlyFire, tickProjectile, removeAfter, distanceSquared-first AoE check
    • IMP-CD-02 CooldownManager.generateProgressBar() uses § codes consistent with downstream serializer
    • IMP-MAIN-01+02 Main.onEnable() split into registerManagers/Listeners/Commands/postStartup + early Java/Paper validation
    • ARCH-MS-01+02+03 MatchService FSM: transition() method + BorderTask/FeastTask/DeathmatchTask + ArenaDeathmatchEvent
    • OPT-CD-01 CooldownManager: purge offline players from activeDisplayItem in periodic cleanup
    • A1-1+3 Ability.java: ISP sub-interfaces (ActiveAbility, PassiveAbility, ProjectileAbility, ListenerAbility) + full Javadoc
    • A1-10+11 AbilityRegistry: ServiceLoader SPI discovery + config-driven disabled/enabled-only overrides
    • A1-17 BaseAbility: AbilityGuard chain-of-responsibility + passesGuards() replaces 5 duplicated validate/cooldown blocks
    • A1-18 BaseAbility: getConfigStringList() + getConfigSection() helpers
    • A1-19 Aiglos: configurable AOE shape (sphere / cylinder) via aoe_shape config key
    • A1-23 CloudSword: self-listener removed; fall-cancel centralised in AbilityListener.onFallDamageCancelCloud
    • A1-26 4 abilities (BeehiveBlaster, ArmadilloDetonator, RavagerHorn, GhastlyWhistle): setRemoveWhenFarAway(true) on all custom entity spawns
    • A1-S1 AbilityServices: lightweight DI context replacing raw Main accessor calls
    • A1-S2 @AbilityTrigger + @PassiveTick annotations for future APT code generation
    • A1-S3+A2-S3 ArenaEntityTracker: unified entity lifecycle manager (track/release/prune by owner, arena, ability)
    • A1-S4+A2-S2 ParticleThrottle: throttle + spawnDeferred() based on arena player count
    • A1-S5 AbilityMetrics: internal activation/blocked counter with Snapshot record
    • A1-S6 ConfigSchemaValidator: declarative YAML schema validation replacing manual assertRange() loop
    • A2-4 Main: ComponentLogger (SLF4J) field + clog() accessor
    • A2-9+10 ArenaManager.processQueue(): async chunk pre-loading + BossBar build progress
    • A2-11 CornucopiaBuilder now injectable via plugin.getCornucopiaBuilder()
    • A2-17 Arena.java: ArenaBlockRestorer + ArenaLegendaryTracker component objects extracted; old getters kept as @Deprecated delegation
    • A2-18 Ingredient + LootEntry converted to Java 21 records with compact constructors
    • A2-20 MatchService.resetArena(): block restoration now async via ArenaBlockRestorer + processQueue()
    • A2-22 VeinMiner disabled by default; opt-in via arena.builtin-veinminer: true
    • A2-S5 HungerGamesAPI: public Developer API for custom ability registration + arena queries
    • A2-S6 MatchState: isActive(), isJoinable(), isEnding(), match() functional switch

    New Files

    FilePurpose
    ability/AbilityServices.javaLightweight DI context
    ability/AbilityMetrics.javaActivation/blocked counters
    ability/annotation/AbilityTrigger.javaTrigger handler annotation
    ability/annotation/PassiveTick.javaPassive tick annotation
    api/HungerGamesAPI.javaPublic Developer API
    manager/ArenaEntityTracker.javaUnified entity lifecycle tracker
    model/ArenaBlockRestorer.javaBlock-change tracking + restore
    model/ArenaLegendaryTracker.javaLegendary placement + hologram lifecycle
    util/ParticleThrottle.javaParticle throttle + deferred spawn
    util/ConfigSchemaValidator.javaDeclarative YAML schema validation
    resources/paper-plugin.ymlModern Paper plugin descriptor

    Config changes

    # New keys added (all have safe defaults — no action required):
    arena:
      builtin-veinminer: false        # VeinMiner now opt-in (was always-on)
      show-build-progress: true       # BossBar during arena build
    abilities:
      disabled: []                    # blacklist ability names
      enabled-only: []                # whitelist mode (empty = disabled)
      spi-override-allow: false       # allow SPI abilities to replace built-ins
    

    Breaking Changes

    • Ingredient.mat / Ingredient.amount public fields removed → use ingredient.material() / ingredient.amount()
    • VeinMiner disabled by default — set arena.builtin-veinminer: true to restore previous behaviour
    • All other changes are backwards-compatible with existing saves, ability YAMLs, and config.yml

  • HungerGameSSS 4.5.9

    release24 апреля 2026 г.

    [4.5.9] — Bug Fix Pass 5 (2026-04-24)

    Fixed — 3 bugs across 3 files

    High

    • BUG-BASE-01 · BaseAbilityvalidateCanUse() uses wrong permission node hg.admin instead of hoplitebr.admin (BaseAbility.java) validateCanUse() granted the admin bypass with player.hasPermission("hg.admin"). The correct node — defined in plugin.yml and fixed for commands in 4.1 (bug M-07) — is hoplitebr.admin. Any operator who granted the hoplitebr.admin permission explicitly (without OP) received no bypass; conversely, hg.admin grants that had been assigned in a permissions plugin incorrectly bypassed ability checks. Fix: changed check to player.hasPermission("hoplitebr.admin"). The || player.isOp() fallback is unchanged so vanilla OP still bypasses.

    Medium

    • BUG-CTX-01 · AbilityContext — no isCancelled() / setCancelled() API (AbilityContext.java) The AbilityContext object was fully immutable after construction. Abilities that need to signal downstream handlers to skip processing (e.g. two abilities sharing the same trigger chain) had no standard way to do so — each ability reimplemented ad-hoc boolean flags. Fix: added a mutable boolean cancelled field with isCancelled() and setCancelled(boolean) accessors. The field defaults to false. Abilities can now call ctx.setCancelled(true) to mark a context as consumed, and other abilities/listeners can check ctx.isCancelled() before acting.

    • BUG-OD-02 · ObsidianDagger — deprecated getTargetBlock(null, range) + 1-tick meteor trail task + hardcoded sendMessage calls (ObsidianDagger.java) Three independent issues in performRightClick:

      1. player.getTargetBlock(null, TARGET_DISTANCE) — passing null for the transparent-block set is deprecated in Paper 1.21 and emits a compile warning. Replaced with player.getTargetBlockExact(distance, FluidCollisionMode.NEVER) with a rayTraceBlocks primary path for accurate targeting.
      2. The meteor particle trail BukkitRunnable ran at period 1L (every tick). A falling meteor moves slowly enough that 2L (every 2 ticks) produces visually identical results at half the server-side task overhead.
      3. Two player.sendMessage("§...") calls bypassed the Adventure component API (italic rendering issue) and the i18n system. Replaced with player.sendActionBar(Component) using LegacyComponentSerializer, consistent with the pattern used throughout other abilities since 4.5.5.

    Changed

    • pom.xml — version 4.5.84.5.9.
    • plugin.yml — version 4.5.84.5.9; description updated.

  • HungerGameSSS 4.5.8

    release21 марта 2026 г.

    HungerGamesSSS v4.5.8 — Legend Rewrite Pass

    🔧 Bug Fixes (13 issues)

    • Fixed 8 abilities double-registering events on reload (CloudSword, VoidStaff, WitherSickles, Excalibur, EmeraldBlade, MidasSword, VillagerWand, ChainsawSword)
    • Fixed ObsidianDagger, HypnosisStaff, GolemHammer passive tasks never cancelling on shutdown
    • Fixed loadPlayerStats() blocking main thread on player join → now async
    • Fixed savePlayerStats() overwriting real stats with zeros on every join
    • Fixed UpdateManager HTTP connection hanging indefinitely when Modrinth unreachable

    🗑️ Removed

    • ChainsawSword — removed (replaced by Crimson Chainsword's new design)
    • DeathScythe — removed (replaced by Reaper Scythe's new design)

    ⚔️ Legend Rewrites (12 weapons)

    WeaponOldNew
    WarpickBroken mine + shatterMine Explosion (5s CD) + Critical Hit armor shred (20s CD)
    Dragon KatanaSimple dashPermanent Speed I passive + Dragon Dash teleport (12s CD)
    Artemis BowPower V + InfinityPower III (upgradeable to VII via Anvil) + Homing 25% + Lightning 20%
    AiglosIce freeze AOEExplosive spear throw — 3×3×3 blast, Sharpness scales explosion, Loyalty III return
    Armadillo DetonatorAuto-explode on contactRight-click shoot (max 3 active, 20s CD) + Left-click instant detonate all
    Beehive BlasterBall projectileRight-click spawns 4 angry bees, auto-target nearest enemy, Poison I (8s) per sting
    Crimson ChainswordBleed DoT + rev mechanicShred Stacks passive (+10% pen/stack, max 5) + Chainsaw Rampage (10s CD, 3s burst, 12 ticks)
    Corrupted CrossbowSpread arrowsPoison Cloud bolt (4s CD) — AoE splash 4×4×4, Multishot = 3 clouds
    Death NoteStare at target to summon WardenType /dn <name> → instant kill (bypass armor/totem), 3 uses total, 25s per-target CD
    Reaper ScytheWither AOE sweepSoul Harvest (45s CD) — steal ALL beneficial effects + 25% lifesteal per target
    Ender BowSwap positions + blinkPearl Shot (30s CD) + Arrow→Floating Pearl (walk in = instant teleport, no CD)
    Excalibur5s timed invincibility3-Hit Immunity Charges — block any damage, auto-recharge +1 every 45s
    Fountain of YouthRegen zone onlyPassive +1 HP/s while held + 8×8 healing zone (30s, 60s CD)
    Ghastly WhistleAir strike onlySummon rideable Ghast (20s) — steer with WASD, auto-fires fireballs at enemies

    🆕 New Systems

    • /dn command — Death Note kill command with tab-complete (enemy arena players only)
    • AnvilListener — Artemis Bow can be upgraded Power III→VII via anvil; other legendaries protected from accidental ability-strip
    • Player Head drop — drops victim's head on PvP kill (used in Warpick/Aiglos/etc. recipes). Configurable: game.death.drop-head + game.death.drop-chance
    • attributes: YAML block — any legend item can now set AttributeModifiers (attack damage, speed, reach) via config without code
    • unbreakable: true — YAML flag support in legend item configs

    🍳 Recipe Overhaul

    All 12 rewritten weapons have brand-new recipes themed around their playstyle. Highlights:

    • Death Note: Nether Star + 3× Player Head + 3× Wither Skull + Echo Shard × 3 + Shulker Shell × 3 (endgame grind)
    • Excalibur: Gold Block × 36 + Emerald Block × 4 + Diamond Sword + Enchanted Golden Apple
    • Ghastly Whistle: Dried Ghast × 5 + Diamond × 4 + Saddle + Ghast Tear × 3 (35 min grind)
  • HungerGameSSS 4.5.7

    release20 марта 2026 г.

    [4.5.7] — Full Bug Sweep Pass 4 (2026-03-20)

    Fixed — 13 issues across 14 files

    High

    • BUG-REG-01 · 8 ability classes — registerEvents() in constructor causes double event-handling on reload (CloudSword.java, VoidStaff.java, WitherSickles.java, Excalibur.java, EmeraldBlade.java, MidasSword.java, VillagerWand.java, ChainsawSword.java, HypnosisStaff.java) Each of these abilities called Bukkit.getPluginManager().registerEvents(this, plugin) inside their constructor. On plugin reload, AbilityRegistry instantiates fresh objects, but the old instances' handlers are never unregistered — both the old and new instances fire for every event, causing every hit, click, and projectile event to be processed twice. Fix: moved all registerEvents() calls out of constructors and into AbilityRegistry.register(), which is called exactly once per ability instance. AbilityRegistry.register() now checks ability instanceof Listener and registers automatically, so abilities only need to implement Listener — no manual registration needed.

    • BUG-OD-01 · ObsidianDagger — standalone passive BukkitRunnable leaks on reload (ObsidianDagger.java) startPassiveTask() spawned a new BukkitRunnable on every class instantiation. After N reloads there were N concurrent tasks all granting Resistance to low-health players. Same root cause as BUG-AB-01 (fixed in 4.5.1 for ArtemisBow). Fix: removed startPassiveTask() entirely. Low-health Resistance passive migrated to passiveTick(), driven by the single UnifiedPassiveTicker in AbilityManager.

    • BUG-HS-01 · HypnosisStaff — minionTask has no reference, cannot be cancelled on shutdown (HypnosisStaff.java) startMinionTask() spawned a BukkitRunnable but discarded the returned BukkitTask reference. On plugin shutdown, AbilityManager.shutdown() cancelled the unified passive ticker but had no way to reach the minion task — it kept running indefinitely after disable, pathfinding mobs toward offline players. Fix: stored the task as private BukkitTask minionTask. Added cleanup() override that cancels the task and calls cleanupMobs() for every tracked owner, removing all controlled mobs from the world.

    • BUG-GH-01 · GolemHammerdisable() is never called, passiveTask never cancelled (GolemHammer.java) GolemHammer stored its passive task in a field and provided a disable() method to cancel it, but nothing ever called disable() — not AbilityManager.shutdown(), not Main.onDisable(). The task ran forever after plugin disable, checking and modifying knockback-resistance attributes on every online player. Fix: renamed disable() to cleanup() (implementing the new Ability.cleanup() contract) so that AbilityRegistry.shutdownAll() picks it up automatically. disable() is kept as a @Deprecated delegate for any external callers.

    • BUG-JOIN-01 · PlayerJoinListenerloadPlayerStats() blocks main thread on every join (PlayerJoinListener.java) loadPlayerStats() executed a JDBC query synchronously on the server's main thread. With a remote MySQL database even a 20 ms query introduces a measurable tick-time spike and can cause lag for all players when multiple players join simultaneously. Fix: wrapped the call in Bukkit.getScheduler().runTaskAsynchronously().

    • BUG-JOIN-02 · PlayerJoinListenersavePlayerStats() immediately after loadPlayerStats() overwrites DB stats with zeroes (PlayerJoinListener.java) savePlayerStats() was called one line after loadPlayerStats() with the comment "Ensure record exists". Because loadPlayerStats() is now async (and was previously also a blocking call that hadn't finished before the save began), PlayerData still held its default values (kills=0, deaths=0, wins=0…) at save time. For any returning player, their stats were reset to zero on every server join. Fix: removed the erroneous savePlayerStats() call. New player records are created correctly by the ON CONFLICT DO UPDATE / INSERT OR REPLACE upsert in DatabaseManager the first time a real stat change is saved (on death, win, or disconnect).

    Medium

    • BUG-SHUT-01 · AbilityManager.shutdown() — only cancels the unified ticker; standalone tasks in GolemHammer, HypnosisStaff, ObsidianDagger, DeathNote are not cleaned up (AbilityManager.java, AbilityRegistry.java, Ability.java) Three abilities (GolemHammer, HypnosisStaff, ObsidianDagger) owned standalone BukkitRunnable tasks that nothing cancelled on shutdown. DeathNote had a working cleanup() method but it required a specific cast in Main.onDisable() — easy to break during refactors. Fix: added default void cleanup() {} to the Ability interface. Added AbilityRegistry.shutdownAll() which iterates all registered abilities and calls cleanup() on each. AbilityManager.shutdown() now delegates to shutdownAll() after cancelling the unified ticker. Main.onDisable() no longer needs any per-ability special cases.

    • BUG-ARENA-01 · Arena — 14 public fields bypass thread-safe getters/setters (Arena.java) name, world, cornucopia, spawns, hologramMap, holograms, originalBlocks, blockQueue, activeLegendaries, configuredLegendaries, temporaryLegendaries, pvpEnabled, netherEnabled, endEnabled, lifestealEnabled, hardcoreEnabled, veinminerEnabled, enabled, netherWorld, and maxPlayers were all public. Any class could modify them without going through the synchronized setters, silently breaking thread-safety guarantees on state, timer, and gameEnded. Fix: changed all fields to private. Added missing accessor methods (getHologramMap(), getHolograms(), getOriginalBlocks(), getBlockQueue(), getTemporaryLegendaries(), getActiveLegendaries(), setActiveLegendaries(), getNetherWorld(), setNetherWorld()). Updated all call-sites in ArenaManager, ArenaListener, DungeonManager, and MatchService to use the new accessors.

    • BUG-UM-01 · UpdateManager — missing connection timeout causes async thread to hang indefinitely (UpdateManager.java) HttpURLConnection was opened with no connectTimeout or readTimeout. If Modrinth's API was unreachable (DNS failure, network outage, server down), the async thread blocked forever, leaking a thread for the entire server uptime. Fix: added conn.setConnectTimeout(5000) and conn.setReadTimeout(5000) — the check fails gracefully within 5 s and logs a warning instead of hanging.

    Low

    • DEAD-CODE-01 · ArenaManager — three buildStyle* placeholder methods are unreachable dead code (ArenaManager.java) buildStyleClassic(), buildStyleUltimate(), and buildStyleSpeedSilver() were never called from anywhere in the codebase. They placed simple flat platforms without integrating into the Cornucopia pipeline (no chest scanning, no legendary hologram placement, no queue processing). They existed as early prototypes and were never completed. Fix: removed all three methods. The Cornucopia pipeline (buildCornucopia()startCornucopiaPhase2()scanForChests()startPhase3()finalizeArena()) is the sole code path for arena construction.

    Changed

    • pom.xml — version 4.5.64.5.7.
    • plugin.yml — version 4.5.64.5.7; description updated.

  • HungerGameSSS 4.5.6

    release20 марта 2026 г.

    [4.5.6] — Bug Sweep Pass 3 (2026-03-20)

    Fixed — 5 issues across 5 files

    High

    • BUG-PM-01 · PlayerManager / MatchService / WithdrawCommand — stolen heart item is unclickable after Component-API migration (PlayerManager.java, MatchService.java, WithdrawCommand.java) PlayerManager.onPlayerInteract identified stolen hearts by comparing meta.getDisplayName() to the language-file string. After the 4.5.4 fix migrated item names to meta.displayName(Component), the legacy getDisplayName() call returns "" — the comparison always failed and hearts could never be consumed. Fix: a NamespacedKey PDC tag stolen_heart is now written to every heart item on creation (MatchService and WithdrawCommand). PlayerManager reads the PDC tag instead of the display name.

    • BUG-EB-01 · EnderBow — position swap has no team check (EnderBow.java) performProjectileHit swapped the shooter and any hit LivingEntity unconditionally. Shooting a teammate teleported them to the shooter's position. Fix: added isFriendlyFire check before performing the swap; returns early for friendly targets.

    Medium

    • BUG-CB-01 · CornucopiaBuilder / ArenaManager — build progress spams all online players (CornucopiaBuilder.java, ArenaManager.java) clearArea() used Bukkit.broadcastMessage() for three status messages ("Pre-loading chunks", "Clearing area", "Clearing N%"). These messages were delivered to every player on the server, not just players in the arena being built. Fix: replaced all four broadcastMessage calls with plugin.getLogger().info().

    Low

    • DUPE-IMPORT · Duplicate import statements across 8 manager/model files (ScoreboardManager.java, ArenaManager.java, DungeonManager.java, Arena.java, LegendaryRecipe.java, HologramManager.java, LobbyManager.java, MessageManager.java) A previous tooling pass accidentally injected the ColorUtil import statement 9–27 times per file. While harmless at runtime, it produced compiler noise and inflated source size. Fix: de-duplicated all import blocks; one import per class per file.

    Changed

    • pom.xml — version 4.5.54.5.6.
    • plugin.yml — version 4.5.54.5.6.

    [4.5.5] — Bug Sweep Pass 2 (2026-03-20)

    Fixed — 7 issues across 6 files

    High

    • BUG-GT-01 · GameTask — world border Phase 1 and Phase 2 execute simultaneously for 60 seconds (GameTask.java) Phase 1 ran while timer ∈ (grace, main] and Phase 2 while timer ∈ (main−60, main]. During the last 60 s of the main phase both conditions were true, so Phase 2 called border.setSize() immediately after Phase 1 — resetting the border back to middleSize on every tick and then fast-shrinking to dmSize. Players saw the border snap suddenly rather than transitioning smoothly. Fix: made the ranges mutually exclusive — Phase 1 covers (grace, main−60] and Phase 2 covers (main−60, main] (else-if chain).

    • BUG-FM-01 · MatchService — feast never spawns from the second match onward (MatchService.java) resetArena() called feastManager.cleanup(arenaName) which removed feast chests but did not clear the feastSpawned guard set in FeastManager. On the next match the guard was still set, so spawnFeast() was never called again for the lifetime of the server. Fix: changed the call to feastManager.resetArena(arenaName) which calls both cleanup() and feastSpawned.remove().

    • BUG-CD-01 · MatchService — countdown cancels immediately because getGamePlayers() is empty during STARTING state (MatchService.java) The not-enough-players check in startCountdown used: arena.getGamePlayers().values().stream().filter(GamePlayer::isAlive).count() < 2 gamePlayers is not populated until the match transitions to PLAYING, so aliveCount was always 0 → the countdown broadcast "not_enough_players" and cancelled on the very first tick. Fix: replaced the alive-count check with arena.getPlayers().size() < 2, which counts the raw joined-player list that is populated during STARTING.

    Medium

    • BUG-AB-04 · DeathNotesendActionBar(String) deprecated on Paper 1.21 (DeathNote.java) The progress bar was sent via player.sendActionBar(String), a deprecated overload removed in newer Paper builds. Fix: wrapped the string with LegacyComponentSerializer.legacySection().deserialize().

    Low

    • BUG-AB-05 · VoidStaff, SoulGauntlet, DeathScythe, WitherSicklessendActionBar(String) deprecated (13 call-sites) (VoidStaff.java, SoulGauntlet.java, DeathScythe.java, WitherSickles.java) Same issue as BUG-AB-04. All 13 remaining String-based action-bar calls replaced with LegacyComponentSerializer.legacySection().deserialize().

    Changed

    • pom.xml — version 4.5.44.5.5.
    • plugin.yml — version 4.5.44.5.5.

  • HungerGameSSS 4.5.4

    release19 марта 2026 г.

    Fixed:

    • 8+ missing message keys, CloudSword stutter, PoseidonsTrident thrown hit
    • Legend name + lore had italic — fix all,use Paper Component API
  • HungerGameSSS 4.5.2

    release18 марта 2026 г.

    [4.5.2] — Artemis Bow & Passive Ticker Fix Pass (2026-03-18)

    Fixed — 8 issues across 5 files

    High

    • AB-OPEN-01 · ArtemisBow — memory leak: unbounded homing-arrow runnables accumulate on rapid fire (ArtemisBow.java) Each call to performProjectileLaunch spawned 5 independent BukkitRunnable instances (one per arrow). Players firing continuously in rapid succession could accumulate dozens of concurrent runnables with no upper bound, gradually degrading server TPS. Fix: added a per-player AtomicInteger counter (activeArrows map, capped at 15 = 3 simultaneous volleys). Each runnable increments on start and decrements on cancel/expire. New volleys are silently skipped if the cap is reached. Counter is cleaned up on performQuit and performDeath.

    • AB-OPEN-02 · ArtemisBowperformProjectileHit deals lightning damage without team check (ArtemisBow.java) After BUG-10 was fixed (switched to strikeLightningEffect + manual target.damage()), the new manual damage call had no isFriendlyFire guard. Result: Artemis Bow arrows could deal lightning damage to teammates. Fix: added if (target instanceof Player tp && isFriendlyFire(shooter, tp)) return; before calling target.damage(). Also added a null-guard: if projectile.getShooter() is not a Player, the method returns early.

    • AB-OPEN-03/05 · ArtemisBow — Sky Strike targets first entity in list, not closest (ArtemisBow.java) getNearbyEntities(20, 20, 20) returns entities in no guaranteed order. Sky Strike broke out of the loop on the first non-team entity — sometimes picking a distant mob over an enemy player standing 2 blocks away. Fix: replaced early-break loop with a full distanceSquared scan to find the closest valid target. Search radius is now configurable via sky_strike_radius (default 20).

    • AB-OPEN-04 · ArtemisBow — fan arrows use default Minecraft damage (~0.5 hearts) instead of bow charge (ArtemisBow.java) player.launchProjectile(Arrow.class) spawns arrows with base damage 2.0 — they ignore the actual bow charge the player applied. Only the centre (original) arrow inherited the real charge damage. Fix: added extraArrow.setDamage(baseArrow.getDamage()) when spawning each fan arrow so all 5 arrows deal equal damage consistent with bow charge.

    Medium

    • BUG-HH-02 · HadesHelm — standalone passive BukkitRunnable leaks on reload (HadesHelm.java) startPassive() spawned a new BukkitRunnable on every class instantiation. On plugin reload the old instance was discarded but the runnable kept running → N tasks after N reloads. Same root cause as BUG-AB-01 (fixed in 4.5.1 for ArtemisBow). Fix: removed startPassive() entirely. Night Vision, Invisibility-while-sneaking, and Fire Aura logic migrated to passiveTick() — driven by the single UnifiedPassiveTicker.

    • BUG-GC-01 · GuardianCannon — standalone passive BukkitRunnable leaks on reload (GuardianCannon.java) Same root cause as BUG-HH-02. startPassiveTask() ran on instantiation → N tasks after N reloads. Fix: Dolphins Grace water passive migrated to passiveTick().

    • BUG-LS-01 · LichStaff — standalone passive BukkitRunnable leaks on reload (LichStaff.java) Same root cause as BUG-HH-02. startPassiveTask() ran on instantiation → N tasks. Fix: Frost Walker passive migrated to passiveTick(). The ammo / shoot system is unaffected — it correctly uses per-use BukkitRunnable instances that self-cancel.

    Low

    • plugin.yml — api-version set to 4.4.1 (invalid format) (plugin.yml) Paper requires api-version to be a major.minor string (1.21), not a plugin version string. An invalid value causes a warning on every server start. Fix: changed api-version: 4.4.1api-version: 1.21.

    Changed

    • pom.xml — version 4.5.14.5.2.
    • plugin.yml — version 4.5.14.5.2; api-version corrected to 1.21; description updated.

  • HungerGameSSS 4.5.1

    release15 марта 2026 г.

    [4.5.1] — Logic Bug Fix Pass (2026-03-16)

    Fixed — 12 logic bugs across 11 weapon files

    Critical

    • BUG-PL-01 · PhantomLongbow — ability completely non-functional (PhantomLongbow.java) arrow.remove() was called immediately in performProjectileLaunch, then a BukkitRunnable was scheduled 1 tick later. By the time the runnable ran, projectile.isValid() was false → instant cancel → ability only granted invisibility, nothing else happened. Fix: stop calling remove(). Instead set arrow.setPickupStatus(DISALLOWED), setGravity(false), setDamage(0) so the arrow flies invisibly. The tracking runnable now checks isValid() || isOnGround() || isDead() and calls arrow.remove() itself.

    High

    • BUG-FY-02 · FountainOfYouth — inverted team check heals enemies, skips teammates (FountainOfYouth.java) isFriendlyFire returns true for teammates. The condition if (isFriendlyFire(player, target)) continue was therefore skipping teammates and healing enemies — the exact opposite of the comment. Fix: added !if (!isFriendlyFire(player, target)) continue.

    • BUG-VS-01 · VoidStaff — portal CD starts on first portal, blocks second placement (VoidStaff.java) portalCDs.put(...) ran unconditionally after any portal placement. Player placed portal #1, 40 s CD started, clicking again to place portal #2 hit the CD guard and was blocked — so a connected portal pair could never be created. Fix: moved portalCDs.put(...) inside the if (connected) branch only.

    • BUG-CC-03 · CorruptedCrossbow — extra bolts missing hg_ability metadata, no hit effects (CorruptedCrossbow.java) Extra bolts were tagged corrupted_extra and corrupted_bolt but not hg_ability. AbilityManager.handleProjectileHit only dispatches performProjectileHit when hg_ability is present. Result: extra bolts dealt only vanilla arrow damage with no Poison or Weakness effects. Fix: added extra.setMetadata("hg_ability", ...) when spawning each extra bolt.

    Medium

    • BUG-CSW-01 · CrimsonChainsword — bleed only fires 1 damage tick out of 5 (CrimsonChainsword.java) runTaskTimer(10L, 10L) increments ticks 0→1→2→3→4 then cancels. Damage condition was ticks % 20 == 0 — only ticks=0 satisfies this → 1 damage tick instead of 5. Fix: removed % 20 == 0 check. Period is already the interval; every call = one bleed tick.

    • BUG-SB-01 · ShadowBlade — Shadow Step has no team check, teleports behind teammates (ShadowBlade.java) Shadow Step's target loop had no isFriendlyFire guard, allowing teleport behind allies. Fix: added if (e instanceof Player tp && isFriendlyFire(player, tp)) continue;.

    • BUG-RH-01/02 · RavagerHorn — lazy location capture + no Ravager cleanup on quit/death (RavagerHorn.java) (1) Stampede lambdas called player.getLocation() lazily — waves diverged if player moved during the 16-tick animation. Fixed: capture castLoc = player.getLocation().clone() before the loop. (2) No performQuit/performDeath hook — Ravager persisted in the world after the player disconnected or died. Fixed: added activeRavagers map + dismountAndRemove() called on both events.

    • BUG-DN-01 · DeathNote — passive task runs every tick (20×/s), expensive raytracing (DeathNote.java) runTaskTimer(1L, 1L) = 20 rayTrace(range:50) calls per player per second. With 10 players = 200 raytrace/s. Changed TASK_PERIOD from 1L to 3L (~7 raytrace/s/player), still provides smooth progress bar updates.

    Low

    • BUG-VW-01 · VillagerWandtaggedForReward map memory leak (VillagerWand.java) Entries were only removed on entity death. Entities that fled, despawned, or were removed by arena reset left their UUID in the map indefinitely. Fixed: value now stores an expiry timestamp (now + rewardWindow). onEntityDeath checks now <= expiry. A cleanup task runs every 20 s to evict stale entries.

    • BUG-SG-01 · SoulGauntlet — action bar hardcodes -3 instead of blastCost (SoulGauntlet.java) If soul_blast_souls was changed in config, the displayed soul count was wrong. Fix: (charges - 3)(charges - blastCost).

    • BUG-WS-02 · WitherSicklesdualWieldActive desync when offhand is overwritten (WitherSickles.java) If a player manually placed another item into the offhand slot, dualWieldActive kept the UUID entry, blocking equipOffhand from re-running. Fixed onInventoryClick to detect this state and call dualWieldActive.remove(uuid).

    • BUG-AB-01 · ArtemisBow — standalone passive BukkitRunnable leaks on reload (ArtemisBow.java) startPassive() spawned a new task on every class instantiation. On plugin reload the old instance was discarded but the runnable kept running → N tasks after N reloads. Migrated to passiveTick() hook consumed by the single UnifiedPassiveTicker in AbilityManager. startPassive() and its runnable removed entirely.

    Changed

    • pom.xml — version 4.5.04.5.1.
    • plugin.yml — version 4.5.04.5.1; description updated.

  • HungerGameSSS 4.5.0

    release15 марта 2026 г.

    [4.5.0] — Weapon Overhaul (2026-03-16)

    Changed — 4 legendary weapons redesigned

    Mechanic ideas for the 4 weapons below were inspired by DemoRaHoplite Weapons by Demora ( Apache-2.0 ). Plugin page: </plugins/demorahopliteweapons>

    VoidStaff.java — Dual-mode system

    • Before: Single sneak+click portal / click shulker logic with no UI feedback.
    • After: Full mode-switching system (ported concept from DemoRaHoplite):
      • LEFT-CLICK toggles between Portal Mode and Shulker Mode.
      • Each mode has its own independent cooldown (portal 40 s, shulker 30 s).
      • Action bar shows current mode + remaining cooldown, refreshes on move and on item-switch (PlayerItemHeldEvent).
      • Cleanup on quit/death prevents state leaks.
      • StaffMode enum added for extensibility.

    Excalibur.java — True invincibility

    • Before: PotionEffect RESISTANCE V — very strong but not true invincibility (high enough burst damage could still kill the player).
    • After: event.setCancelled(true) at EventPriority.HIGHEST (concept from DemoRaHoplite) — 100 % damage blocked for the entire 5 s duration.
      • Attacker hears IRON_GOLEM_HURT sound when a hit is deflected.
      • Reflection + projectile deflect mechanics preserved from the old version.
      • activeInvincibility map with expiry timestamp replaces potion effect check.
      • isInvincible() guard added so performDamaged() (reflect) never fires during the invincibility window.
      • Cleanup on quit/death.

    WitherSickles.java — Dual-wield + throw mechanic

    • Before: Only AOE on-hit wither + lifesteal. No right-click action. No amount: 2 usage in gameplay.
    • After: Full dual-wield system (mechanic inspired by DemoRaHoplite):
      • Auto-equip offhand: when a player holds the Wither Sickles in main-hand, a protected copy is placed in the off-hand slot automatically.
      • Off-hand copy is lockedInventoryClickEvent, InventoryDragEvent, PlayerDropItemEvent, PlayerSwapHandItemsEvent all cancelled for it. Copy is removed when the player switches away.
      • Right-click throw (CD: 7 s, dmg 12, Wither II × duration × 2): projectile travels as a tick-based raycast with SOUL + WITCH particle trail.
      • passiveTick() shows throw cooldown in action bar while holding.
      • Legacy AOE wither + lifesteal preserved on melee hit.

    LichStaff.java — Balance pass

    • Before: Reload time 7 000 ms — could re-fire 4 ice-balls every 7 s, far too strong in arena PvP.
    • After: Reload time raised to 30 000 ms (30 s), matching DemoRaHoplite's cooldown_seconds: 30 for the equivalent weapon. This makes ammo management meaningful — players must choose when to spend their 4 shots.
      • Between-shot cooldown tightened to 800 ms (from 500 ms) to prevent accidental double-fire while staying responsive.
      • Reload-complete message now includes countdown ("Recharging in 30s...").
      • Reload-out sound changed to WITHER_DEATH (thematic) instead of BEACON_ACTIVATE.

    Updated

    • legend-items/void_staff.yml — lore updated to describe mode-switching.
    • legend-items/excalibur.yml — lore updated to say "TRUE invincibility".
    • legend-items/wither_sickles.yml — lore updated to describe dual-wield + throw.
    • legend-items/lich_staff.yml — lore updated to show 30s reload and ammo dots.
    • pom.xml — version 4.4.14.5.0.
    • plugin.yml — version 4.4.14.5.0; description updated.

  • HungerGameSSS 4.4.1

    release13 марта 2026 г.

    [4.4] — Final Bug-Fix Pass (All 32 Known Bugs Resolved)

    Fixed

    Low

    • L-01 · BungeeCord API deprecated in CooldownManager (CooldownManager.java) Two action-bar sends used player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(…)) — BungeeCord/Spigot legacy chat API that is deprecated on Paper 1.21 and may be removed in a future Paper version. Replaced with Paper-native player.sendActionBar(Component). BungeeCord imports (net.md_5.bungee.*) removed. Adventure LegacyComponentSerializer used for §-code → Component conversion to keep the existing colour format intact.

    • L-02 · ChatColor.translateAlternateColorCodes() deprecated across 9 files (ColorUtil.java, LegendaryRecipe.java, Arena.java, DungeonManager.java, HologramManager.java, MessageManager.java, ScoreboardManager.java, AbilityManager.java, LobbyManager.java, ArenaManager.java) ChatColor.translateAlternateColorCodes('&', s) is a Spigot legacy API marked deprecated on Paper 1.21. All 9 call-sites were replaced with ColorUtil.colorize(s). ColorUtil was rewritten to use LegacyComponentSerializer.legacyAmpersand() internally while still returning a §-coded String so all downstream sendMessage / setDisplayName call-sites work unchanged. A ColorUtil.strip() convenience method was also added using Adventure's PlainTextComponentSerializer.

    • L-03 · Player.setResourcePack() deprecated on Paper 1.21 (ConnectionListener.java) Both setResourcePack(url) and setResourcePack(url, hash) overloads are deprecated. The replacement is Adventure's ResourcePackRequest / ResourcePackInfo API, sent via player.sendResourcePacks(request). ConnectionListener now builds a ResourcePackRequest with an optional required flag and configurable prompt text (see config keys resource-pack.required and resource-pack.prompt).

    • L-04 · Loot tables hardcoded in LootTableManager.java (LootTableManager.java, loot.yml) All 30 loot entries (11 common, 11 uncommon, 8 rare) were hardcoded — impossible to change without recompiling. Extracted to a new bundled resource loot.yml. LootTableManager now calls plugin.saveResource("loot.yml", false) on first run then loads via YamlConfiguration. A reload() method is exposed so changes take effect with /perf reload (or equivalent) without restarting the server. Malformed entries log a warning and are skipped; the remaining valid entries load normally.

    • L-05 · 4 dungeon types are invisible aliases (DungeonManager.java) buildUndergroundDungeon and buildAncientMineshaft were one-line delegates to buildCrypt and buildGoldMine with no documentation. Server operators had no way to know they were paying the performance cost of spawning a dungeon that was identical to another one. Both methods are now annotated with deprecation Javadoc explaining the alias relationship, and a startup INFO message tells operators which config keys to set to false to remove the duplicates: dungeons.underground.enabled: false and dungeons.mineshaft.enabled: false.

    • L-08 · ConnectionListener — reconnect during active match loses game state (ConnectionListener.java, ArenaListener.java, GamePlayer.java) When a player disconnected and reconnected during a PLAYING or DEATHMATCH phase, the PlayerJoinEvent handler only sent the resource pack. The player spawned at world spawn (or last logout point), in the wrong game mode, with no scoreboard. Three changes:

      1. GamePlayer gains a lastLocation field updated by ArenaListener.onPlayerMove() on every block-level movement.
      2. ConnectionListener.onPlayerJoin() now calls MatchService.restoreSession() one tick after join to re-apply scoreboard, bossbar, and game mode.
      3. If the rejoining player was alive, they are teleported to gp.getLastLocation() so they return exactly where they were before the disconnect.

    [4.4.1] — Language update

    New Feature

    Added 6 new language(de,es,ja,ko,pt,zh) total 10

  • HungerGameSSS 4.3

    release13 марта 2026 г.

    [4.3] — Stabilization Patch 3

    Fixed

    High

    • H-04 · FeastManager — double announce + possible double-spawn (FeastManager.java) The announce-minutes list in config.yml previously included both 20 and 19, 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 == 0 at the moment the PLAYING state begins, and feastSeconds - 0 * 60 == 0 — meaning any 0-minute entry in the list would fire instantly. Fix: Guard timerSeconds <= 0 returns immediately. Added feastSpawned set (ConcurrentHashMap-backed) so the feast spawns exactly once per match regardless of how many scheduler ticks land on the boundary second. Added resetArena(name) to clear the flag between matches.

    • H-06 · DungeonManager.getMobHP() fallback 40.0 vs config 60.0 (DungeonManager.java) The config.yml declared dungeons.mob-hp: 60.0 as the intended default, but the code fallback was 40.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 to 60.0.

    Medium

    • M-04 · Excalibur — reflection hit dungeon mobs, bypassed team system (Excalibur.java) performDamaged reflected against any LivingEntity attacker. 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 for Player attackers). Reflection is a PvP mechanic; mob attacks should not trigger it. Changed the guard from instanceof LivingEntity attacker to instanceof 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 · MjolnirrotationAngle float unbounded, overflows after ~18 h (Mjolnir.java) rotationAngle was incremented by rotationSpeed on every passive tick with no upper bound. A 32-bit float mantissa has 24-bit precision; at 25°/tick × 20 ticks/s the angle exceeds 2²⁴ in roughly 18 hours of continuous operation, after which rotateY(Math.toRadians(angle)) silently produces garbage rotation matrices and the thrown hammer stops orbiting correctly. Both increment sites now use % 360f to keep the angle in [0, 360).

    • M-06 · VeinMinerListenermaxVeinSize not 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; maxVeinSize is now read from config on every BlockBreakEvent and passed as a parameter to findVein().

    • M-08 · ArenaListener — duplicate no-arg constructor using static Main.getInstance() (ArenaListener.java) A second constructor public ArenaListener() accessed Main.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 a SELECT on 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 with getPlayerStatsAsync(UUID) returning CompletableFuture<Map<String,Object>> dispatched to the Bukkit async scheduler. The original synchronous method is kept as @Deprecated getPlayerStats() (delegates to getPlayerStatsSync) for any call-sites that already run on async threads.

    • M-10 · PerformanceOptimizer.toggleMonitoring() always returned true (PerformanceOptimizer.java) The implementation was return activeTasks.get() >= 0 — an AtomicInteger is always ≥ 0, so the method always returned true regardless of monitoring state. Added AtomicBoolean monitoringEnabled (default true); toggleMonitoring() now inverts the flag and returns the new state.

    Low

    • L-06 · AbilityDispatcher.LEGEND_KEY static field initialised before onEnable() (AbilityDispatcher.java) The field private 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) caused AbilityDispatcher to be loaded before Main.onEnable() completed, getInstance() returned null and every subsequent ability dispatch threw NPE. Changed to lazy initialisation via a private getLegendKey() 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 in startCornucopiaPhase2(). 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() called originalBlocks.clear() destroying prior tracking (ArenaManager.java) Spawn cages and dungeon structures call originalBlocks.put() to record every block they place, enabling full restoration on arena reset. buildCornucopia() called arena.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. The clear() call is removed; CornucopiaBuilder already appends to the map with individual put() calls.

    • L-10 · GameTask extends BukkitRunnable but is never scheduled — double-tick risk (GameTask.java) GameTask was a dead BukkitRunnable subclass. The arena tick is driven entirely by ArenaManager.tick() via the global loop in Main.onEnable(). If a future developer saw the class and scheduled it directly, every arena would tick twice per second. GameTask.run() now throws UnsupportedOperationException immediately, surfacing the bug during development rather than silently corrupting timer state.

  • HungerGameSSS 4.1

    release13 марта 2026 г.

    [4.1] — Bug-Fix Patch 1

    Fixed

    Critical

    • C-03 · arena.max-players default value (config.yml) Changed the default from 1000 to 24. The previous value caused spawn-circle radii of ~1500 blocks, placing cage pistons in unloaded chunks and silently failing block placement — players were teleported into the void at match start.

    • C-02 · ArenaStartEvent fired twice per match (MatchService.java) Removed the premature callEvent(new ArenaStartEvent(arena)) call inside startMatch(). The event is now fired exactly once, inside releasePlayers() when the state transitions to PLAYING and the game actually begins. Previously, any listener hooked to ArenaStartEvent (scoreboards, rewards, third-party integrations) would execute twice.

    • C-05 · DeathNote — non-thread-safe HashMap in passive task (DeathNote.java) Replaced HashMap with ConcurrentHashMap for both progressMap and targetMap. These maps are written by the 1-tick passive BukkitRunnable and concurrently removed by onQuit / onDeath event callbacks.

    • C-04 · Arena.spectators — non-thread-safe ArrayList (Arena.java) Changed to Collections.synchronizedList(new ArrayList<>()). The spectator list is modified on the main thread (handleDeath) and iterated from async contexts (checkWin, scoreboard updates).

    High

    • H-05 · DatabaseManager.loadArena() did not mark players as alive (DatabaseManager.java) After loading player UUIDs on server reload, GamePlayer.setAlive(true) is now called for each loaded player. Without this, checkWin() saw zero alive players immediately after reload and ended the match in the same tick.

    • H-02 · ShadowBlade.revealPlayer() showed vanished player to entire server (ShadowBlade.java) revealPlayer() now iterates only the players in the same arena instead of calling getOnlinePlayers() server-wide. In multi-arena setups, players in other arenas would receive a spurious showPlayer() call. Both armorMap and vanishedPlayers upgraded from HashMap to ConcurrentHashMap to eliminate race conditions between the timed-reveal BukkitRunnable, onDeath, and onQuit callbacks.

    Medium

    • M-07 · Wrong permission node in BlockBreakListener (BlockBreakListener.java) Changed hg.admin to hoplitebr.admin to match the permission declared in plugin.yml. Admins with hoplitebr.admin could not break blocks inside an arena during WAITING / STARTING / ENDING phases.
  • HungerGameSSS 4.0

    release12 марта 2026 г.

    [4.0] — 2026-03-12 — Legendary Ability Audit & Fixes

    🐛 Bug Fixes — Legendary Abilities

    • 🛡️ ReinforcedElytra never activated (Critical)performSneak() called !checkCooldown(player) meaning the ability only "activated" while on cooldown and did nothing when ready. Fixed by removing the negation: if (checkCooldown(player)) return;

    • 💬 DeathNote spammed chat 20×/sec (Major)showProgress() called player.sendMessage() every tick. With the passive task running at 1-tick period, this sent 20 messages per second to chat, making the chat completely unusable while holding the item. Fixed by replacing sendMessage() with sendActionBar() and rendering a proper progress bar (colored block chars + target name).

    • 💊 FountainOfYouth healed all online players (Major) — The heal loop iterated over Bukkit.getOnlinePlayers() instead of the arena player list. This meant the item healed players in other arenas, spectators, and any player on the server within range regardless of game state. Fixed by iterating over arena.getPlayers() with a team-fire check.

    • 💀 HadesHelm applied Wither without checking if helm was equipped (Major)performDamaged() added Wither to any attacker when the player took damage, even if they had already unequipped the helm during combat. Fixed by adding AbilityManager.isAbilityItem(player.getInventory().getHelmet(), "hades_helm") guard at the top of the method.

    • 👢 HermesBoots cancelled fall damage without checking if boots were worn (Major) — Same class of bug as HadesHelm: performDamaged() suppressed all fall damage even after the player swapped out the boots. Fixed by guarding with isAbilityItem(player.getInventory().getBoots(), "hermes_boots").

    • 🔨 MidasSword used deprecated AttributeModifier constructor (Major) — The old AttributeModifier(UUID, String, double, Operation, EquipmentSlot) constructor is removed in Paper 1.21+. Replaced with the current AttributeModifier(NamespacedKey, double, Operation, EquipmentSlotGroup) API; modifier key stored as a NamespacedKey field to allow stable removal on each upgrade.

    • 🌿 EmeraldBlade used deprecated AttributeModifier constructor (Major) — Same issue as MidasSword. updateItemData() called new AttributeModifier(UUID.randomUUID(), "emerald_blade_damage", …). This also meant a fresh random UUID was generated on every deposit, so the old modifier was never removed, stacking damage indefinitely. Fixed with a stable NamespacedKey field (emerald_blade_damage) and the new constructor.

    • 🩸 CrimsonChainsword leaked revvedUp / bleedingTargets maps on disconnect/death (Minor) — Neither map was cleaned up when a player left or died, causing unbounded memory growth over long sessions. Added performQuit() and performDeath() overrides that remove the player's entries from both maps.


  • HG 3.9

    release12 марта 2026 г.

    [3.9] — 2026-03-12 — Bug Fix Release

    🐛 Bug Fixes

    • 💀 Game never ended after kills (Critical)MatchService.handleDeath() delegated to PlayerDeathListener to track the death but never called gp.setAlive(false) on the GamePlayer object. Because checkWin() uses GamePlayer.isAlive as its sole source of truth for alive-player counting, every dead player was still counted as alive — meaning the win condition (aliveCount == 1) was never reached, and games ran until the server was restarted. Fixed by marking the player dead at the very top of handleDeath().

    • 📦 Stray Mjolnir.java causing class ambiguity — A leftover copy of Mjolnir.java existed at me/hoplite/hungergamessss/ability/impl/Mjolnir.java from a package rename. It still imported classes from the current me.duong2012g namespace, which caused class-loading ambiguity at runtime. The file also contained outdated logic (isFriendlyFire replaced by a manual team equality check). Deleted.

    • 🔢 pom.xml version out of sync with plugin.ymlpom.xml declared 3.5 while plugin.yml was 3.9. This meant compiled JARs reported the wrong version in server logs and Modrinth update checks compared against the wrong baseline. Bumped pom.xml to 3.9.


  • 3.76

    release24 февраля 2026 г.

    fixed:

    ✅ Double death processing fix

    ✅ gamesPlayed database persistence

    ✅ onDisable stats flush

    ✅ Mjolnir lightning effect only

    ✅ isAbilityItem security fix

    ✅ Missing YAML files added

  • 3.7

    release24 февраля 2026 г.

    🔧 Critical Fixes Fixed Adventure API dependency - Resolved ClassNotFound crash

    Fixed Mjolnir import package - Resolved compile error

    Fixed database schema inconsistency - Fixed the_end column name

    Fixed empty exception handling - Added proper logging instead of silent failures

    🛡️ Stability Improvements

    Fixed memory leaks in DeathNote - Added proper cleanup on plugin disable Enhanced null safety - Added null checks in ArenaManager

1
...

Совместимость

Minecraft: Java Edition

Платформы

Авторы

Сведения

Лицензия:
Опубликован:5 месяцев назад
Обновлён:1 неделю назад
ID проекта:
Главная