Add AFK support
This commit is contained in:
parent
99099a345a
commit
4f38f2e5f0
4 changed files with 186 additions and 1 deletions
|
@ -9,7 +9,7 @@ yarn_mappings=1.20.1+build.10
|
|||
loader_version=0.16.5
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.8.5
|
||||
mod_version=1.9.0
|
||||
maven_group=cc.reconnected
|
||||
archives_base_name=rcc-server
|
||||
|
||||
|
|
|
@ -2,11 +2,14 @@ package cc.reconnected.server;
|
|||
|
||||
import cc.reconnected.server.commands.RccCommand;
|
||||
import cc.reconnected.server.database.PlayerData;
|
||||
import cc.reconnected.server.events.PlayerActivityEvents;
|
||||
import cc.reconnected.server.events.PlayerWelcome;
|
||||
import cc.reconnected.server.events.Ready;
|
||||
import cc.reconnected.server.http.ServiceServer;
|
||||
import cc.reconnected.server.trackers.AfkTracker;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
|
@ -48,6 +51,11 @@ public class RccServer implements ModInitializer {
|
|||
return luckPerms;
|
||||
}
|
||||
|
||||
private AfkTracker afkTracker;
|
||||
public AfkTracker afkTracker() {
|
||||
return afkTracker;
|
||||
}
|
||||
|
||||
public static float getTPS() {
|
||||
return currentTps;
|
||||
}
|
||||
|
@ -79,6 +87,7 @@ public class RccServer implements ModInitializer {
|
|||
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
||||
luckPerms = LuckPermsProvider.get();
|
||||
afkTracker = new AfkTracker();
|
||||
Ready.READY.invoker().ready(server, luckPerms);
|
||||
});
|
||||
|
||||
|
@ -114,6 +123,7 @@ public class RccServer implements ModInitializer {
|
|||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
currentPlayerCount = server.getCurrentPlayerCount() - 1;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void broadcastMessage(MinecraftServer server, Text message) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package cc.reconnected.server.events;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
public final class PlayerActivityEvents {
|
||||
|
||||
public static final Event<PlayerActivityEvents.Afk> AFK = EventFactory.createArrayBacked(PlayerActivityEvents.Afk.class, callbacks -> (handler, server) -> {
|
||||
for (PlayerActivityEvents.Afk callback : callbacks) {
|
||||
callback.onAfk(handler, server);
|
||||
}
|
||||
});
|
||||
|
||||
public static final Event<PlayerActivityEvents.AfkReturn> AFK_RETURN = EventFactory.createArrayBacked(PlayerActivityEvents.AfkReturn.class, callbacks -> (handler, server) -> {
|
||||
for (PlayerActivityEvents.AfkReturn callback : callbacks) {
|
||||
callback.onAfkReturn(handler, server);
|
||||
}
|
||||
});
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Afk {
|
||||
void onAfk(ServerPlayerEntity player, MinecraftServer server);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AfkReturn {
|
||||
void onAfkReturn(ServerPlayerEntity player, MinecraftServer server);
|
||||
}
|
||||
}
|
144
src/main/java/cc/reconnected/server/trackers/AfkTracker.java
Normal file
144
src/main/java/cc/reconnected/server/trackers/AfkTracker.java
Normal file
|
@ -0,0 +1,144 @@
|
|||
package cc.reconnected.server.trackers;
|
||||
|
||||
import cc.reconnected.server.RccServer;
|
||||
import cc.reconnected.server.events.PlayerActivityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.*;
|
||||
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AfkTracker {
|
||||
private static final int cycleDelay = 10;
|
||||
private static final int absentTimeTrigger = 300 * 20; // 5 mins (* 20 ticks)
|
||||
private final HashMap<UUID, PlayerPosition> playerPositions = new HashMap<>();
|
||||
private final HashMap<UUID, Integer> playerLastUpdate = new HashMap<>();
|
||||
private final HashMap<UUID, Boolean> playerAfkStates = new HashMap<>();
|
||||
|
||||
public AfkTracker() {
|
||||
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||
if (server.getTicks() % cycleDelay == 0) {
|
||||
updatePlayers(server);
|
||||
}
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||
final var player = handler.getPlayer();
|
||||
var playerPosition = new PlayerPosition(player);
|
||||
playerPositions.put(player.getUuid(), playerPosition);
|
||||
playerLastUpdate.put(player.getUuid(), server.getTicks());
|
||||
playerAfkStates.put(player.getUuid(), false);
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
playerPositions.remove(handler.getPlayer().getUuid());
|
||||
playerLastUpdate.remove(handler.getPlayer().getUuid());
|
||||
playerAfkStates.remove(handler.getPlayer().getUuid());
|
||||
});
|
||||
|
||||
AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
|
||||
resetAfkState((ServerPlayerEntity) player, world.getServer());
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
|
||||
AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||
resetAfkState((ServerPlayerEntity) player, world.getServer());
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
|
||||
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||
resetAfkState((ServerPlayerEntity) player, world.getServer());
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
|
||||
UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||
resetAfkState((ServerPlayerEntity) player, world.getServer());
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
|
||||
UseItemCallback.EVENT.register((player, world, hand) -> {
|
||||
resetAfkState((ServerPlayerEntity) player, world.getServer());
|
||||
return TypedActionResult.pass(player.getStackInHand(hand));
|
||||
});
|
||||
|
||||
ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((message, sender, params) -> {
|
||||
resetAfkState(sender, sender.getServer());
|
||||
return true;
|
||||
});
|
||||
|
||||
ServerMessageEvents.ALLOW_COMMAND_MESSAGE.register((message, source, params) -> {
|
||||
if(!source.isExecutedByPlayer())
|
||||
return true;
|
||||
resetAfkState(source.getPlayer(), source.getServer());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public void updatePlayers(MinecraftServer server) {
|
||||
var players = server.getPlayerManager().getPlayerList();
|
||||
var currentTick = server.getTicks();
|
||||
players.forEach(player -> {
|
||||
if (!playerPositions.containsKey(player.getUuid())) {
|
||||
playerPositions.put(player.getUuid(), new PlayerPosition(player));
|
||||
return;
|
||||
}
|
||||
var oldPosition = playerPositions.get(player.getUuid());
|
||||
var newPosition = new PlayerPosition(player);
|
||||
if (!oldPosition.equals(newPosition)) {
|
||||
playerPositions.put(player.getUuid(), newPosition);
|
||||
resetAfkState(player, server);
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerAfkStates.get(player.getUuid())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((playerLastUpdate.get(player.getUuid()) + absentTimeTrigger) <= currentTick) {
|
||||
// player is afk after 5 mins
|
||||
playerAfkStates.put(player.getUuid(), true);
|
||||
PlayerActivityEvents.AFK.invoker().onAfk(player, server);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void resetAfkState(ServerPlayerEntity player, MinecraftServer server) {
|
||||
playerLastUpdate.put(player.getUuid(), server.getTicks());
|
||||
if (playerAfkStates.get(player.getUuid())) {
|
||||
PlayerActivityEvents.AFK_RETURN.invoker().onAfkReturn(player, server);
|
||||
playerAfkStates.put(player.getUuid(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerPosition {
|
||||
public String dimension;
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
public float yaw;
|
||||
public float pitch;
|
||||
|
||||
|
||||
public boolean equals(PlayerPosition obj) {
|
||||
return x == obj.x && y == obj.y && z == obj.z
|
||||
&& yaw == obj.yaw && pitch == obj.pitch
|
||||
&& dimension.equals(obj.dimension);
|
||||
}
|
||||
|
||||
public PlayerPosition(ServerPlayerEntity player) {
|
||||
dimension = player.getWorld().getRegistryKey().getValue().toString();
|
||||
x = player.getX();
|
||||
y = player.getY();
|
||||
z = player.getZ();
|
||||
yaw = player.getYaw();
|
||||
pitch = player.getPitch();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue