Skip to content

Commit ffed59b

Browse files
committed
feat: allow attaching extra ping data on modern
This patch allows modern Minecraft servers to include additional match data in the ping response by splitting off extra ping data attachments into a ExtraPingDataRequestEvent that individual platforms can call with their own implementation that can be appropriately handled afterwards. On SP, this is handled as usual. On modern Minecraft, this is implemented using a ProtocolLib hook. Signed-off-by: TTtie <[email protected]>
1 parent ef6d1c5 commit ffed59b

File tree

7 files changed

+93
-29
lines changed

7 files changed

+93
-29
lines changed

core/src/main/java/tc/oc/pgm/listeners/ServerPingDataListener.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package tc.oc.pgm.listeners;
22

33
import static tc.oc.pgm.util.Assert.assertNotNull;
4-
import static tc.oc.pgm.util.bukkit.MiscUtils.MISC_UTILS;
54

65
import com.google.common.cache.CacheBuilder;
76
import com.google.common.cache.CacheLoader;
@@ -30,6 +29,7 @@
3029
import tc.oc.pgm.api.match.event.MatchLoadEvent;
3130
import tc.oc.pgm.map.contrib.PlayerContributor;
3231
import tc.oc.pgm.util.ClassLogger;
32+
import tc.oc.pgm.util.event.ExtraPingDataRequestEvent;
3333

