fix: close two unbounded map leaks that survived player quit
Обе карты росли без границы и никогда не освобождались. 1. MagicListener.lastCast / lastCastTime Писались на каждом применении магии (recordCast) и не удалялись НИКОГДА — ни на выходе, ни на смерти. Каждый игрок, хоть раз применивший магию, навсегда оставлял две записи. Данные копеечные, но карты растут без границы весь срок жизни сервера. Очистка вынесена в общий forget(UUID), который зовут и onQuit, и onDeath. 2. TensionManager.battleEnemies На выходе не удалялся. Расчёт был на то, что запись исчезнет сама через BATTLE_EXPIRE_MS, но эта проверка требует непустого lastCombat — а он удалялся в той же строке выше. В итоге запись жила вечно, если в бою был противник, который не умирает: босс или запертый моб на ферме. Множество не пустеет, lastCombat == null, условие истечения не проверяется, и tickBattle обходит эту запись каждый тик до конца жизни сервера. Дополнительно tickBattle теперь снимает боевую запись и при lastCombat == null, а не только по таймауту. Это закрывает не только выход, но и любую другую рассинхронизацию: без боя и без отметки времени бой не бой.
This commit is contained in:
@@ -212,7 +212,11 @@ public class TensionManager implements Listener {
|
||||
|| (ent instanceof org.bukkit.entity.LivingEntity le && le.isDead());
|
||||
});
|
||||
final Long last = lastCombat.get(pid);
|
||||
if (set.isEmpty() || (last != null && now - last > BATTLE_EXPIRE_MS)) {
|
||||
// lastCombat == null означает, что бой не начинался или уже вышел из
|
||||
// состояния. Множество при этом может быть непустым (противник жив),
|
||||
// и тогда условие истечения по времени не проверяется вовсе — запись
|
||||
// остаётся навсегда. Без боя и без отметки времени бой не бой.
|
||||
if (last == null || set.isEmpty() || (now - last > BATTLE_EXPIRE_MS)) {
|
||||
if (drop == null) {
|
||||
drop = new java.util.ArrayList<>(4);
|
||||
}
|
||||
@@ -281,6 +285,14 @@ public class TensionManager implements Listener {
|
||||
tp.remove(id);
|
||||
lastCombat.remove(id);
|
||||
lastPct.remove(id);
|
||||
// Утечка: battleEnemies на выходе не чистился. Расчёт на то, что запись
|
||||
// исчезнет сама через BATTLE_EXPIRE_MS, но этот путь требует непустого
|
||||
// lastCombat — а его мы только что удалили строкой выше. В итоге запись
|
||||
// могла жить вечно: пока в бою есть противник, который не умирает
|
||||
// (босс на ферме, запертый моб), множество не пустеет, lastCombat равен
|
||||
// null, и условие истечения не проверяется. Дальше tickBattle обходит
|
||||
// эту запись каждый тик до конца жизни сервера.
|
||||
battleEnemies.remove(id);
|
||||
AbilityCooldown.clearAll(e.getPlayer());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user