new afk
This commit is contained in:
@ -36,6 +36,13 @@ import org.bukkit.event.player.PlayerExpChangeEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
|
||||
public final class popa extends JavaPlugin implements Listener {
|
||||
@ -55,6 +62,9 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
private ScheduledExecutorService scheduler;
|
||||
private Gson gson;
|
||||
private final Map<UUID, Long> lastActivityTimes = new HashMap<>();
|
||||
private final Map<UUID, Boolean> afkStates = new HashMap<>();
|
||||
private long afkThresholdMillis;
|
||||
private String afkPrefix;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@ -157,6 +167,12 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
getLogger().info("Marketplace URL: " + marketplaceUrl);
|
||||
getLogger().info("Bonuses URL: " + bonusesUrl);
|
||||
getLogger().info("Server IP: " + serverIp);
|
||||
|
||||
afkThresholdMillis = getConfig().getLong("afk-threshold-seconds", 60) * 1000L;
|
||||
afkPrefix = getConfig().getString("afk-prefix", "[AFK] ");
|
||||
|
||||
// Периодически проверяем, кто ушёл в AFK (на основном потоке)
|
||||
Bukkit.getScheduler().runTaskTimer(this, this::checkAfkTransitions, 20L, 20L * 5L);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -189,14 +205,49 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
// Игнорируем микродвижения (изменение направления взгляда)
|
||||
if (event.getFrom().getX() != event.getTo().getX() ||
|
||||
event.getFrom().getY() != event.getTo().getY() ||
|
||||
event.getFrom().getZ() != event.getTo().getZ()) {
|
||||
lastActivityTimes.put(event.getPlayer().getUniqueId(), System.currentTimeMillis());
|
||||
if (!event.getFrom().toVector().equals(event.getTo().toVector())) {
|
||||
markActivity(event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
// чат — асинхронный, переключаемся на основной поток
|
||||
Bukkit.getScheduler().runTask(this, () -> markActivity(event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCommand(PlayerCommandPreprocessEvent event) {
|
||||
markActivity(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
markActivity(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInvClick(InventoryClickEvent event) {
|
||||
if (event.getWhoClicked() instanceof Player p) {
|
||||
markActivity(p);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
markActivity(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
markActivity(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onHotbar(PlayerItemHeldEvent event) {
|
||||
markActivity(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
@ -217,6 +268,9 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
|
||||
// сразу обновим онлайн-лист на бэкенде
|
||||
sendOnlinePlayersUpdate();
|
||||
|
||||
lastActivityTimes.put(playerId, System.currentTimeMillis());
|
||||
afkStates.put(playerId, false);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -249,6 +303,9 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
|
||||
// Восстанавливаем базовые атрибуты
|
||||
player.getAttribute(Attribute.MAX_HEALTH).setBaseValue(20.0);
|
||||
|
||||
lastActivityTimes.remove(playerId);
|
||||
afkStates.remove(playerId);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -269,6 +326,68 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
sendEventToBackend(payload);
|
||||
}
|
||||
|
||||
private void pushOnlineUpdateAsync() {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this, this::sendOnlinePlayersUpdate);
|
||||
}
|
||||
|
||||
private void markActivity(Player player) {
|
||||
UUID id = player.getUniqueId();
|
||||
long now = System.currentTimeMillis();
|
||||
lastActivityTimes.put(id, now);
|
||||
|
||||
if (afkStates.getOrDefault(id, false)) {
|
||||
afkStates.put(id, false);
|
||||
player.sendMessage("Вы больше не AFK");
|
||||
|
||||
// 1) опционально: отдельное событие выхода из AFK
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
|
||||
sendEventToBackend(String.format(
|
||||
"{\"event_type\":\"player_afk_end\",\"player_id\":\"%s\",\"player_name\":\"%s\",\"server_ip\":\"%s\",\"timestamp\":%d}",
|
||||
id, player.getName(), serverIp, now
|
||||
));
|
||||
});
|
||||
|
||||
// 2) и сразу пушим обновление списка онлайна (чтобы бэкенд обновился мгновенно)
|
||||
pushOnlineUpdateAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void setAfk(Player player) {
|
||||
UUID id = player.getUniqueId();
|
||||
if (afkStates.getOrDefault(id, false)) return;
|
||||
|
||||
afkStates.put(id, true);
|
||||
player.sendMessage("Вы AFK");
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
|
||||
sendEventToBackend(String.format(
|
||||
"{\"event_type\":\"player_afk_start\",\"player_id\":\"%s\",\"player_name\":\"%s\",\"server_ip\":\"%s\",\"timestamp\":%d}",
|
||||
id, player.getName(), serverIp, System.currentTimeMillis()
|
||||
));
|
||||
});
|
||||
|
||||
pushOnlineUpdateAsync();
|
||||
}
|
||||
|
||||
private void checkAfkTransitions() {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
UUID id = p.getUniqueId();
|
||||
|
||||
// если ещё нет активности — считаем что активен “сейчас”
|
||||
long last = lastActivityTimes.getOrDefault(id, now);
|
||||
lastActivityTimes.putIfAbsent(id, last);
|
||||
|
||||
boolean isAfk = afkStates.getOrDefault(id, false);
|
||||
boolean shouldBeAfk = (now - last) > afkThresholdMillis;
|
||||
|
||||
if (!isAfk && shouldBeAfk) {
|
||||
setAfk(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendOnlinePlayersUpdate() {
|
||||
StringBuilder playersJson = new StringBuilder("[");
|
||||
boolean first = true;
|
||||
@ -278,18 +397,8 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
UUID playerId = entry.getKey();
|
||||
String playerName = playerNames.get(playerId);
|
||||
Long lastActivity = lastActivityTimes.get(playerId);
|
||||
|
||||
// Если нет последней активности — считаем, что игрок "не виден" бэкенду
|
||||
if (lastActivity == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long inactiveSeconds = (currentTime - lastActivity) / 1000;
|
||||
|
||||
// Больше минуты не двигался — не отправляем в список активных
|
||||
if (inactiveSeconds > afkTimeoutSeconds) {
|
||||
continue;
|
||||
}
|
||||
boolean isAfk = ((currentTime - lastActivity) > afkThresholdMillis);
|
||||
String nameForSite = isAfk ? (afkPrefix + playerName) : playerName;
|
||||
|
||||
long onlineTime = (currentTime - entry.getValue()) / 1000;
|
||||
|
||||
@ -297,8 +406,8 @@ public final class popa extends JavaPlugin implements Listener {
|
||||
first = false;
|
||||
|
||||
playersJson.append(String.format(
|
||||
"{\"player_id\":\"%s\",\"player_name\":\"%s\",\"online_time\":%d}",
|
||||
playerId, playerName, onlineTime
|
||||
"{\"player_id\":\"%s\",\"player_name\":\"%s\",\"online_time\":%d,\"afk\":%s}",
|
||||
playerId, nameForSite, onlineTime, isAfk ? "true" : "false"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user