Files
GameModes-SpeedHG/src/main/kotlin/club/mcscrims/speedhg/kit/KitManager.kt
TDSTOS 19bd708b59 Refactor language, kits, and event handling
Major refactor and bugfixes across language loading, kit lifecycle, and event handling:

- LanguageManager: Introduce LangData to hold string and list entries, load YAML lists alongside strings, and centralize retrieval (avoid reloading files at access time).
- GameManager: Use apply {} to configure worldBorder more concisely.
- KitManager.clearAll: Handle offline players by cleaning chargeData without calling lifecycle hooks (onActivate/onDeactivate cannot run for offline players).
- GoblinKit: Track per-player steal BukkitTask, cancel tasks on kit removal, only restore kits if player is still alive, and fix inventory removal by removing cached items and cleaning cache.
- KitEventDispatcher: Use null-safe chaining for victim passive hooks and early-return on non-block-position moves to ignore head-rotation events.
- GameStateListener: Add feastStarted flag placeholder and adjust iron ore handling/messages; add TODO for DB update.
- Extensions: Change legacySerializer visibility to internal.

These changes improve stability around scheduled tasks, offline cleanup, and language list support.
2026-03-25 03:28:52 +01:00

153 lines
4.6 KiB
Kotlin

package club.mcscrims.speedhg.kit
import club.mcscrims.speedhg.SpeedHG
import club.mcscrims.speedhg.kit.charge.PlayerChargeData
import org.bukkit.entity.Player
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
/**
* Manages kit registration, player selections, and the charge state for all online players.
*
* ## Typical usage flow
* ```
* // During plugin startup
* kitManager.registerKit(WarriorKit())
* kitManager.registerKit(ArcherKit())
*
* // During lobby (e.g. GUI click)
* kitManager.selectKit(player, kitManager.getKit("warrior")!!)
* kitManager.selectPlaystyle(player, Playstyle.AGGRESSIVE)
*
* // When the game round starts (replace the TODO in GameManager.startGame)
* kitManager.applyKit(player) // gives items, runs onAssign / passive.onActivate
*
* // When the round ends
* kitManager.clearAll() // runs onRemove / passive.onDeactivate for every player
* ```
*/
class KitManager(
private val plugin: SpeedHG
) {
// All kits available this session, keyed by Kit.id
private val registeredKits = ConcurrentHashMap<String, Kit>()
// Lobby selections — set before the round starts
private val selectedKits = ConcurrentHashMap<UUID, Kit>()
private val selectedPlaystyles = ConcurrentHashMap<UUID, Playstyle>()
// Live charge state — populated by applyKit, cleared by removeKit/clearAll
private val chargeData = ConcurrentHashMap<UUID, PlayerChargeData>()
// -------------------------------------------------------------------------
// Kit registration
// -------------------------------------------------------------------------
fun registerKit(
kit: Kit
) {
registeredKits[kit.id] = kit
plugin.logger.info("[KitManager] Registered kit: ${kit.id}")
}
fun getRegisteredKits(): Collection<Kit> = registeredKits.values
fun getKit( id: String ): Kit? = registeredKits[id]
// -------------------------------------------------------------------------
// Player selections (lobby phase)
// -------------------------------------------------------------------------
fun selectKit(
player: Player,
kit: Kit
) {
selectedKits[player.uniqueId] = kit
}
/**
* Set the playstyle for a player.
* Defaults to [Playstyle.DEFENSIVE] if never called.
*/
fun selectPlaystyle(
player: Player,
playstyle: Playstyle
) {
selectedPlaystyles[player.uniqueId] = playstyle
}
fun getSelectedKit( player: Player ): Kit? = selectedKits[player.uniqueId]
fun getSelectedPlaystyle( player: Player ): Playstyle =
selectedPlaystyles[player.uniqueId] ?: Playstyle.DEFENSIVE
// -------------------------------------------------------------------------
// Game lifecycle
// -------------------------------------------------------------------------
/**
* Apply the player's selected kit at game start.
*
* Call this from [GameManager.startGame] for every online player, **after** teleportation.
* If the player has not selected a kit, this is a no-op.
*/
fun applyKit(
player: Player
) {
val kit = selectedKits[player.uniqueId] ?: return
val playstyle = getSelectedPlaystyle( player )
val active = kit.getActiveAbility( playstyle )
chargeData[player.uniqueId] = PlayerChargeData( active.hitsRequired )
kit.onAssign( player, playstyle )
kit.getPassiveAbility( playstyle ).onActivate( player )
kit.giveItems( player, playstyle )
}
/**
* Remove and clean up a player's kit (round over, player eliminated, etc.).
* Safe to call even if the player has no kit assigned.
*/
fun removeKit(
player: Player
) {
val kit = selectedKits[player.uniqueId] ?: return
val playstyle = getSelectedPlaystyle( player )
kit.getPassiveAbility( playstyle ).onDeactivate( player )
kit.onRemove( player )
chargeData.remove( player.uniqueId )
}
/**
* Remove all kits and clear every selection.
* Call this at the end of each round, **before** resetting other game state.
*/
fun clearAll()
{
selectedKits.keys.toList().forEach { uuid ->
val player = plugin.server.getPlayer( uuid )
if ( player != null )
removeKit( player )
else
{
// Daten bereinigen ohne Lifecycle-Hooks (Spieler ist offline)
chargeData.remove( uuid )
// Hinweis: onDeactivate/onRemove können nicht aufgerufen werden
// → Kits müssen in onActivate gestartete Tasks UUID-basiert führen
}
}
selectedKits.clear()
selectedPlaystyles.clear()
chargeData.clear()
}
// -------------------------------------------------------------------------
// Charge access (used by KitEventDispatcher)
// -------------------------------------------------------------------------
fun getChargeData( player: Player ): PlayerChargeData? = chargeData[player.uniqueId]
}