Add kit system, KitManager and Goblin kit

Introduce a full kit framework and supporting utilities.

- Add core kit API: Kit, Playstyle, ActiveAbility, PassiveAbility, AbilityResult, charge state and PlayerChargeData.
- Implement KitManager for registration, lobby selections, apply/remove/clear lifecycle and charge tracking.
- Add KitEventDispatcher listener to centralize kit event handling (interact, hits, move) and integrate passive/active hooks.
- Provide example kit implementations: GoblinKit (functional abilities) and TemplateKit (reference).
- Add utilities: ItemBuilder and WorldEditUtils (WorldEdit-based sphere creation).
- Integrate into plugin: SpeedHG now initialises KitManager, registers kits and KitEventDispatcher, applies kits at game start and clears on end.
- LanguageManager: add default message/list/component helpers.
- Build changes: bump Kotlin plugin to 2.2.0 and add WorldEdit compileOnly deps; also expose legacySerializer in Extensions.

These changes implement the kit feature set (items, abilities, charge/recharge flow) and wire it into the game lifecycle.
This commit is contained in:
TDSTOS
2026-03-25 02:27:53 +01:00
parent e411879b20
commit 9d6bd6a6b8
18 changed files with 1330 additions and 6 deletions

View File

@@ -0,0 +1,87 @@
package club.mcscrims.speedhg.kit
import club.mcscrims.speedhg.kit.ability.ActiveAbility
import club.mcscrims.speedhg.kit.ability.PassiveAbility
import net.kyori.adventure.text.Component
import org.bukkit.Material
import org.bukkit.entity.Player
/**
* Base class for every kit in SpeedHG.
*
* ## How to create a new kit
* 1. Extend this class.
* 2. Implement all abstract members.
* 3. For each [Playstyle], create a private inner class extending [ActiveAbility]
* and another extending [PassiveAbility].
* 4. Return the correct instance from [getActiveAbility] / [getPassiveAbility]
* using a `when(playstyle)` expression.
* 5. Register the kit via `plugin.kitManager.registerKit(YourKit())` in [SpeedHG.onEnable].
*
* See [TemplateKit] for a fully annotated example.
*/
abstract class Kit {
/** Unique snake_case identifier (e.g. `"warrior"`, `"archer"`). */
abstract val id: String
/** Coloured display name shown in the kit selection GUI. */
abstract val displayName: Component
/** Short lore lines shown on the item in the kit GUI. */
abstract val lore: List<String>
/** Icon used in the kit selection GUI. */
abstract val icon: Material
// -------------------------------------------------------------------------
// Playstyle-specific abilities — implement with a `when` expression
// -------------------------------------------------------------------------
/**
* Return the [ActiveAbility] for the given [playstyle].
*
* ```kotlin
* override fun getActiveAbility(playstyle: Playstyle) = when (playstyle) {
* Playstyle.AGGRESSIVE -> AggressiveActive()
* Playstyle.DEFENSIVE -> DefensiveActive()
* }
* ```
*
* **Performance note:** This is called frequently by [KitEventDispatcher].
* Prefer returning a cached singleton (`private val aggressiveActive = AggressiveActive()`)
* over allocating a new instance on each call.
*/
abstract fun getActiveAbility( playstyle: Playstyle ): ActiveAbility
/** Return the [PassiveAbility] for the given [playstyle]. Same caching advice applies. */
abstract fun getPassiveAbility( playstyle: Playstyle ): PassiveAbility
// -------------------------------------------------------------------------
// Item distribution
// -------------------------------------------------------------------------
/**
* Give the player their kit-specific items at game start (after teleportation).
* The standard HG items (soup, compass, etc.) are already given by [GameManager].
* Only add kit-exclusive items here.
*/
abstract fun giveItems( player: Player, playstyle: Playstyle )
// -------------------------------------------------------------------------
// Lifecycle hooks (optional)
// -------------------------------------------------------------------------
/**
* Called once per round when the kit is applied to [player].
* Use for permanent potion effects, scoreboard objectives, repeating tasks, etc.
* The matching [PassiveAbility.onActivate] is called immediately after this.
*/
open fun onAssign( player: Player, playstyle: Playstyle ) {}
/**
* Called when the kit is removed (game over / round reset).
* The matching [PassiveAbility.onDeactivate] is called immediately before this.
*/
open fun onRemove( player: Player ) {}
}