diff --git a/core/src/main/java/tc/oc/pgm/listeners/ServerPingDataListener.java b/core/src/main/java/tc/oc/pgm/listeners/ServerPingDataListener.java index 86e39cf529..417ac0ca79 100644 --- a/core/src/main/java/tc/oc/pgm/listeners/ServerPingDataListener.java +++ b/core/src/main/java/tc/oc/pgm/listeners/ServerPingDataListener.java @@ -1,7 +1,6 @@ package tc.oc.pgm.listeners; import static tc.oc.pgm.util.Assert.assertNotNull; -import static tc.oc.pgm.util.bukkit.MiscUtils.MISC_UTILS; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -30,6 +29,7 @@ import tc.oc.pgm.api.match.event.MatchLoadEvent; import tc.oc.pgm.map.contrib.PlayerContributor; import tc.oc.pgm.util.ClassLogger; +import tc.oc.pgm.util.event.ExtraPingDataRequestEvent; public class ServerPingDataListener implements Listener { @@ -37,7 +37,6 @@ public class ServerPingDataListener implements Listener { private final MapOrder mapOrder; private final Logger logger; private final AtomicBoolean ready; - private final AtomicBoolean legacySportPaper; private final LoadingCache matchCache; public ServerPingDataListener(MatchManager matchManager, MapOrder mapOrder, Logger parentLogger) { @@ -45,7 +44,6 @@ public ServerPingDataListener(MatchManager matchManager, MapOrder mapOrder, Logg this.mapOrder = assertNotNull(mapOrder); this.logger = ClassLogger.get(assertNotNull(parentLogger), ServerPingDataListener.class); this.ready = new AtomicBoolean(); - this.legacySportPaper = new AtomicBoolean(); this.matchCache = CacheBuilder.newBuilder() .weakKeys() .expireAfterWrite(5L, TimeUnit.SECONDS) @@ -66,7 +64,7 @@ public void onMatchLoad(MatchLoadEvent event) { @EventHandler public void onServerListPing(ServerListPingEvent event) { - if (!ready.get() || legacySportPaper.get()) return; + if (!ready.get()) return; // Remove vanished players from player sample/ping count Iterator playerSample = event.iterator(); @@ -76,20 +74,19 @@ public void onServerListPing(ServerListPingEvent event) { playerSample.remove(); } } + } - try { - JsonObject root = MISC_UTILS.getServerListExtra(event, PGM.get()); - this.matchManager.getMatches().forEachRemaining(match -> { - String matchId = match.getId(); - try { - root.add(matchId, this.matchCache.get(match)); - } catch (ExecutionException e) { - this.logger.log(Level.SEVERE, "Could not load server ping data for match: " + matchId, e); - } - }); - } catch (NoSuchMethodError ex) { - legacySportPaper.compareAndSet(false, true); - } + @EventHandler + public void onExtraDataRequest(ExtraPingDataRequestEvent event) { + JsonObject root = event.getServerListExtra(PGM.get()); + this.matchManager.getMatches().forEachRemaining(match -> { + String matchId = match.getId(); + try { + root.add(matchId, this.matchCache.get(match)); + } catch (ExecutionException e) { + this.logger.log(Level.SEVERE, "Could not load server ping data for match: " + matchId, e); + } + }); } private void serializeMatch(Match match, JsonObject jsonObject) { diff --git a/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/impl/ModernMiscUtil.java b/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/impl/ModernMiscUtil.java index 740d4e18a3..392427d648 100644 --- a/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/impl/ModernMiscUtil.java +++ b/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/impl/ModernMiscUtil.java @@ -2,7 +2,6 @@ import static tc.oc.pgm.util.platform.Supports.Variant.PAPER; -import com.google.gson.JsonObject; import java.nio.file.Path; import java.util.List; import net.kyori.adventure.key.Key; @@ -35,9 +34,7 @@ import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerPickupArrowEvent; import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; import org.bukkit.scoreboard.Team; import tc.oc.pgm.platform.modern.material.ModernBlockMaterialData; import tc.oc.pgm.util.DataVersions; @@ -47,12 +44,6 @@ @Supports(value = PAPER, minVersion = "1.21.5") public class ModernMiscUtil implements MiscUtils { - @Override - public JsonObject getServerListExtra(ServerListPingEvent event, Plugin plugin) { - // TODO: PLATFORM 1.20 no support for extra fields in server ping - return new JsonObject(); - } - @Override public EventException createEventException(Throwable cause, Event event) { return new EventException(cause); diff --git a/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/packets/PacketManipulations.java b/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/packets/PacketManipulations.java index b5f2cd2a21..0e4f733479 100644 --- a/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/packets/PacketManipulations.java +++ b/platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/packets/PacketManipulations.java @@ -1,13 +1,20 @@ package tc.oc.pgm.platform.modern.packets; import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.injector.netty.WirePacket; +import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; +import io.netty.buffer.Unpooled; import java.util.ArrayList; import java.util.List; import java.util.Map; import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.status.ServerStatus; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.world.entity.Entity; @@ -16,6 +23,7 @@ import org.bukkit.plugin.Plugin; import tc.oc.pgm.platform.modern.listeners.PlayerTracker; import tc.oc.pgm.platform.modern.util.Packets; +import tc.oc.pgm.util.event.ExtraPingDataRequestEvent; import tc.oc.pgm.util.reflect.ReflectionUtils; @SuppressWarnings("unchecked") @@ -46,6 +54,10 @@ public PacketManipulations(Plugin plugin, PlayerTracker tracker) { PacketType.Play.Server.ENTITY_STATUS, this::handleEntityStatus, PacketType.Play.Server.PLAYER_COMBAT_KILL, this::handleCombatKill, PacketType.Play.Server.ENTITY_METADATA, this::handleEntityMetadata)); + Packets.register( + plugin, + ListenerPriority.HIGHEST, + Map.of(PacketType.Status.Server.SERVER_INFO, this::handleServerPing)); } private void handleEntityStatus(PacketEvent event) { @@ -127,4 +139,39 @@ private void handleEntityMetadata(PacketEvent event) { if (!checkHealth && !hideParticles) return; } } + + private void handleServerPing(PacketEvent event) { + JsonObject pingExtra = new JsonObject(); + new ExtraPingDataRequestEvent() { + @Override + public JsonObject getServerListExtra(Plugin plugin) { + return (JsonObject) + pingExtra.asMap().computeIfAbsent(plugin.namespace(), k -> new JsonObject()); + } + }.callEvent(); + + if (!pingExtra.isEmpty()) { + // Encode the response manually, otherwise the extra data will get lost + var serverPing = (ServerStatus) event.getPacket().getServerPings().read(0).getHandle(); + var jsonData = ServerStatus.CODEC + .encodeStart(JsonOps.INSTANCE, serverPing) + .getOrThrow() + .getAsJsonObject(); + + jsonData.add("bukkit_extra", pingExtra); + + var byteBuf = Unpooled.buffer(); + ByteBufCodecs.lenientJson(Short.MAX_VALUE).encode(byteBuf, jsonData); + // Trim the excess allocated by the buffer to make things behave more like vanilla + byteBuf.capacity(byteBuf.readableBytes()); + + ProtocolLibrary.getProtocolManager() + .sendWirePacket( + event.getPlayer(), + new WirePacket(PacketType.Status.Server.SERVER_INFO, byteBuf.array())); + + byteBuf.release(); + event.setCancelled(true); + } + } } diff --git a/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/SportPaperListener.java b/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/SportPaperListener.java index 2c520ccc1f..3b28676428 100644 --- a/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/SportPaperListener.java +++ b/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/SportPaperListener.java @@ -2,8 +2,11 @@ import static tc.oc.pgm.util.event.EventUtil.handleCall; +import com.google.gson.JsonObject; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import tc.oc.pgm.util.event.ExtraPingDataRequestEvent; import tc.oc.pgm.util.event.block.BlockDispenseEntityEvent; import tc.oc.pgm.util.event.block.BlockFallEvent; import tc.oc.pgm.util.event.entity.EntityDespawnInVoidEvent; @@ -19,7 +22,6 @@ import tc.oc.pgm.util.event.player.PlayerSpawnEntityEvent; public class SportPaperListener implements Listener { - @EventHandler(ignoreCancelled = true) public void onBlockFall(org.bukkit.event.block.BlockFallEvent sportEvent) { BlockFallEvent pgmEvent = new BlockFallEvent(sportEvent.getBlock(), sportEvent.getEntity()); @@ -108,4 +110,16 @@ public void onEntityDespawn(org.bukkit.event.entity.EntityDespawnInVoidEvent spo EntityDespawnInVoidEvent pgmEvent = new EntityDespawnInVoidEvent(sportEvent.getEntity()); handleCall(pgmEvent, sportEvent); } + + @EventHandler + public void onServerPing(final org.bukkit.event.server.ServerListPingEvent event) { + handleCall( + new ExtraPingDataRequestEvent() { + @Override + public JsonObject getServerListExtra(Plugin plugin) { + return event.getOrCreateExtra(plugin); + } + }, + event); + } } diff --git a/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/impl/SpMiscUtil.java b/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/impl/SpMiscUtil.java index c3229f9743..8e93e518c8 100644 --- a/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/impl/SpMiscUtil.java +++ b/platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/impl/SpMiscUtil.java @@ -4,7 +4,6 @@ import static tc.oc.pgm.util.platform.Supports.Priority.HIGH; import static tc.oc.pgm.util.platform.Supports.Variant.SPORTPAPER; -import com.google.gson.JsonObject; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -31,9 +30,7 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; import tc.oc.pgm.platform.sportpaper.material.LegacyMaterialData; import tc.oc.pgm.util.DataVersions; import tc.oc.pgm.util.bukkit.MiscUtils; @@ -50,11 +47,6 @@ public boolean yield(Event event) { return true; } - @Override - public JsonObject getServerListExtra(ServerListPingEvent event, Plugin plugin) { - return event.getOrCreateExtra(plugin); - } - @Override public EventException createEventException(Throwable cause, Event event) { return new EventException(cause, event); diff --git a/util/src/main/java/tc/oc/pgm/util/bukkit/MiscUtils.java b/util/src/main/java/tc/oc/pgm/util/bukkit/MiscUtils.java index 0abe7196dc..92522eef04 100644 --- a/util/src/main/java/tc/oc/pgm/util/bukkit/MiscUtils.java +++ b/util/src/main/java/tc/oc/pgm/util/bukkit/MiscUtils.java @@ -1,6 +1,5 @@ package tc.oc.pgm.util.bukkit; -import com.google.gson.JsonObject; import java.nio.file.Path; import java.util.List; import net.kyori.adventure.key.Key; @@ -20,9 +19,7 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; import org.bukkit.scoreboard.Team; import tc.oc.pgm.util.material.BlockMaterialData; import tc.oc.pgm.util.platform.Platform; @@ -34,10 +31,6 @@ default boolean yield(Event event) { return false; } - default JsonObject getServerListExtra(ServerListPingEvent event, Plugin plugin) { - return new JsonObject(); - } - default EventException createEventException(Throwable cause, Event event) { return new EventException(cause); } diff --git a/util/src/main/java/tc/oc/pgm/util/event/ExtraPingDataRequestEvent.java b/util/src/main/java/tc/oc/pgm/util/event/ExtraPingDataRequestEvent.java new file mode 100644 index 0000000000..5a28561ada --- /dev/null +++ b/util/src/main/java/tc/oc/pgm/util/event/ExtraPingDataRequestEvent.java @@ -0,0 +1,25 @@ +package tc.oc.pgm.util.event; + +import com.google.gson.JsonObject; +import org.bukkit.event.HandlerList; +import org.bukkit.event.server.ServerEvent; +import org.bukkit.plugin.Plugin; + +/** + * Called by individual platform implementations to allow listeners to attach additional server ping + * data + */ +public abstract class ExtraPingDataRequestEvent extends ServerEvent { + public abstract JsonObject getServerListExtra(Plugin plugin); + + private static final HandlerList handlers = new HandlerList(); + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +}