2026-04-15 21:51:35 +02:00
2026-04-15 21:51:35 +02:00
2025-12-01 03:46:14 +01:00
2025-12-01 03:45:44 +01:00
2025-12-01 19:35:32 +01:00
2026-04-14 05:07:56 +02:00
2025-12-01 03:45:44 +01:00

SpeedHG

A Spigot / Paper plugin for the SpeedHG Hunger-Games variant by McScrims Network.
Built with Kotlin · Paper API 1.21 · Version 1.0.0


Table of Contents


Overview

SpeedHG is a competitive Hunger-Games game-mode where every player selects a Kit (with an Aggressive or Defensive playstyle) and up to 2 passive Perks before the round starts. The world border steadily shrinks, disasters trigger, and a feast spawns mid-game to force confrontation.

Key features at a glance:

  • 17 fully-implemented Kits, each with 2 Playstyles (Aggressive / Defensive)
  • 14 passive Perks with persistent DB-backed selection
  • Hit-charge system for active abilities (configurable hits-to-charge per kit)
  • Dynamic WorldBorder shrink, Feast, and Pit events
  • Anti-runner detection, soup-based healing, team support
  • Lunar Client integration (waypoints, scoreboard)
  • Discord webhook for game results
  • MySQL-backed stats, ranking, and leaderboard
  • Fully i18n-able via en_US.yml (MiniMessage format)

Dependencies

Dependency Role
WorldEdit Arena construction for GladiatorKit
Apollo-Bukkit Lunar Client integration
Kup Internal rank/permission bridge

All three must be present on the server; the plugin will not load without them.


Game Flow

LOBBY → STARTING → INVINCIBILITY → INGAME → ENDING
Phase Description
LOBBY Waiting for min-players. Every 15 s an idle message is broadcast.
STARTING Countdown (lobby-time seconds). Aborts if player count drops.
INVINCIBILITY Players are teleported, kits & perks applied, Speed I + Haste I active. No damage dealt.
INGAME Combat enabled, WorldBorder shrinks, timer counts up, Feast & Pit events fire.
ENDING Winner announced, server shuts down after a short delay.

Default timing values (overridable in config.yml):

Setting Default
Min players 8
Lobby time 120 s
Invincibility time 120 s
Border start 600 blocks
Border end 150 blocks
Border shrink time 900 s

Configuration

config.yml

game:
  beta: true
  min-players: 2
  lobby-time: 60
  invincibility-time: 120
  border-start: 600.0
  border-end: 100.0
  border-shrink-time: 900   # seconds
  max-radius-teleport: 50.0
  ranked: false

teams:
  enabled: false
  preset-count: 10
  max-size: 2

anti-runner:
  enabled: false

discord:
  enabled: false
  webhook-url: "YOUR_WEBHOOK_URL"

database:
  host: "localhost"
  port: 3306
  name: "speedhg"
  username: "speedhg_user"
  password: "your_password"
  use-ssl: false
  pool:
    max-size: 10
    min-idle: 2

SPEEDHG_CUSTOM_SETTINGS Environment Variable

For production overrides without touching config.yml, pass a JSON blob via environment variable (see Runtime Configuration).


Kits

Players select a kit in the lobby and choose a Playstyle (Aggressive [AGG] / Defensive [DEF]).
Active abilities are triggered by right-clicking the kit item. Most abilities require a configurable number of hits to charge first (global_hits_required, default: 15).

Kit Aggressive Active Defensive Active Passive (AGG) Passive (DEF)
Anchor Summon Iron Golem anchor — no-knock + bonus damage in radius ← same Partial knockback resistance Partial knockback resistance
Armorer Strength I on kill Protection I on armor
Backup
BlackPanther Wakanda Leap — leap forward, hit enemies on land ← same
Blitzcrank Rocket Grab — pull nearest enemy to you ← same
Gladiator Sky arena 1v1 duel (glass cage, Wither IV after 180 s) ← same
Goblin Steal enemy kit for 60 s Spawn a bunker for cover
IceMage Ice Spike Burst — cone of freezing projectiles Freeze Burst — 16 snowballs in circle Speed in cold biomes, slowness chance on hit 33 % slowness proc on being hit
Ninja Vanish + backstab: teleport behind last-hit enemy Shadow Step: teleport to nearest enemy Last-hit tracking
Puppet Puppet Trap — summon entity traps ← similar
Rattlesnake Pounce — sneak-charge then leap, applies Poison II Poison II on pounce hit 25 % reflect Poison II on being hit
Spielo
Tesla Lightning strike AoE ← same Knock-back + ignite reflect on being hit
TheWorld Shockwave + 3× Blink forward Shockwave + Freeze nearby enemies (10 s, 5-hit cap) Frozen enemies have a 5-hit break cap
Trident Dive — launch up, lightning on landing (charge-based) Parry — chance to bounce + Slowness on attacker
Venom Venom Blast — Blindness I + Wither I + 2 hearts instant damage Barrier — absorbs up to 15 damage, reflects projectiles
Voodoo Curse — apply Glowing + delayed damage to nearby enemies ← similar 20 % Wither proc on hit Speed + Regen while cursed enemies are nearby

Kit Item

Each kit provides its signature item in the player's inventory at game start. Items are tracked in cachedItems (UUID → List<ItemStack>) and cleaned up on onRemove.


Perks

Players may equip up to 2 Perks before the round starts. Selections are persisted to the database per-player UUID.

Perk Effect
Adrenaline Dropping below 3 hearts → Speed II for 5 s (30 s cooldown)
Berserker Below 4 hearts → deal 15 % more melee damage
Bloodlust On kill: Speed I + Regen I for 5 s
Enderblood Ender Pearl landings deal no fall damage
Evasion 15 % chance to dodge incoming projectiles
Featherweight Full immunity to fall damage
Ghost Invisible to compass tracking and the Oracle perk
Gourmet Consuming soup → Regen I + Speed I for 2 s
Last Stand Taking damage below 3 hearts → Resistance II + Absorption I for 4 s (60 s cooldown)
Momentum Sprint for 4 s without combat → Speed I
Oracle Shows kit + distance to the nearest enemy on sneak / compass
Pyromaniac Immune to fire, lava, magma blocks, and burn ticks
Scavenger Every kill drops an extra Golden Apple at the corpse
Vampire 10 % chance on melee hit to heal ½ heart

Commands

Command Alias Permission Description
/kit <name> <playstyle> Select a kit via command
/kitinfo <id> /perkinfo <id> Show name + lore of a kit or perk
/perks Open the Perk Selector GUI
/leaderboard View the top 10 players
/timer <time> speedhg.admin.timer Change the current game timer
/ranking <toggle|status|rank [player]> speedhg.admin.ranking Manage the ranking system
/help Show the help screen

Permissions

Node Default Description
speedhg.bypass false Join while the game is running
speedhg.admin.timer op Change the game timer
speedhg.admin.ranking op Manage ranking
speedhg.admin.staff false Staff flag for Lunar Client

Architecture

SpeedHG (main class)
├── GameManager           state machine, game loop, compass, win check
├── KitManager            kit registry, player selections, hit-charge state
├── PerkManager           perk registry, player selections, DB persistence
├── KitEventDispatcher    single Listener delegating all kit events
├── PerkEventDispatcher   single Listener delegating all perk events
├── ScoreboardManager     sidebar scoreboard
├── TablistManager        tab list (Lunar Client / Volcano rank)
├── AntiRunningManager    cave-aware anti-runner detection
├── DisasterManager       periodic in-game disasters
├── FeastManager          mid-game feast event
├── PitManager            pit event
├── RankingManager        ELO / rank logic
├── StatsManager          kill/death/win tracking (MySQL)
├── DatabaseManager       HikariCP connection pool
├── LanguageManager       MiniMessage i18n
├── LunarClientManager    Lunar Client waypoints, scoreboard
├── DiscordWebhookManager post-game Discord messages
├── WorldManager          map archive extraction & world loading
├── DataPackManager       biome overrides via datapack
└── CustomGameManager     SPEEDHG_CUSTOM_SETTINGS JSON parsing

Thread Safety

All per-player state maps use ConcurrentHashMap. BukkitTask references are canceled and removed in every onRemove / onDeactivate hook.

Kit Charge System

When a player's kit is applied, a PlayerChargeData object is stored in KitManager. Each confirmed melee hit (≥ 90 % attack strength) increments the charge counter. When it reaches hitsRequired, the state transitions to READY and the player receives an ActionBar notification. Hitting right-click with the ability item triggers ActiveAbility.execute() and resets the charge.

hitsRequired priority: kit-specific override > global_hits_required > hardcoded default.
Kits that use an internal cooldown instead (e.g. TridentKit Dive) set hardcodedHitsRequired = 0.


Adding a New Kit

  1. Create src/main/kotlin/.../kit/impl/YourKit.kt extending Kit().
  2. Implement all abstract members (id, displayName, lore, icon, cachedItems, giveItems, getActiveAbility, getPassiveAbility).
  3. Create private inner class for each ability (Active & Passive, for each Playstyle).
  4. Put magic numbers in a companion object with UPPER_SNAKE_CASE constants.
  5. Wire configurable values through override().getLong("key") ?: DEFAULT_*.
  6. Add language keys under kits.<id>.* in src/main/resources/languages/en_US.yml.
  7. Register in SpeedHG.registerKits():
    kitManager.registerKit( YourKit() )
    

Adding a New Perk

  1. Create src/main/kotlin/.../perk/impl/YourPerk.kt extending Perk().
  2. Implement id, displayName, lore, icon.
  3. Override only the event hooks you need (onActivate, onDeactivate, onHitEnemy, etc.).
  4. Clean up all state in onDeactivate.
  5. Add language keys under perks.<id>.* in en_US.yml.
  6. Register in SpeedHG.registerPerks():
    perkManager.registerPerk( YourPerk() )
    

Runtime Configuration via SPEEDHG_CUSTOM_SETTINGS

Pass a JSON blob as an environment variable to override game and kit settings without redeploying:

{
  "game": {
    "min_players": 4,
    "lobby_time": 45,
    "invincibility_time": 60,
    "border_start": 500.0,
    "border_end": 50.0,
    "border_shrink_time": 720
  },
  "kits": {
    "global_hits_required": 12,
    "kits": {
      "ninja": {
        "hits_required": 10,
        "extras": {
          "cooldown_ms": 8000,
          "backstab_damage": 6.0
        }
      },
      "gladiator": {
        "arena_radius": 11,
        "arena_height": 7,
        "wither_after_seconds": 180
      },
      "trident": {
        "extras": {
          "max_dive_charges": 3,
          "sequence_cooldown_ms": 12000,
          "lightning_radius": 4.0,
          "lightning_damage": 4.0,
          "parry_chance": 0.35,
          "parry_slowness_ticks": 60
        }
      }
    }
  }
}

Kit-level extras keys are free-form strings resolved at runtime via KitOverride.getLong(), .getInt(), and .getDouble() with the kit's own hardcoded defaults as fallback.


McScrims Network · play.mcscrims.club

Description
No description provided
Readme 784 KiB
Languages
Kotlin 100%