diff --git a/src/main/java/net/minecraftforge/fml/client/ClientHooks.java b/src/main/java/net/minecraftforge/fml/client/ClientHooks.java index a5c7273279..40bd53c742 100644 --- a/src/main/java/net/minecraftforge/fml/client/ClientHooks.java +++ b/src/main/java/net/minecraftforge/fml/client/ClientHooks.java @@ -128,7 +128,7 @@ public class ClientHooks if (fmlver > FMLNetworkConstants.FMLNETVERSION) { extraReason = "fml.menu.multiplayer.clientoutdated"; } - target.forgeData = new ExtendedServerListData("FML", extraServerMods.isEmpty() && fmlNetMatches && channelsMatch && modsMatch, mods.size(), extraReason); + target.forgeData = new ExtendedServerListData("FML", extraServerMods.isEmpty() && fmlNetMatches && channelsMatch && modsMatch, mods.size(), extraReason, packet.getForgeData().isTruncated()); } else { target.forgeData = new ExtendedServerListData("VANILLA", NetworkRegistry.canConnectToVanillaServer(),0, null); } @@ -154,6 +154,10 @@ public class ClientHooks tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.incompatible"); } } + if (target.forgeData.truncated) + { + tooltip += "\n" + ForgeI18n.parseMessage("fml.menu.multiplayer.truncated"); + } break; case "VANILLA": if (target.forgeData.isCompatible) { diff --git a/src/main/java/net/minecraftforge/fml/client/ExtendedServerListData.java b/src/main/java/net/minecraftforge/fml/client/ExtendedServerListData.java index 879ca0197f..1a1f755600 100644 --- a/src/main/java/net/minecraftforge/fml/client/ExtendedServerListData.java +++ b/src/main/java/net/minecraftforge/fml/client/ExtendedServerListData.java @@ -24,12 +24,19 @@ public class ExtendedServerListData { public final boolean isCompatible; public int numberOfMods; public String extraReason; + public final boolean truncated; public ExtendedServerListData(String type, boolean isCompatible, int num, String extraReason) + { + this(type, isCompatible, num, extraReason, false); + } + + public ExtendedServerListData(String type, boolean isCompatible, int num, String extraReason, boolean truncated) { this.type = type; this.isCompatible = isCompatible; this.numberOfMods = num; this.extraReason = extraReason; + this.truncated = truncated; } } diff --git a/src/main/java/net/minecraftforge/fml/network/FMLStatusPing.java b/src/main/java/net/minecraftforge/fml/network/FMLStatusPing.java index db52921d1f..870f938f97 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLStatusPing.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLStatusPing.java @@ -63,10 +63,15 @@ import static net.minecraftforge.fml.network.FMLNetworkConstants.NETWORK; */ public class FMLStatusPing { private static final Logger LOGGER = LogManager.getLogger(); + private static final int CHANNEL_TRUNCATE_LIMIT = 150; + private static final int MOD_TRUNCATE_LIMIT = 150; + private static volatile boolean warnedAboutTruncation = false; private transient Map> channels; private transient Map mods; private transient int fmlNetworkVer; + private transient boolean truncated; + public FMLStatusPing() { this.channels = NetworkRegistry.buildChannelVersionsForListPing(); this.mods = new HashMap<>(); @@ -74,12 +79,14 @@ public class FMLStatusPing { mods.put(modid, mc.getCustomExtension(ExtensionPoint.DISPLAYTEST). map(Pair::getLeft).map(Supplier::get).orElse(FMLNetworkConstants.IGNORESERVERONLY))); this.fmlNetworkVer = FMLNetworkConstants.FMLNETVERSION; + this.truncated = false; } - private FMLStatusPing(Map> deserialized, Map modMarkers, int fmlNetVer) { + private FMLStatusPing(Map> deserialized, Map modMarkers, int fmlNetVer, boolean truncated) { this.channels = ImmutableMap.copyOf(deserialized); this.mods = modMarkers; this.fmlNetworkVer = fmlNetVer; + this.truncated = truncated; } public static class Serializer { @@ -96,7 +103,8 @@ public class FMLStatusPing { collect(Collectors.toMap(jo -> JSONUtils.getAsString(jo, "modId"), jo->JSONUtils.getAsString(jo, "modmarker"))); final int remoteFMLVersion = JSONUtils.getAsInt(forgeData, "fmlNetworkVersion"); - return new FMLStatusPing(channels, mods, remoteFMLVersion); + final boolean truncated = JSONUtils.getAsBoolean(forgeData, "truncated", false); + return new FMLStatusPing(channels, mods, remoteFMLVersion, truncated); } catch (JsonSyntaxException e) { LOGGER.debug(NETWORK, "Encountered an error parsing status ping data", e); return null; @@ -106,7 +114,17 @@ public class FMLStatusPing { public static JsonObject serialize(FMLStatusPing forgeData, JsonSerializationContext ctx) { JsonObject obj = new JsonObject(); JsonArray channels = new JsonArray(); - forgeData.channels.forEach((namespace, version) -> { + boolean truncated = forgeData.channels.size() > CHANNEL_TRUNCATE_LIMIT || forgeData.mods.size() > MOD_TRUNCATE_LIMIT; + if (truncated && !warnedAboutTruncation) + { + warnedAboutTruncation = true; + LOGGER.warn("Heuristically truncating mod and/or network channel list in server status ping packet. Compatibility report " + + "in the multiplayer screen may be inaccurate."); + } + + forgeData.channels.entrySet().stream().limit(CHANNEL_TRUNCATE_LIMIT).forEach(entry -> { + ResourceLocation namespace = entry.getKey(); + Pair version = entry.getValue(); JsonObject mi = new JsonObject(); mi.addProperty("res", namespace.toString()); mi.addProperty("version", version.getLeft()); @@ -117,7 +135,9 @@ public class FMLStatusPing { obj.add("channels", channels); JsonArray modTestValues = new JsonArray(); - forgeData.mods.forEach((modId, value) -> { + forgeData.mods.entrySet().stream().limit(MOD_TRUNCATE_LIMIT).forEach(entry -> { + String modId = entry.getKey(); + String value = entry.getValue(); JsonObject mi = new JsonObject(); mi.addProperty("modId", modId); mi.addProperty("modmarker", value); @@ -125,6 +145,7 @@ public class FMLStatusPing { }); obj.add("mods", modTestValues); obj.addProperty("fmlNetworkVersion", forgeData.fmlNetworkVer); + obj.addProperty("truncated", truncated); return obj; } } @@ -141,4 +162,8 @@ public class FMLStatusPing { return fmlNetworkVer; } + public boolean isTruncated() + { + return truncated; + } } diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index e78b0f1ef1..7cbcc65f6a 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -26,6 +26,7 @@ "fml.menu.multiplayer.compatible":"Compatible FML modded server\n{0,choice,1#1 mod|1<{0} mods} present", "fml.menu.multiplayer.incompatible":"Incompatible FML modded server", "fml.menu.multiplayer.incompatible.extra":"Incompatible FML modded server\n{0}", + "fml.menu.multiplayer.truncated":"Data may be inaccurate due to protocol size limits.", "fml.menu.multiplayer.vanilla":"Vanilla server", "fml.menu.multiplayer.vanilla.incompatible":"Incompatible Vanilla server", "fml.menu.multiplayer.unknown":"Unknown server {0}",