added antiGrief inhabited chunk time calculation
This commit is contained in:
@@ -8,4 +8,10 @@ public class NumberUtil {
|
|||||||
|
|
||||||
return out;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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.Main;
|
||||||
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
|
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 eu.mhsl.craftattack.spawn.craftattack.appliances.security.antiGrief.listener.*;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.event.ClickEvent;
|
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 */
|
/** Smoothing factor for EMA baseline. Lower = smoother, higher = more reactive. 0.0 < EMA_ALPHA <= 1.0 */
|
||||||
private static final double EMA_ALPHA = 0.2;
|
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. */
|
/** Stores direct incidents mapped by player UUID. */
|
||||||
private final Map<UUID, Set<GriefIncident>> directGriefRegistry = new ConcurrentHashMap<>();
|
private final Map<UUID, Set<GriefIncident>> directGriefRegistry = new ConcurrentHashMap<>();
|
||||||
/** Stores passive incidents mapped by chunk key. */
|
/** Stores passive incidents mapped by chunk key. */
|
||||||
@@ -176,15 +182,18 @@ public class AntiGrief extends Appliance {
|
|||||||
final double currentScore = state.currentScore(bucketIdx);
|
final double currentScore = state.currentScore(bucketIdx);
|
||||||
if (currentScore <= 0.0) return;
|
if (currentScore <= 0.0) return;
|
||||||
|
|
||||||
final double base = (state.ema == 0.0) ? currentScore : state.ema;
|
final double adjustedScore = adjustScoreToInhabitantTime(state, currentScore);
|
||||||
final double newBase = EMA_ALPHA * currentScore + (1 - EMA_ALPHA) * base;
|
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);
|
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) {
|
if (spike && (now - state.lastAlertAt) >= ALERT_COOLDOWN_MS) {
|
||||||
state.lastAlertAt = now;
|
state.lastAlertAt = now;
|
||||||
Bukkit.getScheduler().runTask(Main.instance(), () ->
|
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);
|
}, 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) {
|
private void alertAdmins(long areaKey, long bucketIdx, double curr, double baseline) {
|
||||||
AreaState meta = this.areas.get(areaKey);
|
AreaState meta = this.areas.get(areaKey);
|
||||||
if (meta == null) return;
|
if (meta == null) return;
|
||||||
|
Reference in New Issue
Block a user