From 3986c24ccddb80a2929b1792370266b1da690418 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:04:13 +0300 Subject: [PATCH 1/8] feat: implement confinement analysis to detect AFK pools and similar behaviors --- .../behavior/BehaviorAnalysisTask.java | 20 ++++++ .../antiafk/behavior/PlayerBehaviorData.java | 67 +++++++++++++++++++ .../handlers/PlayerMovementListener.java | 3 + .../antiafk/managers/ConfigManager.java | 38 +++++++++++ AntiAFK-Core/src/main/resources/config.yml | 17 +++++ 5 files changed, 145 insertions(+) diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java index 197e453..82ad815 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java @@ -68,6 +68,26 @@ public void run() { } PlayerBehaviorData data = analysisManagerProvider.get().getPlayerData(player); + + if (configManager.isConfinementCheckEnabled()) { + long durationMillis = data.getConfinementDuration(); + long requiredMillis = configManager.getConfinementCheckDurationMillis(); + + if (durationMillis > requiredMillis) { + if (data.getTotalDistanceTraveled() > configManager.getConfinementMinDistance()) { + Bukkit.getScheduler().runTask(plugin, () -> + afkManagerProvider.get().getBotDetectionManager().triggerSuspicionAndChallenge( + player, + "behavior.afk_pool_detected", + DetectionType.POINTLESS_ACTIVITY + ) + ); + + data.reset(); + } + } + } + LinkedList history = data.getMovementHistory(); boolean matchFound = false; diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java index 12bac3a..ec21222 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java @@ -18,6 +18,70 @@ public class PlayerBehaviorData { */ private final LinkedList movementHistory = new LinkedList<>(); + private Location confinementStartLocation; + private long confinementStartTime; + private double totalDistanceTraveled = 0.0; + + public void updateConfinement(Location current, double confinementRadius) { + if (confinementStartLocation == null) { + resetConfinement(current); + return; + } + + if (!isInsideRadius(current, confinementStartLocation, confinementRadius)) { + resetConfinement(current); + return; + } + + double distance = current.distance(confinementStartLocation); + } + + private Location lastMoveLocation; + + public void processMovement(Location current, double maxRadius) { + long now = System.currentTimeMillis(); + + if (confinementStartLocation == null) { + confinementStartLocation = current; + lastMoveLocation = current; + confinementStartTime = now; + totalDistanceTraveled = 0; + return; + } + + if (current.getWorld() != confinementStartLocation.getWorld() || + current.distanceSquared(confinementStartLocation) > (maxRadius * maxRadius)) { + resetConfinement(current); + return; + } + + if (lastMoveLocation != null && lastMoveLocation.getWorld() == current.getWorld()) { + totalDistanceTraveled += current.distance(lastMoveLocation); + } + + lastMoveLocation = current; + } + + private void resetConfinement(Location current) { + this.confinementStartLocation = current; + this.lastMoveLocation = current; + this.confinementStartTime = System.currentTimeMillis(); + this.totalDistanceTraveled = 0.0; + } + + private boolean isInsideRadius(Location loc1, Location loc2, double radius) { + if (loc1.getWorld() != loc2.getWorld()) return false; + return loc1.distanceSquared(loc2) <= (radius * radius); + } + + public long getConfinementDuration() { + return (confinementStartLocation == null) ? 0 : System.currentTimeMillis() - confinementStartTime; + } + + public double getTotalDistanceTraveled() { + return totalDistanceTraveled; + } + /** * Tespit edilen son tekrarın ne zaman gerçekleştiğini milisaniye cinsinden tutar. * Bu, tekrarların ardışık olup olmadığını anlamak için kullanılır. @@ -59,5 +123,8 @@ public void reset() { this.movementHistory.clear(); this.lastRepeatTimestamp = 0; this.consecutiveRepeatCount = 0; + this.confinementStartLocation = null; + this.totalDistanceTraveled = 0; + this.lastMoveLocation = null; } } \ No newline at end of file diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/listeners/handlers/PlayerMovementListener.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/listeners/handlers/PlayerMovementListener.java index e5c7b20..faedcce 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/listeners/handlers/PlayerMovementListener.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/listeners/handlers/PlayerMovementListener.java @@ -67,6 +67,9 @@ public void onPlayerMove(PlayerMoveEvent event) { history.removeFirst(); } } + + double radius = configManager.getConfinementRadius(); + data.processMovement(event.getTo(), radius); } } diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/managers/ConfigManager.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/managers/ConfigManager.java index 839c291..b7dd292 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/managers/ConfigManager.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/managers/ConfigManager.java @@ -226,6 +226,40 @@ public class ConfigManager { private boolean behaviorAnalysisEnabled = false; @ConfigPath("behavioral-analysis.history-size-ticks") @Validate(min = 20) private int behaviorHistorySizeTicks = 600; + // --- CONFINEMENT CHECK (AFK POOLS) --- + @ConfigPath("behavioral-analysis.confinement-check.enabled") + @Comment({ + "==================================", + " CONFINEMENT ANALYSIS", + "==================================", + "Detects players who move significantly but never leave a small area.", + "Useful for catching AFK Pools, Piston pushers, and Circle macros." + }) + private boolean confinementCheckEnabled = true; + + @ConfigPath("behavioral-analysis.confinement-check.check-duration") + @Comment({ + "The duration a player must remain within the restricted area to be flagged.", + "Recommended: Max AFK time + a small buffer (e.g., 15m + 5m = 20m)." + }) + @Transform(TimeConverter.class) + private long confinementCheckDurationSeconds = 1200; + + @ConfigPath("behavioral-analysis.confinement-check.radius") + @Comment({ + "The radius in blocks for the confinement area.", + "A value of 3.0 means checking if the player stayed within a 6x6 area." + }) + private double confinementRadius = 3.0; + + @ConfigPath("behavioral-analysis.confinement-check.min-distance-traveled") + @Comment({ + "The minimum total distance (sum of all steps) the player must have traveled.", + "This ensures that someone simply standing still is handled by standard AFK timers.", + "AFK pool users will have a high total distance but low displacement." + }) + private double confinementMinDistance = 100.0; + // --- DISCORD --- @ConfigPath("discord_webhook.enabled") @Comment({ @@ -710,6 +744,10 @@ private Optional checkWorldGuardRegion(Player player) { public double getPreFilterSizeRatio() { return preFilterSizeRatio; } public boolean isBehaviorAnalysisEnabled() { return behaviorAnalysisEnabled; } public int getBehaviorHistorySizeTicks() { return behaviorHistorySizeTicks; } + public boolean isConfinementCheckEnabled() { return confinementCheckEnabled; } + public long getConfinementCheckDurationMillis() { return confinementCheckDurationSeconds * 1000L; } + public double getConfinementRadius() { return confinementRadius; } + public double getConfinementMinDistance() { return confinementMinDistance; } public boolean isDiscordWebhookEnabled() { return discordWebhookEnabled; } public String getDiscordWebhookUrl() { return discordWebhookUrl; } public String getDiscordBotName() { return discordBotName; } diff --git a/AntiAFK-Core/src/main/resources/config.yml b/AntiAFK-Core/src/main/resources/config.yml index 4daefe7..e7cf421 100644 --- a/AntiAFK-Core/src/main/resources/config.yml +++ b/AntiAFK-Core/src/main/resources/config.yml @@ -223,6 +223,23 @@ behavioral-analysis: direction-tolerance: 25.0 similarity-threshold: 0.85 + confinement-check: + enabled: true + + # The duration a player must remain within the restricted area to be flagged. + # Recommended: Max AFK time + a small buffer (e.g., 15m + 5m = 20m). + check-duration: "20m" + + + # The radius in blocks for the confinement area. + # A value of 3.0 means checking if the player stayed within a 6x6 area. + radius: 3.0 + + # The minimum total distance (sum of all steps) the player must have traveled. + # This ensures that someone simply standing still is handled by standard AFK timers. + # AFK pool users will have a high total distance but low displacement. + min-distance-traveled: 100.0 + # ================================== # # LEARNING MODE (PATTERN AI) # # ================================== # From 7dbee5aed5479810cf28b372fed884f63ae65f74 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:20:21 +0300 Subject: [PATCH 2/8] refactor: improve world comparison in isInsideRadius method using Objects.equals --- .../com/bentahsin/antiafk/behavior/PlayerBehaviorData.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java index ec21222..823912d 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java @@ -3,6 +3,7 @@ import org.bukkit.Location; import java.util.LinkedList; +import java.util.Objects; /** * Her oyuncu için davranış analizi verilerini tutan veri sınıfı. @@ -70,7 +71,7 @@ private void resetConfinement(Location current) { } private boolean isInsideRadius(Location loc1, Location loc2, double radius) { - if (loc1.getWorld() != loc2.getWorld()) return false; + if (!Objects.equals(loc1.getWorld(), loc2.getWorld())) return false; return loc1.distanceSquared(loc2) <= (radius * radius); } From 604ca0750be272ed5489ae13fb6dc0ade5a89d26 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:21:44 +0300 Subject: [PATCH 3/8] refactor: use Objects.equals for world comparison in PlayerBehaviorData --- .../java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java index 823912d..2e701cb 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java @@ -56,7 +56,7 @@ public void processMovement(Location current, double maxRadius) { return; } - if (lastMoveLocation != null && lastMoveLocation.getWorld() == current.getWorld()) { + if (lastMoveLocation != null && Objects.equals(lastMoveLocation.getWorld(), current.getWorld())) { totalDistanceTraveled += current.distance(lastMoveLocation); } From 43274444724f869a18ead0483b020a58cf7669cd Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:22:26 +0300 Subject: [PATCH 4/8] refactor: remove unnecessary blank line in config.yml --- AntiAFK-Core/src/main/resources/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/AntiAFK-Core/src/main/resources/config.yml b/AntiAFK-Core/src/main/resources/config.yml index e7cf421..6e34d56 100644 --- a/AntiAFK-Core/src/main/resources/config.yml +++ b/AntiAFK-Core/src/main/resources/config.yml @@ -230,7 +230,6 @@ behavioral-analysis: # Recommended: Max AFK time + a small buffer (e.g., 15m + 5m = 20m). check-duration: "20m" - # The radius in blocks for the confinement area. # A value of 3.0 means checking if the player stayed within a 6x6 area. radius: 3.0 From 4092a88313dca28fd84e411d95125ee0f8f5c001 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:28:33 +0300 Subject: [PATCH 5/8] refactor: optimize confinement logic and improve thread safety in PlayerBehaviorData --- .../antiafk/behavior/PlayerBehaviorData.java | 92 ++++--------------- 1 file changed, 19 insertions(+), 73 deletions(-) diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java index 2e701cb..72dbd79 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/PlayerBehaviorData.java @@ -1,58 +1,31 @@ package com.bentahsin.antiafk.behavior; import org.bukkit.Location; - import java.util.LinkedList; import java.util.Objects; -/** - * Her oyuncu için davranış analizi verilerini tutan veri sınıfı. - * Bu sınıf, oyuncunun hareket geçmişini ve tespit edilen otonom hareket - * tekrarlarını depolamak için kullanılır. - */ public class PlayerBehaviorData { - /** - * Oyuncunun son 'X' saniyelik tüm anlamlı hareketlerini tutan ana veri havuzu. - * LinkedList, listenin başından (en eski veri) eleman silme işlemlerinde - * (FIFO - First-In, First-Out) ArrayList'e göre daha performanslıdır. - */ private final LinkedList movementHistory = new LinkedList<>(); - private Location confinementStartLocation; - private long confinementStartTime; - private double totalDistanceTraveled = 0.0; - - public void updateConfinement(Location current, double confinementRadius) { - if (confinementStartLocation == null) { - resetConfinement(current); - return; - } - - if (!isInsideRadius(current, confinementStartLocation, confinementRadius)) { - resetConfinement(current); - return; - } - - double distance = current.distance(confinementStartLocation); - } - + private volatile Location confinementStartLocation; + private volatile long confinementStartTime; + private volatile double totalDistanceTraveled = 0.0; private Location lastMoveLocation; - public void processMovement(Location current, double maxRadius) { + private volatile long lastRepeatTimestamp; + private volatile int consecutiveRepeatCount = 0; + + public synchronized void processMovement(Location current, double maxRadius) { long now = System.currentTimeMillis(); if (confinementStartLocation == null) { - confinementStartLocation = current; - lastMoveLocation = current; - confinementStartTime = now; - totalDistanceTraveled = 0; + resetConfinement(current, now); return; } - if (current.getWorld() != confinementStartLocation.getWorld() || - current.distanceSquared(confinementStartLocation) > (maxRadius * maxRadius)) { - resetConfinement(current); + if (!isInsideRadius(current, confinementStartLocation, maxRadius)) { + resetConfinement(current, now); return; } @@ -63,10 +36,10 @@ public void processMovement(Location current, double maxRadius) { lastMoveLocation = current; } - private void resetConfinement(Location current) { + private void resetConfinement(Location current, long timestamp) { this.confinementStartLocation = current; this.lastMoveLocation = current; - this.confinementStartTime = System.currentTimeMillis(); + this.confinementStartTime = timestamp; this.totalDistanceTraveled = 0.0; } @@ -75,52 +48,25 @@ private boolean isInsideRadius(Location loc1, Location loc2, double radius) { return loc1.distanceSquared(loc2) <= (radius * radius); } - public long getConfinementDuration() { + public synchronized long getConfinementDuration() { return (confinementStartLocation == null) ? 0 : System.currentTimeMillis() - confinementStartTime; } - public double getTotalDistanceTraveled() { + public synchronized double getTotalDistanceTraveled() { return totalDistanceTraveled; } - /** - * Tespit edilen son tekrarın ne zaman gerçekleştiğini milisaniye cinsinden tutar. - * Bu, tekrarların ardışık olup olmadığını anlamak için kullanılır. - */ - private long lastRepeatTimestamp; - - /** - * Birbirini takip eden (ardışık) tekrar sayısını tutar. - * Oyuncu kalıbı bozduğunda bu sayaç sıfırlanır. - */ - private int consecutiveRepeatCount = 0; - public LinkedList getMovementHistory() { return movementHistory; } - public long getLastRepeatTimestamp() { - return lastRepeatTimestamp; - } - - public void setLastRepeatTimestamp(long lastRepeatTimestamp) { - this.lastRepeatTimestamp = lastRepeatTimestamp; - } + public long getLastRepeatTimestamp() { return lastRepeatTimestamp; } + public void setLastRepeatTimestamp(long lastRepeatTimestamp) { this.lastRepeatTimestamp = lastRepeatTimestamp; } - public int getConsecutiveRepeatCount() { - return consecutiveRepeatCount; - } - - public void setConsecutiveRepeatCount(int consecutiveRepeatCount) { - this.consecutiveRepeatCount = consecutiveRepeatCount; - } + public int getConsecutiveRepeatCount() { return consecutiveRepeatCount; } + public void setConsecutiveRepeatCount(int consecutiveRepeatCount) { this.consecutiveRepeatCount = consecutiveRepeatCount; } - /** - * Oyuncunun tüm analiz verilerini sıfırlar. - * Bu metot, oyuncu AFK olarak işaretlendiğinde veya bilinçli bir aktivite - * (sohbet, envanter açma vb.) göstererek kalıbı bozduğunda çağrılır. - */ - public void reset() { + public synchronized void reset() { this.movementHistory.clear(); this.lastRepeatTimestamp = 0; this.consecutiveRepeatCount = 0; From 21525408730ded59444c0a3fa24edad6b27318a0 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:34:41 +0300 Subject: [PATCH 6/8] test: add unit tests for confinement detection logic in PlayerBehaviorData --- AntiAFK-Core/src/main/resources/messages.yml | 1 + .../behavior/ConfinementDetectionTest.java | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/ConfinementDetectionTest.java diff --git a/AntiAFK-Core/src/main/resources/messages.yml b/AntiAFK-Core/src/main/resources/messages.yml index 26a7bc5..61c83c4 100644 --- a/AntiAFK-Core/src/main/resources/messages.yml +++ b/AntiAFK-Core/src/main/resources/messages.yml @@ -160,6 +160,7 @@ behavior: rapid_world_change: "Sürekli dünya değiştirme tespiti." turing_test_failed: "Bot testi başarısız." learned_pattern_detected: "Öğrenilmiş bot deseni (%pattern%)" + afk_pool_detected: "AFK havuzu veya dairesel hareket tespiti." debug: suspicion: "!§8[AntiAFK-Debug] Yörünge şüphesi. Analiz başlıyor." repetition: "!§8[AntiAFK-Debug] %time%s'lik yörünge tekrarı! Sayaç: %count%/%max_repeats%" diff --git a/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/ConfinementDetectionTest.java b/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/ConfinementDetectionTest.java new file mode 100644 index 0000000..987fcec --- /dev/null +++ b/AntiAFK-Core/src/test/java/com/bentahsin/antiafk/behavior/ConfinementDetectionTest.java @@ -0,0 +1,70 @@ +package com.bentahsin.antiafk.behavior; + +import org.bukkit.Location; +import org.bukkit.World; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class ConfinementDetectionTest { + + private PlayerBehaviorData behaviorData; + @Mock private World mockWorld; + @Mock private Location loc1; + @Mock private Location loc2; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + behaviorData = new PlayerBehaviorData(); + + when(loc1.getWorld()).thenReturn(mockWorld); + when(loc2.getWorld()).thenReturn(mockWorld); + } + + @Test + @DisplayName("Pozitif Tespit: Oyuncu dar alanda çok hareket ederse yakalanmalı") + void testConfinementPositive() { + behaviorData.processMovement(loc1, 5.0); + + when(loc1.distance(loc2)).thenReturn(2.0); + when(loc1.distanceSquared(loc2)).thenReturn(4.0); + + for(int i = 0; i < 50; i++) { + behaviorData.processMovement(loc2, 5.0); + behaviorData.processMovement(loc1, 5.0); + } + + assertTrue(behaviorData.getTotalDistanceTraveled() >= 100.0, "Toplam mesafe doğru hesaplanmadı."); + assertTrue(behaviorData.getConfinementDuration() >= 0); + } + + @Test + @DisplayName("Negatif Tespit: Oyuncu alanın dışına çıkarsa sayaç sıfırlanmalı") + void testConfinementResetOnExit() { + behaviorData.processMovement(loc1, 3.0); + + when(loc1.distanceSquared(loc2)).thenReturn(100.0); + + behaviorData.processMovement(loc2, 3.0); + assertEquals(0.0, behaviorData.getTotalDistanceTraveled(), 0.001); + } + + @Test + @DisplayName("Dünya Değişimi: Farklı dünyaya geçerse sistem sıfırlanmalı") + void testWorldChangeReset() { + World otherWorld = mock(World.class); + Location otherWorldLoc = mock(Location.class); + when(otherWorldLoc.getWorld()).thenReturn(otherWorld); + + behaviorData.processMovement(loc1, 5.0); + behaviorData.processMovement(otherWorldLoc, 5.0); + + assertEquals(0.0, behaviorData.getTotalDistanceTraveled(), "Dünya değişince veriler sıfırlanmadı."); + } +} \ No newline at end of file From f8a2d7a2a81192aa40dd852435f0c5145f1dbfa4 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:39:08 +0300 Subject: [PATCH 7/8] feat: add localization for learned bot patterns and AFK pool detection --- AntiAFK-Core/src/main/resources/messages.yml | 2 +- messages_yml/english.yml | 2 ++ messages_yml/french.yml | 2 ++ messages_yml/german.yml | 2 ++ messages_yml/polish.yml | 2 ++ messages_yml/russian.yml | 2 ++ messages_yml/spanish.yml | 2 ++ 7 files changed, 13 insertions(+), 1 deletion(-) diff --git a/AntiAFK-Core/src/main/resources/messages.yml b/AntiAFK-Core/src/main/resources/messages.yml index 61c83c4..5a853ae 100644 --- a/AntiAFK-Core/src/main/resources/messages.yml +++ b/AntiAFK-Core/src/main/resources/messages.yml @@ -159,7 +159,7 @@ behavior: autoclicker_detected: "Auto-clicker tespiti." rapid_world_change: "Sürekli dünya değiştirme tespiti." turing_test_failed: "Bot testi başarısız." - learned_pattern_detected: "Öğrenilmiş bot deseni (%pattern%)" + learned_pattern_detected: "Öğrenilmiş bot deseni tespit edildi. (%pattern%)" afk_pool_detected: "AFK havuzu veya dairesel hareket tespiti." debug: suspicion: "!§8[AntiAFK-Debug] Yörünge şüphesi. Analiz başlıyor." diff --git a/messages_yml/english.yml b/messages_yml/english.yml index a18c601..fae41ef 100644 --- a/messages_yml/english.yml +++ b/messages_yml/english.yml @@ -160,6 +160,8 @@ behavior: autoclicker_detected: "Auto-clicker detected." rapid_world_change: "Rapid world changing detected." turing_test_failed: "Bot test failed." + learned_pattern_detected: "Learned bot pattern detected (%pattern%)" + afk_pool_detected: "AFK pool or circular movement detected." debug: suspicion: "!§8[AntiAFK-Debug] Trajectory suspicion. Analysis started." repetition: "!§8[AntiAFK-Debug] %time%s trajectory repetition! Count: %count%/%max_repeats%" diff --git a/messages_yml/french.yml b/messages_yml/french.yml index 9ef4bb8..7de22ec 100644 --- a/messages_yml/french.yml +++ b/messages_yml/french.yml @@ -159,6 +159,8 @@ behavior: autoclicker_detected: "Auto-clicker detectado." rapid_world_change: "Mudança rápida de mundo detectada." turing_test_failed: "Falhou no teste de bot." + learned_pattern_detected: "Motif de bot appris détecté (%pattern%)" + afk_pool_detected: "Zone AFK ou mouvement circulaire détecté." debug: suspicion: "!§8[AntiAFK-Debug] Suspeita de trajetória. Análise iniciada." repetition: "!§8[AntiAFK-Debug] Repetição de trajetória de %time%s! Contagem: %count%/%max_repeats%" diff --git a/messages_yml/german.yml b/messages_yml/german.yml index 84395f3..00771b1 100644 --- a/messages_yml/german.yml +++ b/messages_yml/german.yml @@ -159,6 +159,8 @@ behavior: autoclicker_detected: "Auto-Klicker erkannt." rapid_world_change: "Schneller Weltwechsel erkannt." turing_test_failed: "Bot-Test fehlgeschlagen." + learned_pattern_detected: "Gelerntes Bot-Muster erkannt (%pattern%)" + afk_pool_detected: "AFK-Pool oder Kreisbewegung erkannt." debug: suspicion: "!§8[AntiAFK-Debug] Verdächtige Trajektorie. Analyse gestartet." repetition: "!§8[AntiAFK-Debug] %time%s Trajektorienwiederholung! Anzahl: %count%/%max_repeats%" diff --git a/messages_yml/polish.yml b/messages_yml/polish.yml index 51fc114..6e95ed8 100644 --- a/messages_yml/polish.yml +++ b/messages_yml/polish.yml @@ -159,6 +159,8 @@ behavior: autoclicker_detected: "Wykryto auto-klicker." rapid_world_change: "Wykryto szybką zmianę świata." turing_test_failed: "Test na bota nie powiódł się." + learned_pattern_detected: "Wykryto wyuczony wzorzec bota (%pattern%)" + afk_pool_detected: "Wykryto AFK pool lub ruch okrężny." debug: suspicion: "!§8[AntiAFK-Debug] Podejrzenie trajektorii. Rozpoczęto analizę." repetition: "!§8[AntiAFK-Debug] Powtórzenie trajektorii %time%s! Licznik: %count%/%max_repeats%" diff --git a/messages_yml/russian.yml b/messages_yml/russian.yml index 7c42a6d..9fce9b5 100644 --- a/messages_yml/russian.yml +++ b/messages_yml/russian.yml @@ -159,6 +159,8 @@ behavior: autoclicker_detected: "Обнаружен авто-кликер." rapid_world_change: "Обнаружена быстрая смена мира." turing_test_failed: "Тест на бота провален." + learned_pattern_detected: "Обнаружен изученный паттерн бота (%pattern%)" + afk_pool_detected: "Обнаружен AFK-pool или круговое движение." debug: suspicion: "!§8[AntiAFK-Debug] Подозрение на траекторию. Анализ начат." repetition: "!§8[AntiAFK-Debug] Повторение траектории %time%с! Счетчик: %count%/%max_repeats%" diff --git a/messages_yml/spanish.yml b/messages_yml/spanish.yml index d97466b..9a7cb20 100644 --- a/messages_yml/spanish.yml +++ b/messages_yml/spanish.yml @@ -159,6 +159,8 @@ behavior: autoclicker_detected: "Auto-clicker detectado." rapid_world_change: "Cambio rápido de mundo detectado." turing_test_failed: "Prueba de bot fallada." + learned_pattern_detected: "Patrón de bot aprendido detectado (%pattern%)" + afk_pool_detected: "Detección de AFK pool o movimiento circular." debug: suspicion: "!§8[AntiAFK-Debug] Sospecha de trayectoria. Análisis iniciado." repetition: "!§8[AntiAFK-Debug] ¡Repetición de trayectoria de %time%s! Conteo: %count%/%max_repeats%" From 8b082b370f384c39ab65999560ef9b54d9db2db5 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Wed, 24 Dec 2025 22:45:35 +0300 Subject: [PATCH 8/8] feat: log confinement period end and reset data in BehaviorAnalysisTask --- .../com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java index 82ad815..ef74c4a 100644 --- a/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java +++ b/AntiAFK-Core/src/main/java/com/bentahsin/antiafk/behavior/BehaviorAnalysisTask.java @@ -82,7 +82,10 @@ public void run() { DetectionType.POINTLESS_ACTIVITY ) ); - + data.reset(); + } else { + debugManager.log(DebugManager.DebugModule.BEHAVIORAL_ANALYSIS, + "Confinement period ended for %s without violation. Resetting window.", player.getName()); data.reset(); } }