3434
public class ServerPingDataListener implements Listener {
3535

@@ -66,7 +66,7 @@ public void onMatchLoad(MatchLoadEvent event) {
6666

6767
@EventHandler
6868
public void onServerListPing(ServerListPingEvent event) {
69-
if (!ready.get() || legacySportPaper.get()) return;
69+
if (!ready.get()) return;
7070

7171
// Remove vanished players from player sample/ping count
7272
Iterator<Player> playerSample = event.iterator();
@@ -76,9 +76,14 @@ public void onServerListPing(ServerListPingEvent event) {
7676
playerSample.remove();
7777
}
7878
}
79+
}
80+
81+
@EventHandler
82+
public void onExtraDataRequest(ExtraPingDataRequestEvent event) {
83+
if (legacySportPaper.get()) return;
7984

8085
try {
81-
JsonObject root = MISC_UTILS.getServerListExtra(event, PGM.get());
86+
JsonObject root = event.getServerListExtra(PGM.get());
8287
this.matchManager.getMatches().forEachRemaining(match -> {
8388
String matchId = match.getId();
8489
try {

platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/impl/ModernMiscUtil.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import static tc.oc.pgm.util.platform.Supports.Variant.PAPER;
44

5-
import com.google.gson.JsonObject;
65
import java.nio.file.Path;
76
import java.util.List;
87
import net.kyori.adventure.key.Key;
@@ -33,9 +32,7 @@
3332
import org.bukkit.event.entity.EntityDamageEvent;
3433
import org.bukkit.event.entity.EntityExplodeEvent;
3534
import org.bukkit.event.entity.PlayerDeathEvent;
36-
import org.bukkit.event.server.ServerListPingEvent;
3735
import org.bukkit.inventory.ItemStack;
38-
import org.bukkit.plugin.Plugin;
3936
import org.bukkit.scoreboard.Team;
4037
import tc.oc.pgm.platform.modern.material.ModernBlockMaterialData;
4138
import tc.oc.pgm.util.DataVersions;
@@ -45,12 +42,6 @@
4542

4643
@Supports(value = PAPER, minVersion = "1.21.5")
4744
public class ModernMiscUtil implements MiscUtils {
48-
@Override
49-
public JsonObject getServerListExtra(ServerListPingEvent event, Plugin plugin) {
50-
// TODO: PLATFORM 1.20 no support for extra fields in server ping
51-
return new JsonObject();
52-
}
53-
5445
@Override
5546
public EventException createEventException(Throwable cause, Event event) {
5647
return new EventException(cause);

platform/platform-modern/src/main/java/tc/oc/pgm/platform/modern/packets/PacketManipulations.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
package tc.oc.pgm.platform.modern.packets;
22

33
import com.comphenix.protocol.PacketType;
4+
import com.comphenix.protocol.ProtocolLibrary;
45
import com.comphenix.protocol.events.ListenerPriority;
56
import com.comphenix.protocol.events.PacketEvent;
7+
import com.comphenix.protocol.injector.netty.WirePacket;
8+
import com.google.gson.JsonObject;
9+
import com.mojang.serialization.Codec;
10+
import com.mojang.serialization.Dynamic;
11+
import com.mojang.serialization.JsonOps;
12+
import io.netty.buffer.Unpooled;
613
import java.util.ArrayList;
714
import java.util.List;
815
import java.util.Map;
916
import net.minecraft.core.particles.ParticleOptions;
17+
import net.minecraft.network.FriendlyByteBuf;
1018
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
19+
import net.minecraft.network.protocol.status.ServerStatus;
1120
import net.minecraft.network.syncher.EntityDataAccessor;
1221
import net.minecraft.network.syncher.SynchedEntityData;
1322
import net.minecraft.world.entity.Entity;
@@ -16,6 +25,7 @@
1625
import org.bukkit.plugin.Plugin;
1726
import tc.oc.pgm.platform.modern.listeners.PlayerTracker;
1827
import tc.oc.pgm.platform.modern.util.Packets;
28+
import tc.oc.pgm.util.event.ExtraPingDataRequestEvent;
1929
import tc.oc.pgm.util.reflect.ReflectionUtils;
2030

2131
@SuppressWarnings("unchecked")
@@ -45,7 +55,8 @@ public PacketManipulations(Plugin plugin, PlayerTracker tracker) {
4555
Map.of(
4656
PacketType.Play.Server.ENTITY_STATUS, this::handleEntityStatus,
4757
PacketType.Play.Server.PLAYER_COMBAT_KILL, this::handleCombatKill,
48-
PacketType.Play.Server.ENTITY_METADATA, this::handleEntityMetadata));
58+
PacketType.Play.Server.ENTITY_METADATA, this::handleEntityMetadata,
59+
PacketType.Status.Server.SERVER_INFO, this::handleServerPing));
4960
}
5061

5162
private void handleEntityStatus(PacketEvent event) {
@@ -127,4 +138,37 @@ private void handleEntityMetadata(PacketEvent event) {
127138
if (!checkHealth && !hideParticles) return;
128139
}
129140
}
141+
142+
private void handleServerPing(PacketEvent event) {
143+
JsonObject pingExtra = new JsonObject();
144+
new ExtraPingDataRequestEvent() {
145+
@Override
146+
public JsonObject getServerListExtra(Plugin plugin) {
147+
return (JsonObject)
148+
pingExtra.asMap().computeIfAbsent(plugin.namespace(), k -> new JsonObject());
149+
}
150+
}.callEvent();
151+
152+
if (!pingExtra.isEmpty()) {
153+
// Encode the response manually, otherwise the extra data will get lost
154+
var serverPing = (ServerStatus) event.getPacket().getServerPings().read(0).getHandle();
155+
var jsonData = ServerStatus.CODEC
156+
.encodeStart(JsonOps.INSTANCE, serverPing)
157+
.getOrThrow()
158+
.getAsJsonObject();
159+
160+
jsonData.add("bukkit_extra", pingExtra);
161+
162+
var byteBuf = new FriendlyByteBuf(Unpooled.buffer());
163+
byteBuf.writeJsonWithCodec(Codec.PASSTHROUGH, new Dynamic<>(JsonOps.INSTANCE, jsonData));
164+
165+
ProtocolLibrary.getProtocolManager()
166+
.sendWirePacket(
167+
event.getPlayer(),
168+
new WirePacket(PacketType.Status.Server.SERVER_INFO, byteBuf.array()));
169+
170+
byteBuf.release();
171+
event.setCancelled(true);
172+
}
173+
}
130174
}

platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/SportPaperListener.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import static tc.oc.pgm.util.event.EventUtil.handleCall;
44

5+
import com.google.gson.JsonObject;
56
import org.bukkit.event.EventHandler;
67
import org.bukkit.event.Listener;
8+
import org.bukkit.plugin.Plugin;
9+
import tc.oc.pgm.util.event.ExtraPingDataRequestEvent;
710
import tc.oc.pgm.util.event.block.BlockDispenseEntityEvent;
811
import tc.oc.pgm.util.event.block.BlockFallEvent;
912
import tc.oc.pgm.util.event.entity.EntityDespawnInVoidEvent;
@@ -19,7 +22,6 @@
1922
import tc.oc.pgm.util.event.player.PlayerSpawnEntityEvent;
2023

2124
public class SportPaperListener implements Listener {
22-
2325
@EventHandler(ignoreCancelled = true)
2426
public void onBlockFall(org.bukkit.event.block.BlockFallEvent sportEvent) {
2527
BlockFallEvent pgmEvent = new BlockFallEvent(sportEvent.getBlock(), sportEvent.getEntity());
@@ -108,4 +110,16 @@ public void onEntityDespawn(org.bukkit.event.entity.EntityDespawnInVoidEvent spo
108110
EntityDespawnInVoidEvent pgmEvent = new EntityDespawnInVoidEvent(sportEvent.getEntity());
109111
handleCall(pgmEvent, sportEvent);
110112
}
113+
114+
@EventHandler
115+
public void onServerPing(final org.bukkit.event.server.ServerListPingEvent event) {
116+
handleCall(
117+
new ExtraPingDataRequestEvent() {
118+
@Override
119+
public JsonObject getServerListExtra(Plugin plugin) {
120+
return event.getOrCreateExtra(plugin);
121+
}
122+
},
123+
event);
124+
}
111125
}

platform/platform-sportpaper/src/main/java/tc/oc/pgm/platform/sportpaper/impl/SpMiscUtil.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import static tc.oc.pgm.util.platform.Supports.Priority.HIGH;
55
import static tc.oc.pgm.util.platform.Supports.Variant.SPORTPAPER;
66

7-
import com.google.gson.JsonObject;
87
import java.nio.file.Files;
98
import java.nio.file.Path;
109
import java.util.List;
@@ -30,9 +29,7 @@
3029
import org.bukkit.event.entity.EntityDamageEvent;
3130
import org.bukkit.event.entity.EntityExplodeEvent;
3231
import org.bukkit.event.entity.PlayerDeathEvent;
33-
import org.bukkit.event.server.ServerListPingEvent;
3432
import org.bukkit.inventory.ItemStack;
35-
import org.bukkit.plugin.Plugin;
3633
import tc.oc.pgm.platform.sportpaper.material.LegacyMaterialData;
3734
import tc.oc.pgm.util.DataVersions;
3835
import tc.oc.pgm.util.bukkit.MiscUtils;
@@ -49,11 +46,6 @@ public boolean yield(Event event) {
4946
return true;
5047
}
5148

52-
@Override
53-
public JsonObject getServerListExtra(ServerListPingEvent event, Plugin plugin) {
54-
return event.getOrCreateExtra(plugin);
55-
}
56-
5749
@Override
5850
public EventException createEventException(Throwable cause, Event event) {
5951
return new EventException(cause, event);

util/src/main/java/tc/oc/pgm/util/bukkit/MiscUtils.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package tc.oc.pgm.util.bukkit;
22

3-
import com.google.gson.JsonObject;
43
import java.nio.file.Path;
54
import java.util.List;
65
import net.kyori.adventure.key.Key;
@@ -19,9 +18,7 @@
1918
import org.bukkit.event.entity.EntityDamageEvent;
2019
import org.bukkit.event.entity.EntityExplodeEvent;
2120
import org.bukkit.event.entity.PlayerDeathEvent;
22-
import org.bukkit.event.server.ServerListPingEvent;
2321
import org.bukkit.inventory.ItemStack;
24-
import org.bukkit.plugin.Plugin;
2522
import org.bukkit.scoreboard.Team;
2623
import tc.oc.pgm.util.material.BlockMaterialData;
2724
import tc.oc.pgm.util.platform.Platform;
@@ -33,10 +30,6 @@ default boolean yield(Event event) {
3330
return false;
3431
}
3532

36-
default JsonObject getServerListExtra(ServerListPingEvent event, Plugin plugin) {
37-
return new JsonObject();
38-
}
39-
4033
default EventException createEventException(Throwable cause, Event event) {
4134
return new EventException(cause);
4235
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package tc.oc.pgm.util.event;
2+
3+
import com.google.gson.JsonObject;
4+
import org.bukkit.event.HandlerList;
5+
import org.bukkit.event.server.ServerEvent;
6+
import org.bukkit.plugin.Plugin;
7+
8+
/**
9+
* Called by individual platform implementations to allow listeners to attach additional server ping
10+
* data
11+
*/
12+
public abstract class ExtraPingDataRequestEvent extends ServerEvent {
13+
public abstract JsonObject getServerListExtra(Plugin plugin);
14+
15+
private static final HandlerList handlers = new HandlerList();
16+
17+
@Override
18+
public HandlerList getHandlers() {
19+
return handlers;
20+
}
21+
22+
public static HandlerList getHandlerList() {
23+
return handlers;
24+
}
25+
}

0 commit comments

Comments
 (0)