added antiGrief inhabited chunk time calculation

This commit is contained in:
2025-09-27 07:42:13 +02:00
parent 16d7347fd0
commit d7cc141b94
2 changed files with 27 additions and 4 deletions

View File

@@ -8,4 +8,10 @@ public class NumberUtil {
return out;
}
public static <T extends Comparable<T>> T clamp(T value, T min, T max) {
if (value.compareTo(min) < 0) return min;
if (value.compareTo(max) > 0) return max;
return value;
}
}

View File

@@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.security.antiGrief;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.util.NumberUtil;
import eu.mhsl.craftattack.spawn.craftattack.appliances.security.antiGrief.listener.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
@@ -139,6 +140,11 @@ public class AntiGrief extends Appliance {
/** Smoothing factor for EMA baseline. Lower = smoother, higher = more reactive. 0.0 < EMA_ALPHA <= 1.0 */
private static final double EMA_ALPHA = 0.2;
/** Minimal chunk inhabited time to start registering scores linearly to INHABITED_FULL_MS */
private static final int INHABITED_MIN_MS = 60 * 60 * 1000;
/** Max time to reach 100% effect on the score */
private static final int INHABITED_FULL_MS = 24 * 60 * 60 * 1000;
/** Stores direct incidents mapped by player UUID. */
private final Map<UUID, Set<GriefIncident>> directGriefRegistry = new ConcurrentHashMap<>();
/** Stores passive incidents mapped by chunk key. */
@@ -176,15 +182,18 @@ public class AntiGrief extends Appliance {
final double currentScore = state.currentScore(bucketIdx);
if (currentScore <= 0.0) return;
final double base = (state.ema == 0.0) ? currentScore : state.ema;
final double newBase = EMA_ALPHA * currentScore + (1 - EMA_ALPHA) * base;
final double adjustedScore = adjustScoreToInhabitantTime(state, currentScore);
if (adjustedScore <= 0.0) return;
final double base = (state.ema == 0.0) ? adjustedScore : state.ema;
final double newBase = EMA_ALPHA * adjustedScore + (1 - EMA_ALPHA) * base;
state.ema = Math.max(3, newBase);
boolean spike = currentScore >= HARD_THRESHOLD || currentScore >= base * FACTOR_SPIKE;
final boolean spike = adjustedScore >= HARD_THRESHOLD || adjustedScore >= base * FACTOR_SPIKE;
if (spike && (now - state.lastAlertAt) >= ALERT_COOLDOWN_MS) {
state.lastAlertAt = now;
Bukkit.getScheduler().runTask(Main.instance(), () ->
this.alertAdmins(areaKey, bucketIdx, currentScore, newBase)
this.alertAdmins(areaKey, bucketIdx, adjustedScore, newBase)
);
}
});
@@ -212,6 +221,14 @@ public class AntiGrief extends Appliance {
}, Ticks.TICKS_PER_SECOND * 30, Ticks.TICKS_PER_SECOND * 30);
}
private static double adjustScoreToInhabitantTime(AreaState state, double currentScore) {
final long inhabitedMs = state.getInhabitedTime() * Ticks.SINGLE_TICK_DURATION_MS / Ticks.TICKS_PER_SECOND;
double factor = (double) (inhabitedMs - INHABITED_MIN_MS) / (double) (INHABITED_FULL_MS - INHABITED_MIN_MS);
factor = NumberUtil.clamp(factor, 0.0, 1.0);
return currentScore * factor;
}
private void alertAdmins(long areaKey, long bucketIdx, double curr, double baseline) {
AreaState meta = this.areas.get(areaKey);
if (meta == null) return;