diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 80ffafed92..169f32d7e6 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -44,7 +44,7 @@ Display.setVSyncEnabled(this.field_71474_y.field_74352_v); } -@@ -915,9 +922,11 @@ +@@ -916,9 +923,11 @@ if (!this.field_71454_w) { @@ -56,7 +56,7 @@ } GL11.glFlush(); -@@ -1495,6 +1504,8 @@ +@@ -1496,6 +1505,8 @@ --this.field_71467_ac; } @@ -65,7 +65,7 @@ this.field_71424_I.func_76320_a("gui"); if (!this.field_71445_n) -@@ -1645,6 +1656,7 @@ +@@ -1646,6 +1657,7 @@ this.field_71462_r.func_146274_d(); } } @@ -73,7 +73,7 @@ } if (this.field_71429_W > 0) -@@ -1786,6 +1798,7 @@ +@@ -1787,6 +1799,7 @@ } } } @@ -81,7 +81,7 @@ } } -@@ -1977,6 +1990,8 @@ +@@ -1978,6 +1991,8 @@ this.field_71453_ak.func_74428_b(); } @@ -90,7 +90,7 @@ this.field_71424_I.func_76319_b(); this.field_71423_H = func_71386_F(); } -@@ -2093,6 +2108,7 @@ +@@ -2094,6 +2109,7 @@ this.field_110448_aq.func_148529_f(); this.func_71351_a((ServerData)null); this.field_71455_al = false; diff --git a/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.java.patch b/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.java.patch new file mode 100644 index 0000000000..43b0b5b4b4 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/gui/GuiMultiplayer.java.patch @@ -0,0 +1,18 @@ +--- ../src-base/minecraft/net/minecraft/client/gui/GuiMultiplayer.java ++++ ../src-work/minecraft/net/minecraft/client/gui/GuiMultiplayer.java +@@ -2,6 +2,7 @@ + + import com.google.common.base.Splitter; + import com.google.common.collect.Lists; ++import cpw.mods.fml.client.FMLClientHandler; + import cpw.mods.fml.relauncher.Side; + import cpw.mods.fml.relauncher.SideOnly; + import java.util.List; +@@ -40,6 +41,7 @@ + public GuiMultiplayer(GuiScreen p_i1040_1_) + { + this.field_146798_g = p_i1040_1_; ++ FMLClientHandler.instance().setupServerList(); + } + + public void func_73866_w_() diff --git a/patches/minecraft/net/minecraft/client/gui/ServerListEntryNormal.java.patch b/patches/minecraft/net/minecraft/client/gui/ServerListEntryNormal.java.patch new file mode 100644 index 0000000000..e8ae64aa35 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/gui/ServerListEntryNormal.java.patch @@ -0,0 +1,31 @@ +--- ../src-base/minecraft/net/minecraft/client/gui/ServerListEntryNormal.java ++++ ../src-work/minecraft/net/minecraft/client/gui/ServerListEntryNormal.java +@@ -2,6 +2,7 @@ + + import com.google.common.base.Charsets; + import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import cpw.mods.fml.client.FMLClientHandler; + import cpw.mods.fml.relauncher.Side; + import cpw.mods.fml.relauncher.SideOnly; + import io.netty.buffer.ByteBuf; +@@ -83,7 +84,7 @@ + boolean flag2 = this.field_148301_e.field_82821_f < 4; + boolean flag3 = flag1 || flag2; + this.field_148300_d.field_71466_p.func_78276_b(this.field_148301_e.field_78847_a, p_148279_2_ + 32 + 3, p_148279_3_ + 1, 16777215); +- List list = this.field_148300_d.field_71466_p.func_78271_c(this.field_148301_e.field_78843_d, p_148279_4_ - 32 - 2); ++ List list = this.field_148300_d.field_71466_p.func_78271_c(FMLClientHandler.instance().fixDescription(this.field_148301_e.field_78843_d), p_148279_4_ - 32 - 2); + + for (int l1 = 0; l1 < Math.min(list.size(), 2); ++l1) + { +@@ -174,6 +175,11 @@ + int k2 = p_148279_7_ - p_148279_2_; + int l2 = p_148279_8_ - p_148279_3_; + ++ String tooltip = FMLClientHandler.instance().enhanceServerListEntry(this, this.field_148301_e, p_148279_2_, p_148279_4_, p_148279_3_, k2, l2); ++ if (tooltip != null) ++ { ++ this.field_148303_c.func_146793_a(tooltip); ++ } else + if (k2 >= p_148279_4_ - 15 && k2 <= p_148279_4_ - 5 && l2 >= 0 && l2 <= 8) + { + this.field_148303_c.func_146793_a(s1); diff --git a/patches/minecraft/net/minecraft/client/network/OldServerPinger.java.patch b/patches/minecraft/net/minecraft/client/network/OldServerPinger.java.patch new file mode 100644 index 0000000000..22e10b3f43 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/network/OldServerPinger.java.patch @@ -0,0 +1,18 @@ +--- ../src-base/minecraft/net/minecraft/client/network/OldServerPinger.java ++++ ../src-work/minecraft/net/minecraft/client/network/OldServerPinger.java +@@ -4,6 +4,7 @@ + import com.google.common.base.Splitter; + import com.google.common.collect.Iterables; + import com.mojang.authlib.GameProfile; ++import cpw.mods.fml.client.FMLClientHandler; + import cpw.mods.fml.relauncher.Side; + import cpw.mods.fml.relauncher.SideOnly; + import io.netty.bootstrap.Bootstrap; +@@ -148,6 +149,7 @@ + p_147224_1_.func_147407_a((String)null); + } + ++ FMLClientHandler.instance().bindServerListData(p_147224_1_, serverstatusresponse); + networkmanager.func_150725_a(new C01PacketPing(Minecraft.func_71386_F()), new GenericFutureListener[0]); + this.field_147403_d = true; + } diff --git a/patches/minecraft/net/minecraft/network/ServerStatusResponse.java.patch b/patches/minecraft/net/minecraft/network/ServerStatusResponse.java.patch new file mode 100644 index 0000000000..cc8f10c8ff --- /dev/null +++ b/patches/minecraft/net/minecraft/network/ServerStatusResponse.java.patch @@ -0,0 +1,27 @@ +--- ../src-base/minecraft/net/minecraft/network/ServerStatusResponse.java ++++ ../src-work/minecraft/net/minecraft/network/ServerStatusResponse.java +@@ -8,6 +8,8 @@ + import com.google.gson.JsonSerializationContext; + import com.google.gson.JsonSerializer; + import com.mojang.authlib.GameProfile; ++import cpw.mods.fml.client.FMLClientHandler; ++import cpw.mods.fml.common.network.internal.FMLNetworkHandler; + import java.lang.reflect.Type; + import net.minecraft.util.IChatComponent; + import net.minecraft.util.JsonUtils; +@@ -230,6 +232,7 @@ + serverstatusresponse.func_151320_a(JsonUtils.func_151200_h(jsonobject, "favicon")); + } + ++ FMLClientHandler.instance().captureAdditionalData(serverstatusresponse, jsonobject); + return serverstatusresponse; + } + +@@ -257,6 +260,7 @@ + jsonobject.addProperty("favicon", p_151313_1_.func_151316_d()); + } + ++ FMLNetworkHandler.enhanceStatusQuery(jsonobject); + return jsonobject; + } + diff --git a/src/main/java/cpw/mods/fml/client/ExtendedServerListData.java b/src/main/java/cpw/mods/fml/client/ExtendedServerListData.java new file mode 100644 index 0000000000..1253e4c768 --- /dev/null +++ b/src/main/java/cpw/mods/fml/client/ExtendedServerListData.java @@ -0,0 +1,16 @@ +package cpw.mods.fml.client; + +public class ExtendedServerListData { + public final String type; + public final boolean isCompatible; + public final int modCount; + public final boolean isBlocked; + + public ExtendedServerListData(String type, boolean isCompatible, int modCount, boolean isBlocked) + { + this.type = type; + this.isCompatible = isCompatible; + this.modCount = modCount; + this.isBlocked = isBlocked; + } +} diff --git a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java index 40366bcf52..1b1688a2ce 100644 --- a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java +++ b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java @@ -14,15 +14,19 @@ package cpw.mods.fml.client; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Logger; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityClientPlayerMP; +import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.GuiIngameMenu; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiSelectWorld; +import net.minecraft.client.gui.ServerListEntryNormal; +import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; @@ -34,7 +38,9 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.launchwrapper.Launch; import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; +import net.minecraft.network.ServerStatusResponse; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ResourceLocation; import org.apache.logging.log4j.Level; import com.google.common.base.Strings; import com.google.common.base.Throwables; @@ -43,6 +49,7 @@ import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; +import com.google.gson.JsonObject; import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.DummyModContainer; import cpw.mods.fml.common.DuplicateModsFoundException; @@ -124,6 +131,9 @@ public class FMLClientHandler implements IFMLSidedHandler private BiMap guiFactories; + private Map extraServerListData; + private Map serverDataTag; + /** * Called to start the whole game off * @@ -544,4 +554,97 @@ public class FMLClientHandler implements IFMLSidedHandler { return guiFactories.get(selectedMod); } + + + public void setupServerList() + { + extraServerListData = Collections.synchronizedMap(Maps.newHashMap()); + serverDataTag = Collections.synchronizedMap(Maps.newHashMap()); + } + + public void captureAdditionalData(ServerStatusResponse serverstatusresponse, JsonObject jsonobject) + { + if (jsonobject.has("modinfo")) + { + JsonObject fmlData = jsonobject.get("modinfo").getAsJsonObject(); + extraServerListData.put(serverstatusresponse, fmlData); + } + } + public void bindServerListData(ServerData data, ServerStatusResponse originalResponse) + { + if (extraServerListData.containsKey(originalResponse)) + { + JsonObject jsonData = extraServerListData.get(originalResponse); + String type = jsonData.get("type").getAsString(); + int modCount = jsonData.get("modList").getAsJsonArray().size(); + boolean moddedClientAllowed = jsonData.has("clientModsAllowed") ? jsonData.get("clientModsAllowed").getAsBoolean() : true; + serverDataTag.put(data, new ExtendedServerListData(type, true, modCount, !moddedClientAllowed)); + } + else + { + String serverDescription = data.field_78843_d; + boolean moddedClientAllowed = true; + if (!Strings.isNullOrEmpty(serverDescription)) + { + moddedClientAllowed = !serverDescription.endsWith(":NOFML§r"); + } + serverDataTag.put(data, new ExtendedServerListData("VANILLA", false, -1, !moddedClientAllowed)); + } + } + + private static final ResourceLocation iconSheet = new ResourceLocation("fml:textures/gui/icons.png"); + + public String enhanceServerListEntry(ServerListEntryNormal serverListEntry, ServerData serverEntry, int x, int width, int y, int relativeMouseX, int relativeMouseY) + { + String tooltip; + int idx; + boolean blocked = false; + if (serverDataTag.containsKey(serverEntry)) + { + ExtendedServerListData extendedData = serverDataTag.get(serverEntry); + if ("FML".equals(extendedData.type) && extendedData.isCompatible) + { + idx = 0; + tooltip = String.format("Compatible FML modded server\n%d mods present", extendedData.modCount); + } + else if ("FML".equals(extendedData.type) && !extendedData.isCompatible) + { + idx = 16; + tooltip = String.format("Incompatible FML modded server\n%d mods present", extendedData.modCount); + } + else if ("BUKKIT".equals(extendedData.type)) + { + idx = 32; + tooltip = String.format("Bukkit modded server"); + } + else if ("VANILLA".equals(extendedData.type)) + { + idx = 48; + tooltip = String.format("Vanilla server"); + } + else + { + idx = 64; + tooltip = String.format("Unknown server data"); + } + blocked = extendedData.isBlocked; + } + else + { + return null; + } + this.client.func_110434_K().func_110577_a(iconSheet); + Gui.func_146110_a(x + width - 18, y + 10, 0, (float)idx, 16, 16, 256.0f, 256.0f); + if (blocked) + { + Gui.func_146110_a(x + width - 18, y + 10, 0, 80, 16, 16, 256.0f, 256.0f); + } + + return relativeMouseX > width - 15 && relativeMouseX < width && relativeMouseY > 10 && relativeMouseY < 26 ? tooltip : null; + } + + public String fixDescription(String description) + { + return description.endsWith(":NOFML§r") ? description.substring(0, description.length() - 8)+"§r" : description; + } } diff --git a/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java b/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java index cf721e3def..652396fee4 100644 --- a/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java +++ b/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java @@ -20,10 +20,12 @@ public class FMLNetworkEvent extends Event { } public static class ClientConnectedToServerEvent extends FMLNetworkEvent { public final boolean isLocal; - public ClientConnectedToServerEvent(NetworkManager manager) + public final String connectionType; + public ClientConnectedToServerEvent(NetworkManager manager, String connectionType) { super((INetHandlerPlayClient) manager.func_150729_e(), INetHandlerPlayClient.class, manager); - isLocal = manager.func_150731_c(); + this.isLocal = manager.func_150731_c(); + this.connectionType = connectionType; } } @@ -32,7 +34,7 @@ public class FMLNetworkEvent extends Event { public ServerConnectionFromClientEvent(NetworkManager manager) { super((INetHandlerPlayServer) manager.func_150729_e(), INetHandlerPlayServer.class, manager); - isLocal = manager.func_150731_c(); + this.isLocal = manager.func_150731_c(); } } public static class ServerDisconnectionFromClientEvent extends FMLNetworkEvent { diff --git a/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java b/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java index 30940037ad..bd3df960b5 100644 --- a/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java +++ b/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java @@ -37,8 +37,17 @@ enum FMLHandshakeClientState implements IHandshakeState @Override public FMLHandshakeClientState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { - FMLLog.info("Server protocol version %x", ((FMLHandshakeMessage.ServerHello)msg).protocolVersion()); + // write our custom packet registration, always ctx.writeAndFlush(FMLHandshakeMessage.makeCustomChannelRegistration(NetworkRegistry.INSTANCE.channelNamesFor(Side.CLIENT))); + if (msg == null) + { + NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); + dispatcher.abortClientHandshake("VANILLA"); + // VANILLA login + return DONE; + } + + FMLLog.info("Server protocol version %x", ((FMLHandshakeMessage.ServerHello)msg).protocolVersion()); ctx.writeAndFlush(new FMLHandshakeMessage.ClientHello()); ctx.writeAndFlush(new FMLHandshakeMessage.ModList(Loader.instance().getActiveModList())); return WAITINGSERVERDATA; diff --git a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index 7e00a9e293..07c2cd8e03 100644 --- a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -12,6 +12,7 @@ import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.ScheduledFuture; import java.net.SocketAddress; import java.util.List; +import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import net.minecraft.entity.player.EntityPlayerMP; @@ -21,6 +22,7 @@ import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.client.C17PacketCustomPayload; +import net.minecraft.network.play.server.S01PacketJoinGame; import net.minecraft.network.play.server.S3FPacketCustomPayload; import net.minecraft.network.play.server.S40PacketDisconnect; import net.minecraft.server.management.ServerConfigurationManager; @@ -69,7 +71,6 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple private final ServerConfigurationManager scm; private EntityPlayerMP player; private ConnectionState state; - @SuppressWarnings("unused") private ConnectionType connectionType; private final Side side; private final EmbeddedChannel handshakeChannel; @@ -151,19 +152,19 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple this.state = ConnectionState.AWAITING_HANDSHAKE; } - private void completeClientSideConnection() + private void completeClientSideConnection(ConnectionType type) { - FMLLog.info("[%s] Client side modded connection established", Thread.currentThread().getName()); + this.connectionType = type; + FMLLog.info("[%s] Client side %s connection established", Thread.currentThread().getName(), this.connectionType.name().toLowerCase(Locale.ENGLISH)); this.state = ConnectionState.CONNECTED; - this.connectionType = ConnectionType.MODDED; - FMLCommonHandler.instance().bus().post(new FMLNetworkEvent.ClientConnectedToServerEvent(manager)); + FMLCommonHandler.instance().bus().post(new FMLNetworkEvent.ClientConnectedToServerEvent(manager, this.connectionType.name())); } - private void completeServerSideConnection() + private void completeServerSideConnection(ConnectionType type) { - FMLLog.info("[%s] Server side modded connection established", Thread.currentThread().getName()); + this.connectionType = type; + FMLLog.info("[%s] Server side %s connection established", Thread.currentThread().getName(), this.connectionType.name().toLowerCase(Locale.ENGLISH)); this.state = ConnectionState.CONNECTED; - this.connectionType = ConnectionType.MODDED; FMLCommonHandler.instance().bus().post(new FMLNetworkEvent.ServerConnectionFromClientEvent(manager)); scm.func_72355_a(manager, player, serverHandler); } @@ -181,7 +182,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple } else if (state != ConnectionState.CONNECTED && state != ConnectionState.HANDSHAKECOMPLETE) { - FMLLog.info("Unexpected packet during modded negotiation - assuming vanilla or keepalives : %s", msg.getClass().getName()); + handled = handleVanilla(msg); } if (!handled) { @@ -189,6 +190,19 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple } } + private boolean handleVanilla(Packet msg) + { + if (state == ConnectionState.AWAITING_HANDSHAKE && msg instanceof S01PacketJoinGame) + { + handshakeChannel.pipeline().fireUserEventTriggered(msg); + } + else + { + FMLLog.info("Unexpected packet during modded negotiation - assuming vanilla or keepalives : %s", msg.getClass().getName()); + } + return false; + } + public INetHandler getNetHandler() { return netHandler; @@ -399,11 +413,11 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple } if (side == Side.CLIENT) { - completeClientSideConnection(); + completeClientSideConnection(ConnectionType.MODDED); } else { - completeServerSideConnection(); + completeServerSideConnection(ConnectionType.MODDED); } } @@ -411,4 +425,9 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple { state = ConnectionState.HANDSHAKECOMPLETE; } + + public void abortClientHandshake(String type) + { + completeClientSideConnection(ConnectionType.valueOf(type)); + } } diff --git a/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java b/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java index 3f291671d6..39515032b8 100644 --- a/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java +++ b/src/main/java/cpw/mods/fml/common/network/internal/FMLNetworkHandler.java @@ -29,9 +29,12 @@ import net.minecraft.server.management.ServerConfigurationManager; import net.minecraft.world.World; import org.apache.logging.log4j.core.helpers.Integers; import com.google.common.collect.Lists; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLContainer; import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.network.FMLEmbeddedChannel; import cpw.mods.fml.common.network.FMLOutboundHandler; @@ -176,4 +179,20 @@ public class FMLNetworkHandler return list; } + + public static void enhanceStatusQuery(JsonObject jsonobject) + { + JsonObject fmlData = new JsonObject(); + fmlData.addProperty("type", "FML"); + JsonArray modList = new JsonArray(); + for (ModContainer mc : Loader.instance().getActiveModList()) + { + JsonObject modData = new JsonObject(); + modData.addProperty("modid", mc.getModId()); + modData.addProperty("version", mc.getVersion()); + modList.add(modData); + } + fmlData.add("modList", modList); + jsonobject.add("modinfo", fmlData); + } } diff --git a/src/main/resources/assets/fml/textures/gui/icons.png b/src/main/resources/assets/fml/textures/gui/icons.png new file mode 100644 index 0000000000..20bb91e9d6 Binary files /dev/null and b/src/main/resources/assets/fml/textures/gui/icons.png differ