From 6ca46fc562e4b6c8094b8bd113ee17656d5cf1d8 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Fri, 25 Oct 2024 12:56:22 +0200 Subject: [PATCH] Refactor code structure --- .../java/cc/reconnected/server/RccServer.java | 137 +----------------- .../server/commands/AfkCommand.java | 4 +- .../server/commands/BackCommand.java | 4 +- .../commands/TeleportAcceptCommand.java | 10 +- .../server/commands/TeleportAskCommand.java | 59 +------- .../commands/TeleportAskHereCommand.java | 10 +- .../server/commands/TeleportDenyCommand.java | 8 +- .../server/{trackers => core}/AfkTracker.java | 48 +++++- .../reconnected/server/core/BackTracker.java | 27 ++++ .../server/core/HttpApiServer.java | 104 +++++++++++++ .../server/{tablist => core}/TabList.java | 2 +- .../server/core/TeleportTracker.java | 82 +++++++++++ .../server/events/PlayerTeleport.java | 17 +++ .../server/http/ServiceServer.java | 61 -------- .../server/struct/ServerPosition.java | 4 +- 15 files changed, 306 insertions(+), 271 deletions(-) rename src/main/java/cc/reconnected/server/{trackers => core}/AfkTracker.java (77%) create mode 100644 src/main/java/cc/reconnected/server/core/BackTracker.java create mode 100644 src/main/java/cc/reconnected/server/core/HttpApiServer.java rename src/main/java/cc/reconnected/server/{tablist => core}/TabList.java (98%) create mode 100644 src/main/java/cc/reconnected/server/core/TeleportTracker.java create mode 100644 src/main/java/cc/reconnected/server/events/PlayerTeleport.java delete mode 100644 src/main/java/cc/reconnected/server/http/ServiceServer.java diff --git a/src/main/java/cc/reconnected/server/RccServer.java b/src/main/java/cc/reconnected/server/RccServer.java index cb30ff4..01f5f15 100644 --- a/src/main/java/cc/reconnected/server/RccServer.java +++ b/src/main/java/cc/reconnected/server/RccServer.java @@ -1,39 +1,26 @@ package cc.reconnected.server; import cc.reconnected.server.commands.*; +import cc.reconnected.server.core.*; 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.struct.ServerPosition; -import cc.reconnected.server.tablist.TabList; -import cc.reconnected.server.trackers.AfkTracker; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.kyori.adventure.platform.fabric.FabricServerAudiences; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; import java.util.Date; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; public class RccServer implements ModInitializer { @@ -42,20 +29,14 @@ public class RccServer implements ModInitializer { public static final cc.reconnected.server.RccServerConfig CONFIG = cc.reconnected.server.RccServerConfig.createAndLoad(); - private static float currentTps = 0; - private static float currentMspt = 0; - private static int currentPlayerCount = 0; - private static RccServer INSTANCE; public static RccServer getInstance() { return INSTANCE; } - private ServiceServer serviceServer; - - public ServiceServer serviceServer() { - return serviceServer; + public RccServer() { + INSTANCE = this; } private LuckPerms luckPerms; @@ -64,28 +45,6 @@ public class RccServer implements ModInitializer { return luckPerms; } - private AfkTracker afkTracker; - - public AfkTracker afkTracker() { - return afkTracker; - } - - public static float getTPS() { - return currentTps; - } - - public static float getMSPT() { - return currentMspt; - } - - public static int getPlayerCount() { - return currentPlayerCount; - } - - public RccServer() { - INSTANCE = this; - } - private volatile FabricServerAudiences adventure; public FabricServerAudiences adventure() { @@ -96,9 +55,6 @@ public class RccServer implements ModInitializer { return ret; } - public static final ConcurrentHashMap> teleportRequests = new ConcurrentHashMap<>(); - public static final ConcurrentHashMap lastPlayerPositions = new ConcurrentHashMap<>(); - @Override public void onInitialize() { LOGGER.info("Starting rcc-server"); @@ -120,46 +76,18 @@ public class RccServer implements ModInitializer { GodCommand.register(dispatcher, registryAccess, environment); }); + AfkTracker.register(); + TeleportTracker.register(); + BackTracker.register(); TabList.register(); + HttpApiServer.register(); ServerLifecycleEvents.SERVER_STARTED.register(server -> { luckPerms = LuckPermsProvider.get(); - afkTracker = new AfkTracker(); Ready.READY.invoker().ready(server, luckPerms); - - if (CONFIG.enableHttpApi()) { - try { - serviceServer = new ServiceServer(); - } catch (IOException e) { - LOGGER.error("Unable to start HTTP server", e); - } - } - }); - - ServerTickEvents.END_SERVER_TICK.register(server -> { - currentMspt = server.getTickTime(); - if (currentMspt != 0) { - currentTps = Math.min(20, 1000 / currentMspt); - } - - teleportRequests.forEach((recipient, requestList) -> { - requestList.forEach(request -> { - if (request.remainingTicks-- == 0) { - requestList.remove(request); - } - }); - }); - }); - - ServerLifecycleEvents.SERVER_STOPPING.register(server -> { - if (CONFIG.enableHttpApi()) { - LOGGER.info("Stopping HTTP services"); - serviceServer.httpServer().stop(0); - } }); ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { - currentPlayerCount = server.getCurrentPlayerCount() + 1; var player = handler.getPlayer(); var playerData = PlayerData.getPlayer(player.getUuid()); playerData.set(PlayerData.KEYS.username, player.getName().getString()); @@ -173,45 +101,6 @@ public class RccServer implements ModInitializer { PlayerWelcome.PLAYER_WELCOME.invoker().playerWelcome(player, playerData, server); LOGGER.info("Player {} joined for the first time!", player.getName().getString()); } - - teleportRequests.put(player.getUuid(), new ConcurrentLinkedDeque<>()); - }); - - ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { - currentPlayerCount = server.getCurrentPlayerCount() - 1; - - teleportRequests.remove(handler.getPlayer().getUuid()); - lastPlayerPositions.remove(handler.getPlayer().getUuid()); - }); - - PlayerActivityEvents.AFK.register((player, server) -> { - LOGGER.info("{} is AFK. Active time: {} seconds.", player.getGameProfile().getName(), afkTracker.getActiveTime(player)); - - var displayNameJson = Text.Serializer.toJson(player.getDisplayName()); - var displayName = JSONComponentSerializer.json().deserialize(displayNameJson); - - var message = MiniMessage.miniMessage().deserialize(CONFIG.afkMessage(), - Placeholder.component("displayname", displayName), - Placeholder.unparsed("username", player.getGameProfile().getName()), - Placeholder.unparsed("uuid", player.getUuid().toString()) - ); - - broadcastMessage(server, message); - }); - - PlayerActivityEvents.AFK_RETURN.register((player, server) -> { - LOGGER.info("{} is no longer AFK. Active time: {} seconds.", player.getGameProfile().getName(), afkTracker.getActiveTime(player)); - - var displayNameJson = Text.Serializer.toJson(player.getDisplayName()); - var displayName = JSONComponentSerializer.json().deserialize(displayNameJson); - - var message = MiniMessage.miniMessage().deserialize(CONFIG.afkReturnMessage(), - Placeholder.component("displayname", displayName), - Placeholder.unparsed("username", player.getGameProfile().getName()), - Placeholder.unparsed("uuid", player.getUuid().toString()) - ); - - broadcastMessage(server, message); }); } @@ -226,16 +115,4 @@ public class RccServer implements ModInitializer { player.sendMessage(message); } } - - public boolean isPlayerAfk(PlayerEntity player) { - return afkTracker.isPlayerAfk(player.getUuid()); - } - - public void setPlayerAfk(ServerPlayerEntity player, boolean afk) { - afkTracker.setPlayerAfk(player, afk); - } - - public int getActiveTime(ServerPlayerEntity player) { - return afkTracker().getActiveTime(player); - } } \ No newline at end of file diff --git a/src/main/java/cc/reconnected/server/commands/AfkCommand.java b/src/main/java/cc/reconnected/server/commands/AfkCommand.java index 2945fc2..50886b9 100644 --- a/src/main/java/cc/reconnected/server/commands/AfkCommand.java +++ b/src/main/java/cc/reconnected/server/commands/AfkCommand.java @@ -1,6 +1,6 @@ package cc.reconnected.server.commands; -import cc.reconnected.server.RccServer; +import cc.reconnected.server.core.AfkTracker; import com.mojang.brigadier.CommandDispatcher; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.command.CommandRegistryAccess; @@ -22,7 +22,7 @@ public class AfkCommand { } var player = context.getSource().getPlayer(); - RccServer.getInstance().setPlayerAfk(player, true); + AfkTracker.getInstance().setPlayerAfk(player, true); return 1; }); diff --git a/src/main/java/cc/reconnected/server/commands/BackCommand.java b/src/main/java/cc/reconnected/server/commands/BackCommand.java index 344f1fe..6a3ac6b 100644 --- a/src/main/java/cc/reconnected/server/commands/BackCommand.java +++ b/src/main/java/cc/reconnected/server/commands/BackCommand.java @@ -1,6 +1,6 @@ package cc.reconnected.server.commands; -import cc.reconnected.server.RccServer; +import cc.reconnected.server.core.BackTracker; import com.mojang.brigadier.CommandDispatcher; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.command.CommandRegistryAccess; @@ -23,7 +23,7 @@ public class BackCommand { var player = context.getSource().getPlayer(); - var lastPosition = RccServer.lastPlayerPositions.get(player.getUuid()); + var lastPosition = BackTracker.lastPlayerPositions.get(player.getUuid()); if (lastPosition == null) { context.getSource().sendFeedback(() -> Text.literal("There is no position to return back to.").formatted(Formatting.RED), false); return 1; diff --git a/src/main/java/cc/reconnected/server/commands/TeleportAcceptCommand.java b/src/main/java/cc/reconnected/server/commands/TeleportAcceptCommand.java index cb3e566..17621c3 100644 --- a/src/main/java/cc/reconnected/server/commands/TeleportAcceptCommand.java +++ b/src/main/java/cc/reconnected/server/commands/TeleportAcceptCommand.java @@ -1,6 +1,6 @@ package cc.reconnected.server.commands; -import cc.reconnected.server.RccServer; +import cc.reconnected.server.core.TeleportTracker; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import net.minecraft.command.CommandRegistryAccess; @@ -23,7 +23,7 @@ public class TeleportAcceptCommand { } var playerUuid = context.getSource().getPlayer().getUuid(); - var playerRequests = RccServer.teleportRequests.get(playerUuid); + var playerRequests = TeleportTracker.teleportRequests.get(playerUuid); var request = playerRequests.pollLast(); @@ -46,7 +46,7 @@ public class TeleportAcceptCommand { var uuid = UuidArgumentType.getUuid(context, "uuid"); var playerUuid = context.getSource().getPlayer().getUuid(); - var playerRequests = RccServer.teleportRequests.get(playerUuid); + var playerRequests = TeleportTracker.teleportRequests.get(playerUuid); var request = playerRequests.stream().filter(req -> req.requestId.equals(uuid)).findFirst().orElse(null); if (request == null) { @@ -62,7 +62,7 @@ public class TeleportAcceptCommand { dispatcher.register(literal("tpyes").redirect(node)); } - private static void execute(CommandContext context, TeleportAskCommand.TeleportRequest request) { + private static void execute(CommandContext context, TeleportTracker.TeleportRequest request) { var source = context.getSource(); request.expire(); @@ -88,6 +88,6 @@ public class TeleportAcceptCommand { targetPlayer.sendMessage(Text.empty().append(player.getDisplayName()).append(Text.literal(" accepted your teleport request.").formatted(Formatting.GREEN)), false); } - TeleportAskCommand.teleport(sourcePlayer, targetPlayer); + TeleportTracker.teleport(sourcePlayer, targetPlayer); } } diff --git a/src/main/java/cc/reconnected/server/commands/TeleportAskCommand.java b/src/main/java/cc/reconnected/server/commands/TeleportAskCommand.java index f15a2f1..3a76565 100644 --- a/src/main/java/cc/reconnected/server/commands/TeleportAskCommand.java +++ b/src/main/java/cc/reconnected/server/commands/TeleportAskCommand.java @@ -1,28 +1,19 @@ package cc.reconnected.server.commands; -import cc.reconnected.server.RccServer; -import cc.reconnected.server.struct.ServerPosition; +import cc.reconnected.server.core.TeleportTracker; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.ComponentLike; -import net.kyori.adventure.text.event.ClickCallback; -import net.kyori.adventure.text.event.ClickEvent; -import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.command.CommandSource; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import java.time.Duration; -import java.util.UUID; - import static net.minecraft.server.command.CommandManager.*; public class TeleportAskCommand { @@ -60,8 +51,8 @@ public class TeleportAskCommand { return; } - var request = new TeleportRequest(player.getUuid(), target.getUuid()); - var targetRequests = RccServer.teleportRequests.get(target.getUuid()); + var request = new TeleportTracker.TeleportRequest(player.getUuid(), target.getUuid()); + var targetRequests = TeleportTracker.teleportRequests.get(target.getUuid()); targetRequests.addLast(request); var requestMessage = Component.empty() @@ -69,53 +60,13 @@ public class TeleportAskCommand { .appendSpace() .append(Component.text("requested to teleport to you.", NamedTextColor.GOLD)) .appendNewline().appendSpace() - .append(makeButton(Component.text("Accept", NamedTextColor.GREEN), Component.text("Click to accept request"), "/tpaccept " + request.requestId)) + .append(TeleportTracker.makeButton(Component.text("Accept", NamedTextColor.GREEN), Component.text("Click to accept request"), "/tpaccept " + request.requestId)) .appendSpace() - .append(makeButton(Component.text("Refuse", NamedTextColor.RED), Component.text("Click to refuse request"), "/tpdeny " + request.requestId)); + .append(TeleportTracker.makeButton(Component.text("Refuse", NamedTextColor.RED), Component.text("Click to refuse request"), "/tpdeny " + request.requestId)); target.sendMessage(requestMessage); source.sendFeedback(() -> Text.literal("Teleport request sent.").setStyle(Style.EMPTY.withColor(Formatting.GREEN)), false); } - public static Component makeButton(ComponentLike text, ComponentLike hoverText, String command) { - return Component.empty() - .append(Component.text("[")) - .append(text) - .append(Component.text("]")) - .color(NamedTextColor.AQUA) - .hoverEvent(HoverEvent.showText(hoverText)) - .clickEvent(ClickEvent.runCommand(command)); - } - - public static void teleport(ServerPlayerEntity sourcePlayer, ServerPlayerEntity targetPlayer) { - RccServer.lastPlayerPositions.put(sourcePlayer.getUuid(), new ServerPosition(sourcePlayer)); - sourcePlayer.teleport( - targetPlayer.getServerWorld(), - targetPlayer.getX(), - targetPlayer.getY(), - targetPlayer.getZ(), - targetPlayer.getYaw(), - targetPlayer.getPitch() - ); - } - - public static class TeleportRequest { - public UUID requestId = UUID.randomUUID(); - public UUID player; - public UUID target; - public int remainingTicks; - - public TeleportRequest(UUID player, UUID target) { - this.player = player; - this.target = target; - // Seconds in config per 20 ticks - this.remainingTicks = RccServer.CONFIG.teleportRequestTimeout() * 20; - } - - public void expire() { - remainingTicks = 0; - } - } - } diff --git a/src/main/java/cc/reconnected/server/commands/TeleportAskHereCommand.java b/src/main/java/cc/reconnected/server/commands/TeleportAskHereCommand.java index 24f8ae2..14ab56f 100644 --- a/src/main/java/cc/reconnected/server/commands/TeleportAskHereCommand.java +++ b/src/main/java/cc/reconnected/server/commands/TeleportAskHereCommand.java @@ -1,6 +1,6 @@ package cc.reconnected.server.commands; -import cc.reconnected.server.RccServer; +import cc.reconnected.server.core.TeleportTracker; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; @@ -52,8 +52,8 @@ public class TeleportAskHereCommand { return; } - var request = new TeleportAskCommand.TeleportRequest(target.getUuid(), player.getUuid()); - var targetRequests = RccServer.teleportRequests.get(target.getUuid()); + var request = new TeleportTracker.TeleportRequest(target.getUuid(), player.getUuid()); + var targetRequests = TeleportTracker.teleportRequests.get(target.getUuid()); targetRequests.addLast(request); var requestMessage = Component.empty() @@ -61,9 +61,9 @@ public class TeleportAskHereCommand { .appendSpace() .append(Component.text("requested you to teleport to them.", NamedTextColor.GOLD)) .appendNewline().appendSpace() - .append(TeleportAskCommand.makeButton(Component.text("Accept", NamedTextColor.GREEN), Component.text("Click to accept request"), "/tpaccept " + request.requestId)) + .append(TeleportTracker.makeButton(Component.text("Accept", NamedTextColor.GREEN), Component.text("Click to accept request"), "/tpaccept " + request.requestId)) .appendSpace() - .append(TeleportAskCommand.makeButton(Component.text("Refuse", NamedTextColor.RED), Component.text("Click to refuse request"), "/tpdeny " + request.requestId)); + .append(TeleportTracker.makeButton(Component.text("Refuse", NamedTextColor.RED), Component.text("Click to refuse request"), "/tpdeny " + request.requestId)); target.sendMessage(requestMessage); diff --git a/src/main/java/cc/reconnected/server/commands/TeleportDenyCommand.java b/src/main/java/cc/reconnected/server/commands/TeleportDenyCommand.java index 60845ec..b10a970 100644 --- a/src/main/java/cc/reconnected/server/commands/TeleportDenyCommand.java +++ b/src/main/java/cc/reconnected/server/commands/TeleportDenyCommand.java @@ -1,6 +1,6 @@ package cc.reconnected.server.commands; -import cc.reconnected.server.RccServer; +import cc.reconnected.server.core.TeleportTracker; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import net.minecraft.command.CommandRegistryAccess; @@ -25,7 +25,7 @@ public class TeleportDenyCommand { } var playerUuid = context.getSource().getPlayer().getUuid(); - var playerRequests = RccServer.teleportRequests.get(playerUuid); + var playerRequests = TeleportTracker.teleportRequests.get(playerUuid); var request = playerRequests.pollLast(); @@ -47,7 +47,7 @@ public class TeleportDenyCommand { var uuid = UuidArgumentType.getUuid(context, "uuid"); var playerUuid = context.getSource().getPlayer().getUuid(); - var playerRequests = RccServer.teleportRequests.get(playerUuid); + var playerRequests = TeleportTracker.teleportRequests.get(playerUuid); var request = playerRequests.stream().filter(req -> req.requestId.equals(uuid)).findFirst().orElse(null); if (request == null) { @@ -64,7 +64,7 @@ public class TeleportDenyCommand { dispatcher.register(literal("tprefuse").redirect(node)); } - private static void execute(CommandContext context, TeleportAskCommand.TeleportRequest request) { + private static void execute(CommandContext context, TeleportTracker.TeleportRequest request) { var source = context.getSource(); request.expire(); diff --git a/src/main/java/cc/reconnected/server/trackers/AfkTracker.java b/src/main/java/cc/reconnected/server/core/AfkTracker.java similarity index 77% rename from src/main/java/cc/reconnected/server/trackers/AfkTracker.java rename to src/main/java/cc/reconnected/server/core/AfkTracker.java index 44fbca6..c60d130 100644 --- a/src/main/java/cc/reconnected/server/trackers/AfkTracker.java +++ b/src/main/java/cc/reconnected/server/core/AfkTracker.java @@ -1,15 +1,18 @@ -package cc.reconnected.server.trackers; +package cc.reconnected.server.core; import cc.reconnected.server.RccServer; import cc.reconnected.server.data.StateSaverAndLoader; -import cc.reconnected.server.database.PlayerData; 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.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.TypedActionResult; @@ -22,7 +25,44 @@ public class AfkTracker { private final HashMap playerStates = new HashMap<>(); - public AfkTracker() { + private static final AfkTracker instance = new AfkTracker(); + public static AfkTracker getInstance() { + return instance; + } + + public static void register() { + PlayerActivityEvents.AFK.register((player, server) -> { + RccServer.LOGGER.info("{} is AFK. Active time: {} seconds.", player.getGameProfile().getName(), getInstance().getActiveTime(player)); + + var displayNameJson = Text.Serializer.toJson(player.getDisplayName()); + var displayName = JSONComponentSerializer.json().deserialize(displayNameJson); + + var message = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afkMessage(), + Placeholder.component("displayname", displayName), + Placeholder.unparsed("username", player.getGameProfile().getName()), + Placeholder.unparsed("uuid", player.getUuid().toString()) + ); + + RccServer.getInstance().broadcastMessage(server, message); + }); + + PlayerActivityEvents.AFK_RETURN.register((player, server) -> { + RccServer.LOGGER.info("{} is no longer AFK. Active time: {} seconds.", player.getGameProfile().getName(), getInstance().getActiveTime(player)); + + var displayNameJson = Text.Serializer.toJson(player.getDisplayName()); + var displayName = JSONComponentSerializer.json().deserialize(displayNameJson); + + var message = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afkReturnMessage(), + Placeholder.component("displayname", displayName), + Placeholder.unparsed("username", player.getGameProfile().getName()), + Placeholder.unparsed("uuid", player.getUuid().toString()) + ); + + RccServer.getInstance().broadcastMessage(server, message); + }); + } + + private AfkTracker() { ServerTickEvents.END_SERVER_TICK.register(server -> { if (server.getTicks() % cycleDelay == 0) { updatePlayers(server); @@ -83,7 +123,6 @@ public class AfkTracker { }); } - private void updatePlayer(ServerPlayerEntity player, MinecraftServer server) { var currentTick = server.getTicks(); var playerState = playerStates.computeIfAbsent(player.getUuid(), uuid -> new PlayerState(player, currentTick)); @@ -202,5 +241,4 @@ public class AfkTracker { var worldPlayerData = StateSaverAndLoader.getPlayerState(player); return worldPlayerData.activeTime; } - } diff --git a/src/main/java/cc/reconnected/server/core/BackTracker.java b/src/main/java/cc/reconnected/server/core/BackTracker.java new file mode 100644 index 0000000..4681f18 --- /dev/null +++ b/src/main/java/cc/reconnected/server/core/BackTracker.java @@ -0,0 +1,27 @@ +package cc.reconnected.server.core; + +import cc.reconnected.server.events.PlayerTeleport; +import cc.reconnected.server.struct.ServerPosition; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class BackTracker { + public static final ConcurrentHashMap lastPlayerPositions = new ConcurrentHashMap<>(); + + public static void register() { + ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + BackTracker.lastPlayerPositions.remove(handler.getPlayer().getUuid()); + }); + + PlayerTeleport.EVENT.register((player, origin, destination) -> { + lastPlayerPositions.put(player.getUuid(), origin); + }); + + ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { + lastPlayerPositions.put(oldPlayer.getUuid(), new ServerPosition(oldPlayer)); + }); + } +} diff --git a/src/main/java/cc/reconnected/server/core/HttpApiServer.java b/src/main/java/cc/reconnected/server/core/HttpApiServer.java new file mode 100644 index 0000000..d67ca15 --- /dev/null +++ b/src/main/java/cc/reconnected/server/core/HttpApiServer.java @@ -0,0 +1,104 @@ +package cc.reconnected.server.core; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import cc.reconnected.server.RccServer; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; + +import java.io.IOException; +import java.net.InetSocketAddress; + +public class HttpApiServer { + private static HttpApiServer instance; + + public static HttpApiServer getInstance() { + return instance; + } + + private static float currentTps = 0; + private static float currentMspt = 0; + private static int currentPlayerCount = 0; + + public static void register() { + if (!RccServer.CONFIG.enableHttpApi()) + return; + + try { + instance = new HttpApiServer(); + } catch (IOException e) { + RccServer.LOGGER.error("Could not start HTTP API server", e); + return; + } + new Thread(() -> instance.httpServer().start()); + + ServerLifecycleEvents.SERVER_STOPPING.register(server -> { + RccServer.LOGGER.info("Stopping HTTP services"); + instance.httpServer().stop(0); + }); + + ServerTickEvents.END_SERVER_TICK.register(server -> { + currentMspt = server.getTickTime(); + if (currentMspt != 0) { + currentTps = Math.min(20, 1000 / currentMspt); + } + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + currentPlayerCount = server.getCurrentPlayerCount() + 1; + }); + + ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + currentPlayerCount = server.getCurrentPlayerCount() - 1; + }); + } + + private final HttpServer server; + + public HttpServer httpServer() { + return this.server; + } + + private HttpApiServer() throws IOException { + server = HttpServer.create(new InetSocketAddress(RccServer.CONFIG.httpPort()), 0); + server.createContext("/tps", new TPSHandler()); + server.createContext("/mspt", new MSPTHandler()); + server.createContext("/player", new PlayerCountHandler()); + server.setExecutor(null); + } + + static class TPSHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + var tps = String.valueOf(currentTps); + t.sendResponseHeaders(200, tps.length()); + var body = t.getResponseBody(); + body.write(tps.getBytes()); + body.close(); + } + } + + static class MSPTHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + var tps = String.valueOf(currentTps); + t.sendResponseHeaders(200, tps.length()); + var body = t.getResponseBody(); + body.write(tps.getBytes()); + body.close(); + } + } + + static class PlayerCountHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + var tps = String.valueOf(currentPlayerCount); + t.sendResponseHeaders(200, tps.length()); + var body = t.getResponseBody(); + body.write(tps.getBytes()); + body.close(); + } + } +} diff --git a/src/main/java/cc/reconnected/server/tablist/TabList.java b/src/main/java/cc/reconnected/server/core/TabList.java similarity index 98% rename from src/main/java/cc/reconnected/server/tablist/TabList.java rename to src/main/java/cc/reconnected/server/core/TabList.java index 25143d3..2155053 100644 --- a/src/main/java/cc/reconnected/server/tablist/TabList.java +++ b/src/main/java/cc/reconnected/server/core/TabList.java @@ -1,4 +1,4 @@ -package cc.reconnected.server.tablist; +package cc.reconnected.server.core; import cc.reconnected.server.RccServer; import eu.pb4.placeholders.api.PlaceholderContext; diff --git a/src/main/java/cc/reconnected/server/core/TeleportTracker.java b/src/main/java/cc/reconnected/server/core/TeleportTracker.java new file mode 100644 index 0000000..36fac37 --- /dev/null +++ b/src/main/java/cc/reconnected/server/core/TeleportTracker.java @@ -0,0 +1,82 @@ +package cc.reconnected.server.core; + +import cc.reconnected.server.RccServer; +import cc.reconnected.server.events.PlayerTeleport; +import cc.reconnected.server.struct.ServerPosition; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; + +public class TeleportTracker { + public static final ConcurrentHashMap> teleportRequests = new ConcurrentHashMap<>(); + + public static void register() { + ServerTickEvents.END_SERVER_TICK.register(server -> { + teleportRequests.forEach((recipient, requestList) -> { + requestList.forEach(request -> { + if (request.remainingTicks-- == 0) { + requestList.remove(request); + } + }); + }); + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + teleportRequests.put(handler.getPlayer().getUuid(), new ConcurrentLinkedDeque<>()); + }); + + ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + TeleportTracker.teleportRequests.remove(handler.getPlayer().getUuid()); + }); + } + + public static Component makeButton(ComponentLike text, ComponentLike hoverText, String command) { + return Component.empty() + .append(Component.text("[")) + .append(text) + .append(Component.text("]")) + .color(NamedTextColor.AQUA) + .hoverEvent(HoverEvent.showText(hoverText)) + .clickEvent(ClickEvent.runCommand(command)); + } + + public static void teleport(ServerPlayerEntity sourcePlayer, ServerPlayerEntity targetPlayer) { + PlayerTeleport.EVENT.invoker().teleport(sourcePlayer, new ServerPosition(sourcePlayer), new ServerPosition(targetPlayer)); + + sourcePlayer.teleport( + targetPlayer.getServerWorld(), + targetPlayer.getX(), + targetPlayer.getY(), + targetPlayer.getZ(), + targetPlayer.getYaw(), + targetPlayer.getPitch() + ); + } + + public static class TeleportRequest { + public UUID requestId = UUID.randomUUID(); + public UUID player; + public UUID target; + public int remainingTicks; + + public TeleportRequest(UUID player, UUID target) { + this.player = player; + this.target = target; + // Seconds in config per 20 ticks + this.remainingTicks = RccServer.CONFIG.teleportRequestTimeout() * 20; + } + + public void expire() { + remainingTicks = 0; + } + } +} diff --git a/src/main/java/cc/reconnected/server/events/PlayerTeleport.java b/src/main/java/cc/reconnected/server/events/PlayerTeleport.java new file mode 100644 index 0000000..a14967f --- /dev/null +++ b/src/main/java/cc/reconnected/server/events/PlayerTeleport.java @@ -0,0 +1,17 @@ +package cc.reconnected.server.events; + +import cc.reconnected.server.struct.ServerPosition; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.network.ServerPlayerEntity; + +public interface PlayerTeleport { + Event EVENT = EventFactory.createArrayBacked(PlayerTeleport.class, + (listeners) -> (player, origin, destination) -> { + for (PlayerTeleport listener : listeners) { + listener.teleport(player, origin, destination); + } + }); + + void teleport(ServerPlayerEntity player, ServerPosition origin, ServerPosition destination); +} diff --git a/src/main/java/cc/reconnected/server/http/ServiceServer.java b/src/main/java/cc/reconnected/server/http/ServiceServer.java deleted file mode 100644 index e3e4445..0000000 --- a/src/main/java/cc/reconnected/server/http/ServiceServer.java +++ /dev/null @@ -1,61 +0,0 @@ -package cc.reconnected.server.http; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import cc.reconnected.server.RccServer; - -import java.io.IOException; -import java.net.InetSocketAddress; - -public class ServiceServer { - private final HttpServer server; - - public HttpServer httpServer() { - return this.server; - } - - public ServiceServer() throws IOException { - server = HttpServer.create(new InetSocketAddress(RccServer.CONFIG.httpPort()), 0); - server.createContext("/tps", new TPSHandler()); - server.createContext("/mspt", new MSPTHandler()); - server.createContext("/player", new PlayerCountHandler()); - server.setExecutor(null); - - var httpThread = new Thread(server::start); - httpThread.start(); - } - - static class TPSHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - var tps = String.valueOf(RccServer.getTPS()); - t.sendResponseHeaders(200, tps.length()); - var body = t.getResponseBody(); - body.write(tps.getBytes()); - body.close(); - } - } - - static class MSPTHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - var tps = String.valueOf(RccServer.getMSPT()); - t.sendResponseHeaders(200, tps.length()); - var body = t.getResponseBody(); - body.write(tps.getBytes()); - body.close(); - } - } - - static class PlayerCountHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - var tps = String.valueOf(RccServer.getPlayerCount()); - t.sendResponseHeaders(200, tps.length()); - var body = t.getResponseBody(); - body.write(tps.getBytes()); - body.close(); - } - } -} diff --git a/src/main/java/cc/reconnected/server/struct/ServerPosition.java b/src/main/java/cc/reconnected/server/struct/ServerPosition.java index ead4b35..35e08b0 100644 --- a/src/main/java/cc/reconnected/server/struct/ServerPosition.java +++ b/src/main/java/cc/reconnected/server/struct/ServerPosition.java @@ -1,6 +1,6 @@ package cc.reconnected.server.struct; -import cc.reconnected.server.RccServer; +import cc.reconnected.server.core.BackTracker; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; @@ -32,7 +32,7 @@ public class ServerPosition { public void teleport(ServerPlayerEntity player) { var currentPosition = new ServerPosition(player); - RccServer.lastPlayerPositions.put(player.getUuid(), currentPosition); + BackTracker.lastPlayerPositions.put(player.getUuid(), currentPosition); player.teleport( this.world,