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.
This commit is contained in:
@@ -13,8 +13,13 @@ class LanguageManager(
|
|||||||
private val plugin: JavaPlugin
|
private val plugin: JavaPlugin
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private data class LangData(
|
||||||
|
val strings: Map<String, String>,
|
||||||
|
val lists: Map<String, List<String>>
|
||||||
|
)
|
||||||
|
|
||||||
// Map: Sprachcode -> (Key -> Nachricht)
|
// Map: Sprachcode -> (Key -> Nachricht)
|
||||||
private val languages = ConcurrentHashMap<String, Map<String, String>>()
|
private val languages = ConcurrentHashMap<String, LangData>()
|
||||||
private val miniMessage = MiniMessage.miniMessage()
|
private val miniMessage = MiniMessage.miniMessage()
|
||||||
private val defaultLanguage = plugin.config.getString("default.language", "en_US")!!
|
private val defaultLanguage = plugin.config.getString("default.language", "en_US")!!
|
||||||
|
|
||||||
@@ -37,12 +42,15 @@ class LanguageManager(
|
|||||||
val langCode = file.nameWithoutExtension
|
val langCode = file.nameWithoutExtension
|
||||||
val config = YamlConfiguration.loadConfiguration( file )
|
val config = YamlConfiguration.loadConfiguration( file )
|
||||||
|
|
||||||
val messages = config.getKeys( true )
|
val strings = config.getKeys( true )
|
||||||
.filter { config.isString( it ) }
|
.filter { config.isString( it ) }
|
||||||
.associateWith { config.getString( it ) }
|
.associateWith { config.getString( it )!! }
|
||||||
|
|
||||||
languages[ langCode ] = messages as Map<String, String>
|
val lists = config.getKeys( true )
|
||||||
plugin.logger.info("Sprache geladen: $langCode (${messages.size} Nachrichten)")
|
.filter { config.isList( it ) }
|
||||||
|
.associateWith { config.getStringList( it ) }
|
||||||
|
|
||||||
|
languages[ langCode ] = LangData( strings, lists )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,14 +70,14 @@ class LanguageManager(
|
|||||||
{
|
{
|
||||||
val locale = player.locale().toString()
|
val locale = player.locale().toString()
|
||||||
val langMap = languages[ locale ] ?: languages[ defaultLanguage ]
|
val langMap = languages[ locale ] ?: languages[ defaultLanguage ]
|
||||||
return langMap?.get( key ) ?: "<red>Missing Key: $key</red>"
|
return langMap?.strings?.get( key ) ?: "<red>Missing Key: $key</red>"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDefaultRawMessage(
|
fun getDefaultRawMessage(
|
||||||
key: String
|
key: String
|
||||||
): String
|
): String
|
||||||
{
|
{
|
||||||
return languages[ defaultLanguage ]?.get( key ) ?: "<red>Missing Key: $key</red>"
|
return languages[ defaultLanguage ]?.strings?.get( key ) ?: "<red>Missing Key: $key</red>"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRawMessageList(
|
fun getRawMessageList(
|
||||||
@@ -77,25 +85,17 @@ class LanguageManager(
|
|||||||
key: String
|
key: String
|
||||||
): List<String>
|
): List<String>
|
||||||
{
|
{
|
||||||
var locale = player.locale().toString()
|
val locale = player.locale().toString()
|
||||||
val langMap = languages[ locale ]
|
val data = languages[ locale ] ?: languages[ defaultLanguage ]
|
||||||
|
return data?.lists?.get( key ) ?: listOf( "<red>Missing List: $key</red>" )
|
||||||
if ( langMap == null ) {
|
|
||||||
locale = defaultLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
val file = File( plugin.dataFolder, "languages/$locale.yml" )
|
|
||||||
val config = YamlConfiguration.loadConfiguration( file )
|
|
||||||
return if (config.contains( key )) config.getStringList( key ) else listOf( "<red>Missing List: $key</red>" )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDefaultRawMessageList(
|
fun getDefaultRawMessageList(
|
||||||
key: String
|
key: String
|
||||||
): List<String>
|
): List<String>
|
||||||
{
|
{
|
||||||
val file = File( plugin.dataFolder, "languages/$defaultLanguage.yml" )
|
val data = languages[ defaultLanguage ]
|
||||||
val config = YamlConfiguration.loadConfiguration( file )
|
return data?.lists?.get( key ) ?: listOf( "<red>Missing List: $key</red>" )
|
||||||
return if (config.contains( key )) config.getStringList( key ) else listOf( "<red>Missing List: $key</red>" )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getComponent(
|
fun getComponent(
|
||||||
@@ -116,7 +116,7 @@ class LanguageManager(
|
|||||||
placeholders: Map<String, String>
|
placeholders: Map<String, String>
|
||||||
): Component
|
): Component
|
||||||
{
|
{
|
||||||
val raw = languages[ defaultLanguage ]?.get( key ) ?: "<red>Missing Key: $key</red>"
|
val raw = languages[ defaultLanguage ]?.strings?.get( key ) ?: "<red>Missing Key: $key</red>"
|
||||||
val tags = placeholders.map { (k, v) -> Placeholder.parsed( k, v ) }
|
val tags = placeholders.map { (k, v) -> Placeholder.parsed( k, v ) }
|
||||||
return miniMessage.deserialize( raw, *tags.toTypedArray() )
|
return miniMessage.deserialize( raw, *tags.toTypedArray() )
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,11 +134,12 @@ class GameManager(
|
|||||||
world.time = 0
|
world.time = 0
|
||||||
world.setStorm( false )
|
world.setStorm( false )
|
||||||
|
|
||||||
val border = world.worldBorder
|
world.worldBorder.apply {
|
||||||
border.center = Location( world, 0.0, 0.0, 0.0 )
|
center = Location( world, 0.0, 0.0, 0.0 )
|
||||||
border.size = startBorder
|
size = startBorder
|
||||||
border.damageBuffer = 0.0
|
damageBuffer = 0.0
|
||||||
border.damageAmount = 1.0
|
damageAmount = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
val speedEffect = PotionEffect(
|
val speedEffect = PotionEffect(
|
||||||
PotionEffectType.SPEED,
|
PotionEffectType.SPEED,
|
||||||
|
|||||||
@@ -129,7 +129,16 @@ class KitManager(
|
|||||||
fun clearAll()
|
fun clearAll()
|
||||||
{
|
{
|
||||||
selectedKits.keys.toList().forEach { uuid ->
|
selectedKits.keys.toList().forEach { uuid ->
|
||||||
plugin.server.getPlayer( uuid )?.let { removeKit( it ) }
|
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()
|
selectedKits.clear()
|
||||||
selectedPlaystyles.clear()
|
selectedPlaystyles.clear()
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.bukkit.Material
|
|||||||
import org.bukkit.Sound
|
import org.bukkit.Sound
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@@ -98,12 +99,15 @@ class GoblinKit : Kit() {
|
|||||||
override fun onRemove(
|
override fun onRemove(
|
||||||
player: Player
|
player: Player
|
||||||
) {
|
) {
|
||||||
val items = cachedItems[ player.uniqueId ] ?: return
|
aggressiveActive.cancelStealTask( player )
|
||||||
player.inventory.removeAll { items.contains( it ) }
|
val items = cachedItems.remove( player.uniqueId ) ?: return
|
||||||
|
items.forEach { player.inventory.remove( it ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class AggressiveActive : ActiveAbility( Playstyle.AGGRESSIVE ) {
|
private inner class AggressiveActive : ActiveAbility( Playstyle.AGGRESSIVE ) {
|
||||||
|
|
||||||
|
private val plugin get() = SpeedHG.instance
|
||||||
|
|
||||||
override val name: String
|
override val name: String
|
||||||
get() = plugin.languageManager.getDefaultRawMessage( "kits.goblin.items.steal.name" )
|
get() = plugin.languageManager.getDefaultRawMessage( "kits.goblin.items.steal.name" )
|
||||||
|
|
||||||
@@ -116,6 +120,8 @@ class GoblinKit : Kit() {
|
|||||||
override val triggerMaterial: Material
|
override val triggerMaterial: Material
|
||||||
get() = Material.GLASS
|
get() = Material.GLASS
|
||||||
|
|
||||||
|
private val activeStealTasks = ConcurrentHashMap<UUID, BukkitTask>()
|
||||||
|
|
||||||
override fun execute(
|
override fun execute(
|
||||||
player: Player
|
player: Player
|
||||||
): AbilityResult
|
): AbilityResult
|
||||||
@@ -129,16 +135,25 @@ class GoblinKit : Kit() {
|
|||||||
val currentKit = plugin.kitManager.getSelectedKit( player )
|
val currentKit = plugin.kitManager.getSelectedKit( player )
|
||||||
?: return AbilityResult.ConditionNotMet( "Error while copying kit" )
|
?: return AbilityResult.ConditionNotMet( "Error while copying kit" )
|
||||||
|
|
||||||
|
activeStealTasks.remove( player.uniqueId )
|
||||||
|
|
||||||
plugin.kitManager.removeKit( player )
|
plugin.kitManager.removeKit( player )
|
||||||
plugin.kitManager.selectKit( player, targetKit )
|
plugin.kitManager.selectKit( player, targetKit )
|
||||||
plugin.kitManager.applyKit( player )
|
plugin.kitManager.applyKit( player )
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskLater( plugin, { ->
|
val task = Bukkit.getScheduler().runTaskLater( plugin, { ->
|
||||||
plugin.kitManager.removeKit( player )
|
activeStealTasks.remove( player.uniqueId )
|
||||||
plugin.kitManager.selectKit( player, currentKit )
|
// Nur wiederherstellen, wenn Spieler noch alive und Spiel läuft
|
||||||
plugin.kitManager.applyKit( player )
|
if (plugin.gameManager.alivePlayers.contains( player.uniqueId ))
|
||||||
|
{
|
||||||
|
plugin.kitManager.removeKit( player )
|
||||||
|
plugin.kitManager.selectKit( player, currentKit )
|
||||||
|
plugin.kitManager.applyKit( player )
|
||||||
|
}
|
||||||
}, 20L * 60)
|
}, 20L * 60)
|
||||||
|
|
||||||
|
activeStealTasks[ player.uniqueId ] = task
|
||||||
|
|
||||||
player.playSound( player.location, Sound.ENTITY_EVOKER_CAST_SPELL, 1f, 1.5f )
|
player.playSound( player.location, Sound.ENTITY_EVOKER_CAST_SPELL, 1f, 1.5f )
|
||||||
player.sendActionBar(player.trans( "kits.goblin.messages.stole_kit", "kit" to legacySerializer.serialize( targetKit.displayName )))
|
player.sendActionBar(player.trans( "kits.goblin.messages.stole_kit", "kit" to legacySerializer.serialize( targetKit.displayName )))
|
||||||
|
|
||||||
@@ -152,10 +167,18 @@ class GoblinKit : Kit() {
|
|||||||
player.sendActionBar(player.trans( "kits.goblin.messages.ability_charged" ))
|
player.sendActionBar(player.trans( "kits.goblin.messages.ability_charged" ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cancelStealTask(
|
||||||
|
player: Player
|
||||||
|
) {
|
||||||
|
activeStealTasks.remove( player.uniqueId )?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class DefensiveActive : ActiveAbility( Playstyle.DEFENSIVE ) {
|
private inner class DefensiveActive : ActiveAbility( Playstyle.DEFENSIVE ) {
|
||||||
|
|
||||||
|
private val plugin get() = SpeedHG.instance
|
||||||
|
|
||||||
override val name: String
|
override val name: String
|
||||||
get() = plugin.languageManager.getDefaultRawMessage( "kits.goblin.items.bunker.name" )
|
get() = plugin.languageManager.getDefaultRawMessage( "kits.goblin.items.bunker.name" )
|
||||||
|
|
||||||
|
|||||||
@@ -75,9 +75,9 @@ class KitEventDispatcher(
|
|||||||
.onHitEnemy( attacker, victim, event )
|
.onHitEnemy( attacker, victim, event )
|
||||||
|
|
||||||
// ── 3. Victim passive hook ────────────────────────────────────────────
|
// ── 3. Victim passive hook ────────────────────────────────────────────
|
||||||
val victimKit = kitManager.getSelectedKit( victim ) ?: return
|
kitManager.getSelectedKit( victim )
|
||||||
victimKit.getPassiveAbility(kitManager.getSelectedPlaystyle( victim ))
|
?.getPassiveAbility(kitManager.getSelectedPlaystyle( victim ))
|
||||||
.onHitByEnemy( victim, attacker, event )
|
?.onHitByEnemy( victim, attacker, event )
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -159,13 +159,16 @@ class KitEventDispatcher(
|
|||||||
fun onMove(
|
fun onMove(
|
||||||
event: PlayerMoveEvent
|
event: PlayerMoveEvent
|
||||||
) {
|
) {
|
||||||
|
// Frühexit: nur echte Positionsänderungen, keine Kopfdrehungen
|
||||||
|
val from = event.from
|
||||||
|
val to = event.to
|
||||||
|
if ( from.blockX == to.blockX && from.blockY == to.blockY && from.blockZ == to.blockZ ) return
|
||||||
|
|
||||||
if ( !isIngame() ) return
|
if ( !isIngame() ) return
|
||||||
|
|
||||||
val player = event.player
|
val player = event.player
|
||||||
val kit = kitManager.getSelectedKit( player ) ?: return
|
val kit = kitManager.getSelectedKit( player ) ?: return
|
||||||
|
kit.getPassiveAbility(kitManager.getSelectedPlaystyle( player )).onMove( player, event )
|
||||||
kit.getPassiveAbility(kitManager.getSelectedPlaystyle( player ))
|
|
||||||
.onMove( player, event )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ class GameStateListener : Listener {
|
|||||||
private val plugin = SpeedHG.instance
|
private val plugin = SpeedHG.instance
|
||||||
private val gameManager = plugin.gameManager
|
private val gameManager = plugin.gameManager
|
||||||
|
|
||||||
|
private val feastStarted = false // später ersetzen
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onLeavesDecay(
|
fun onLeavesDecay(
|
||||||
event: LeavesDecayEvent
|
event: LeavesDecayEvent
|
||||||
@@ -118,16 +120,15 @@ class GameStateListener : Listener {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add feast check
|
if ( block.type == Material.IRON_ORE && !feastStarted )
|
||||||
if ( block.type == Material.IRON_ORE && TODO( "Add before feast check" ))
|
|
||||||
{
|
{
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
player.sendMsg( "build.no_iron_before_feast" )
|
player.sendMsg("build.no_iron_before_feast")
|
||||||
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
player.playSound(player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f)
|
||||||
}
|
}
|
||||||
else if ( block.type == Material.IRON_ORE && TODO( "Add after feast check" ))
|
else if ( block.type == Material.IRON_ORE && feastStarted )
|
||||||
{
|
{
|
||||||
// TODO: add 0.1 to ironFarmed in database
|
// TODO: Database-Aufruf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import org.bukkit.entity.Player
|
|||||||
|
|
||||||
private val langManager get() = SpeedHG.instance.languageManager
|
private val langManager get() = SpeedHG.instance.languageManager
|
||||||
|
|
||||||
val legacySerializer = LegacyComponentSerializer.builder()
|
internal val legacySerializer = LegacyComponentSerializer.builder()
|
||||||
.character('§')
|
.character('§')
|
||||||
.hexColors()
|
.hexColors()
|
||||||
.useUnusualXRepeatedCharacterHexFormat()
|
.useUnusualXRepeatedCharacterHexFormat()
|
||||||
|
|||||||
Reference in New Issue
Block a user