Optimize code; memory-leaks, race-condition
Fix bugs like StackOverflow, Thread-Leak, or Race-Condition. Optimize code generally
This commit is contained in:
@@ -212,6 +212,7 @@ class SpeedHG : JavaPlugin() {
|
||||
override fun onDisable()
|
||||
{
|
||||
podiumManager.cleanup()
|
||||
gameManager.shutdown()
|
||||
if ( ::lobbyAnnouncer.isInitialized ) lobbyAnnouncer.stop()
|
||||
if ( ::perkManager.isInitialized ) perkManager.shutdown()
|
||||
if ( ::tablistManager.isInitialized ) tablistManager.shutdown()
|
||||
|
||||
@@ -142,17 +142,19 @@ class StatsManager(private val plugin: SpeedHG) {
|
||||
* Aufrufpunkt: `PlayerQuitEvent` — nach diesem Event brauchen wir die
|
||||
* Daten nicht mehr im RAM.
|
||||
*/
|
||||
fun saveAndEvict(uuid: UUID) {
|
||||
val stats = cache[uuid] ?: return
|
||||
fun saveAndEvict( uuid: UUID ) {
|
||||
val stats = cache[ uuid ] ?: return
|
||||
|
||||
scope.launch {
|
||||
try {
|
||||
repository.upsert(stats)
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("[StatsManager] Fehler beim Speichern für $uuid: ${e.message}")
|
||||
repository.upsert( stats )
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.severe( "[StatsManager] Fehler beim Speichern für $uuid: ${e.message}" )
|
||||
} finally {
|
||||
cache.remove(uuid)
|
||||
dirtyFlags.remove(uuid)
|
||||
// Nur entfernen wenn der Cache-Eintrag noch unser ursprüngliches Objekt ist
|
||||
// (verhindert, dass ein Reconnect-Eintrag gelöscht wird)
|
||||
cache.remove( uuid, stats )
|
||||
dirtyFlags.remove( uuid )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,40 +60,26 @@ class TornadoDisaster : NaturalDisaster() {
|
||||
return eligibleBiomes.any { biome.contains( it ) }
|
||||
}
|
||||
|
||||
override fun trigger(
|
||||
plugin: SpeedHG,
|
||||
player: Player
|
||||
) {
|
||||
override fun trigger( plugin: SpeedHG, player: Player )
|
||||
{
|
||||
val center = player.location.clone()
|
||||
val world = center.world ?: return
|
||||
val coroutineScope = CoroutineScope( Dispatchers.Default + SupervisorJob() )
|
||||
|
||||
var tick = 0
|
||||
var angle = 0.0
|
||||
var mainTask: BukkitTask? = null
|
||||
|
||||
mainTask = Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||
Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||
tick++
|
||||
|
||||
if ( tick > DURATION_TICKS )
|
||||
{
|
||||
mainTask?.cancel()
|
||||
coroutineScope.cancel()
|
||||
return@runTaskTimer
|
||||
}
|
||||
if ( tick > DURATION_TICKS ) return@runTaskTimer // Bukkit cancelt via cancel()
|
||||
|
||||
val currentAngle = angle
|
||||
angle += ROTATION_SPEED
|
||||
|
||||
coroutineScope.launch {
|
||||
val positions = ArrayList<Triple<Double, Double, Double>>( MAX_HEIGHT * SPOKES )
|
||||
|
||||
for ( layer in 0..MAX_HEIGHT )
|
||||
{
|
||||
val layerRadius = (( MAX_HEIGHT - layer ).toDouble() / MAX_HEIGHT )
|
||||
val layerRadius = ( MAX_HEIGHT - layer ).toDouble() / MAX_HEIGHT
|
||||
for ( spoke in 0 until SPOKES )
|
||||
{
|
||||
val a = currentAngle + ( spoke * ( Math.PI * 2.0 / SPOKES ))
|
||||
val a = angle + ( spoke * ( Math.PI * 2.0 / SPOKES ))
|
||||
positions += Triple(
|
||||
center.x + cos( a ) * layerRadius,
|
||||
center.y + layer.toDouble(),
|
||||
@@ -101,14 +87,10 @@ class TornadoDisaster : NaturalDisaster() {
|
||||
)
|
||||
}
|
||||
}
|
||||
angle += ROTATION_SPEED
|
||||
|
||||
Bukkit.getScheduler().runTask( plugin ) { ->
|
||||
positions.forEach { (x, y, z) ->
|
||||
world.spawnParticle(
|
||||
Particle.CAMPFIRE_COSY_SMOKE,
|
||||
x, y, z,
|
||||
1, 0.0, 0.0, 0.0, 0.0
|
||||
)
|
||||
positions.forEach { ( x, y, z ) ->
|
||||
world.spawnParticle( Particle.CAMPFIRE_COSY_SMOKE, x, y, z, 1, 0.0, 0.0, 0.0, 0.0 )
|
||||
}
|
||||
|
||||
if ( tick % 20 == 0 )
|
||||
@@ -119,21 +101,17 @@ class TornadoDisaster : NaturalDisaster() {
|
||||
|
||||
plugin.gameManager.alivePlayers
|
||||
.mapNotNull { Bukkit.getPlayer( it ) }
|
||||
.filter { it.location.distance( center ) in 0.5..PULL_RADIUS }
|
||||
.forEach { nearby ->
|
||||
val dist = nearby.location.distance( center )
|
||||
if ( dist !in 0.5..PULL_RADIUS ) return@forEach
|
||||
|
||||
val strength = ( 1.0 - dist / PULL_RADIUS ) * 0.35
|
||||
val toCenter: Vector = center.toVector()
|
||||
val toCenter = center.toVector()
|
||||
.subtract( nearby.location.toVector() )
|
||||
.normalize()
|
||||
.multiply( strength )
|
||||
|
||||
toCenter.y = strength * 0.45
|
||||
nearby.velocity = nearby.velocity.add( toCenter )
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0L, 1L )
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.random.Random
|
||||
|
||||
class GameManager(
|
||||
@@ -32,7 +33,7 @@ class GameManager(
|
||||
|
||||
var timer = 0
|
||||
|
||||
val alivePlayers = mutableSetOf<UUID>()
|
||||
val alivePlayers: MutableSet<UUID> = ConcurrentHashMap.newKeySet()
|
||||
|
||||
private var gameTask: BukkitTask? = null
|
||||
|
||||
@@ -72,6 +73,13 @@ class GameManager(
|
||||
}, 10L )
|
||||
}
|
||||
|
||||
fun shutdown()
|
||||
{
|
||||
recraftManager.shutdown()
|
||||
gameTask?.cancel()
|
||||
gameTask = null
|
||||
}
|
||||
|
||||
private var lobbyIdleCount: Int = 0
|
||||
|
||||
private fun gameLoop()
|
||||
@@ -442,7 +450,7 @@ class GameManager(
|
||||
val x = Random.nextDouble( -maxRadius, maxRadius )
|
||||
val z = Random.nextDouble( -maxRadius, maxRadius )
|
||||
val y = world.getHighestBlockYAt( x.toInt(), z.toInt() ) + 1.0
|
||||
loc = Location( world, x, y, z )
|
||||
loc = Location( world, x, y + 1.0, z )
|
||||
|
||||
val block = loc.block.type
|
||||
val below = loc.subtract( 0.0, 1.0, 0.0 ).block.type
|
||||
@@ -452,7 +460,7 @@ class GameManager(
|
||||
attempts++
|
||||
} while ( !safe && attempts < 20 )
|
||||
|
||||
player.teleport(loc.add( 0.0, 1.0, 0.0 ))
|
||||
player.teleport( loc )
|
||||
}
|
||||
|
||||
private fun updateCompass()
|
||||
|
||||
@@ -11,8 +11,10 @@ import org.bukkit.GameMode
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
import java.util.*
|
||||
@@ -62,6 +64,15 @@ class AntiRunningManager(
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler( priority = EventPriority.MONITOR )
|
||||
fun onQuit(
|
||||
event: PlayerQuitEvent
|
||||
) {
|
||||
lastCombatAction.remove( event.player.uniqueId )
|
||||
// BossBar entfernen falls aktiv (verhindert Ghost-BossBar nach Reconnect)
|
||||
event.player.hideBossBar( warningBar )
|
||||
}
|
||||
|
||||
private fun checkPlayers()
|
||||
{
|
||||
if (plugin.gameManager.currentState != GameState.INGAME)
|
||||
|
||||
@@ -7,11 +7,14 @@ import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
class RecraftManager(
|
||||
private val plugin: SpeedHG
|
||||
) {
|
||||
|
||||
private var task: BukkitTask? = null
|
||||
|
||||
private val beforeFeast = plugin.config.getBoolean( "game.recraftNerf.beforeFeast", true )
|
||||
private val recraftNerfEnabled = plugin.config.getBoolean( "game.recraftNerf.enabled", false )
|
||||
private val maxRecraftAmount = plugin.config.getInt( "game.recraftNerf.maxAmount", 64 )
|
||||
@@ -21,7 +24,7 @@ class RecraftManager(
|
||||
if ( !recraftNerfEnabled )
|
||||
return
|
||||
|
||||
object : BukkitRunnable() {
|
||||
task = object : BukkitRunnable() {
|
||||
|
||||
override fun run()
|
||||
{
|
||||
@@ -29,6 +32,7 @@ class RecraftManager(
|
||||
plugin.gameManager.feastManager.hasSpawned )
|
||||
{
|
||||
this.cancel()
|
||||
task = null
|
||||
return
|
||||
}
|
||||
|
||||
@@ -51,6 +55,12 @@ class RecraftManager(
|
||||
}.runTaskTimer( plugin, 10L, 10L )
|
||||
}
|
||||
|
||||
fun shutdown()
|
||||
{
|
||||
task?.cancel()
|
||||
task = null
|
||||
}
|
||||
|
||||
private class Recraft {
|
||||
|
||||
private val recraftMaterials = listOf(
|
||||
|
||||
@@ -276,7 +276,7 @@ class ArmorerKit : Kit()
|
||||
// Shared no-active placeholder
|
||||
// =========================================================================
|
||||
|
||||
inner class NoActive(
|
||||
private class NoActive(
|
||||
playstyle: Playstyle
|
||||
) : ActiveAbility( playstyle )
|
||||
{
|
||||
|
||||
@@ -181,7 +181,7 @@ class GladiatorKit : Kit()
|
||||
player.location.clone().add( 0.0, 64.0, 0.0 ),
|
||||
capturedRadius,
|
||||
capturedHeight + 2
|
||||
)
|
||||
) ?: return AbilityResult.ConditionNotMet( "No space found for gladiator arena" )
|
||||
val center = BukkitAdapter.adapt( player.world, gladiatorRegion.center )
|
||||
|
||||
WorldEditUtils.createCylinder( player.world, center, capturedRadius - 1, true, 1, Material.WHITE_STAINED_GLASS )
|
||||
@@ -228,11 +228,13 @@ class GladiatorKit : Kit()
|
||||
private fun getGladiatorLocation(
|
||||
location: Location,
|
||||
radius: Int,
|
||||
height: Int
|
||||
): Region
|
||||
height: Int,
|
||||
attempt: Int = 0
|
||||
): Region?
|
||||
{
|
||||
val random = Random()
|
||||
if ( attempt >= 20 ) return null // Kein Platz gefunden → Ability abbrechen
|
||||
|
||||
val random = Random()
|
||||
val region = CylinderRegion(
|
||||
BukkitAdapter.adapt( location.world ),
|
||||
BukkitAdapter.asBlockVector( location ),
|
||||
@@ -248,7 +250,8 @@ class GladiatorKit : Kit()
|
||||
if ( random.nextBoolean() ) -10.0 else 10.0
|
||||
),
|
||||
radius,
|
||||
height
|
||||
height,
|
||||
attempt + 1 // ← Versuch mitzählen
|
||||
)
|
||||
else region
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ import kotlin.math.sin
|
||||
* [lastHitEnemy]-Fenster und berechnet eine Position 1,8 Blöcke hinter dem Feind.
|
||||
*
|
||||
* ### Smoke-Mechanismus
|
||||
* Ein BukkitTask spawnt alle [smokRefreshTicks] einen Partikelring. Jeder Feind
|
||||
* Ein BukkitTask spawnt alle [smokeRefreshTicks] einen Partikelring. Jeder Feind
|
||||
* im Ring erhält Blindness I + Slowness I, die regelmäßig erneuert werden.
|
||||
*/
|
||||
class NinjaKit : Kit() {
|
||||
|
||||
@@ -40,11 +40,9 @@ class TeamSelectionListener(
|
||||
}
|
||||
|
||||
@EventHandler( priority = EventPriority.MONITOR )
|
||||
fun onQuit(
|
||||
event: PlayerQuitEvent
|
||||
) {
|
||||
val state = plugin.gameManager.currentState
|
||||
if ( state == GameState.LOBBY || state == GameState.STARTING )
|
||||
fun onQuit( event: PlayerQuitEvent )
|
||||
{
|
||||
// Immer aus dem Team-Tracking entfernen, unabhängig vom GameState
|
||||
plugin.presetTeamManager.leave( event.player )
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user