From 5a6275f0e1dbdb2ba2f7a84b4da443c8d2a0eb14 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 26 Aug 2012 22:13:43 -0400 Subject: [PATCH] Fix up network negotiation - now it will disconnect with a nice error screen if there are missing mods on the client vs server --- .../cpw/mods/fml/client/FMLClientHandler.java | 7 ++ .../cpw/mods/fml/client/GuiModsMissing.java | 5 ++ .../fml/client/GuiModsMissingForServer.java | 52 +++++++++++++ .../cpw/mods/fml/common/IFMLSidedHandler.java | 3 + .../fml/common/network/FMLNetworkHandler.java | 10 +++ .../common/network/ModListRequestPacket.java | 15 +++- .../common/network/ModListResponsePacket.java | 9 ++- .../fml/common/network/ModMissingPacket.java | 77 ++++++++++++++++++- .../cpw/mods/fml/server/FMLServerHandler.java | 6 ++ .../.launches/FML-Client.launch | 3 +- .../.launches/FML-Server.launch | 7 ++ 11 files changed, 185 insertions(+), 9 deletions(-) create mode 100644 fml/client/cpw/mods/fml/client/GuiModsMissingForServer.java diff --git a/fml/client/cpw/mods/fml/client/FMLClientHandler.java b/fml/client/cpw/mods/fml/client/FMLClientHandler.java index 42e170e5d0..a612ffacf1 100644 --- a/fml/client/cpw/mods/fml/client/FMLClientHandler.java +++ b/fml/client/cpw/mods/fml/client/FMLClientHandler.java @@ -53,6 +53,7 @@ import cpw.mods.fml.common.ObfuscationReflectionHelper; import cpw.mods.fml.common.Side; import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket; import cpw.mods.fml.common.network.EntitySpawnPacket; +import cpw.mods.fml.common.network.ModMissingPacket; import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration; import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; import cpw.mods.fml.common.registry.IThrowableEntity; @@ -373,4 +374,10 @@ public class FMLClientHandler implements IFMLSidedHandler { client.field_71439_g.field_71174_a.func_72552_c(packet); } + + @Override + public void displayMissingMods(ModMissingPacket modMissingPacket) + { + client.func_71373_a(new GuiModsMissingForServer(modMissingPacket)); + } } diff --git a/fml/client/cpw/mods/fml/client/GuiModsMissing.java b/fml/client/cpw/mods/fml/client/GuiModsMissing.java index 4937e7ba38..5398cf2821 100644 --- a/fml/client/cpw/mods/fml/client/GuiModsMissing.java +++ b/fml/client/cpw/mods/fml/client/GuiModsMissing.java @@ -14,6 +14,11 @@ public class GuiModsMissing extends GuiErrorScreen this.modsMissing = modsMissing; } + @Override + public void func_73866_w_() + { + super.func_73866_w_(); + } @Override public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_) { diff --git a/fml/client/cpw/mods/fml/client/GuiModsMissingForServer.java b/fml/client/cpw/mods/fml/client/GuiModsMissingForServer.java new file mode 100644 index 0000000000..67f7398700 --- /dev/null +++ b/fml/client/cpw/mods/fml/client/GuiModsMissingForServer.java @@ -0,0 +1,52 @@ +package cpw.mods.fml.client; + +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiSmallButton; +import net.minecraft.src.StringTranslate; +import cpw.mods.fml.common.network.ModMissingPacket; +import cpw.mods.fml.common.versioning.ArtifactVersion; + +public class GuiModsMissingForServer extends GuiScreen +{ + private ModMissingPacket modsMissing; + + public GuiModsMissingForServer(ModMissingPacket modsMissing) + { + this.modsMissing = modsMissing; + } + + @Override + public void func_73866_w_() + { + StringTranslate translations = StringTranslate.func_74808_a(); + this.field_73887_h.add(new GuiSmallButton(1, this.field_73880_f / 2 - 75, this.field_73881_g - 38, translations.func_74805_b("gui.done"))); + } + + @Override + protected void func_73875_a(GuiButton p_73875_1_) + { + if (p_73875_1_.field_73742_g && p_73875_1_.field_73741_f == 1) + { + FMLClientHandler.instance().getClient().func_71373_a(null); + } + } + @Override + public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_) + { + this.func_73873_v_(); + int offset = 85 - modsMissing.getModList().size() * 10; + this.func_73732_a(this.field_73886_k, "Forge Mod Loader could not connect to this server", this.field_73880_f / 2, offset, 0xFFFFFF); + offset += 10; + this.func_73732_a(this.field_73886_k, "The mods and versions listed below could not be found", this.field_73880_f / 2, offset, 0xFFFFFF); + offset += 10; + this.func_73732_a(this.field_73886_k, "They are required to play on this server", this.field_73880_f / 2, offset, 0xFFFFFF); + offset += 5; + for (ArtifactVersion v : modsMissing.getModList()) + { + offset += 10; + this.func_73732_a(this.field_73886_k, String.format("%s : %s", v.getLabel(), v.getRangeString()), this.field_73880_f / 2, offset, 0xEEEEEE); + } + super.func_73863_a(p_73863_1_, p_73863_2_, p_73863_3_); + } +} diff --git a/fml/common/cpw/mods/fml/common/IFMLSidedHandler.java b/fml/common/cpw/mods/fml/common/IFMLSidedHandler.java index f25636e110..a849a18663 100644 --- a/fml/common/cpw/mods/fml/common/IFMLSidedHandler.java +++ b/fml/common/cpw/mods/fml/common/IFMLSidedHandler.java @@ -7,6 +7,7 @@ import net.minecraft.src.Entity; import net.minecraft.src.Packet; import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket; import cpw.mods.fml.common.network.EntitySpawnPacket; +import cpw.mods.fml.common.network.ModMissingPacket; import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration; public interface IFMLSidedHandler @@ -30,4 +31,6 @@ public interface IFMLSidedHandler MinecraftServer getServer(); void sendPacket(Packet packet); + + void displayMissingMods(ModMissingPacket modMissingPacket); } diff --git a/fml/common/cpw/mods/fml/common/network/FMLNetworkHandler.java b/fml/common/cpw/mods/fml/common/network/FMLNetworkHandler.java index 205df801cd..0e4995c06e 100644 --- a/fml/common/cpw/mods/fml/common/network/FMLNetworkHandler.java +++ b/fml/common/cpw/mods/fml/common/network/FMLNetworkHandler.java @@ -138,6 +138,11 @@ public class FMLNetworkHandler netLoginHandler.completeConnection(null); loginStates.remove(netLoginHandler); } + else if (loginStates.get(netLoginHandler) == 3) + { + netLoginHandler.completeConnection("The server requires mods that are missing on your client"); + loginStates.remove(netLoginHandler); + } // We have to abort this connection - there was a negotiation problem // (most likely missing mods) else @@ -181,6 +186,11 @@ public class FMLNetworkHandler } } + static void setHandlerState(NetLoginHandler handler, int state) + { + instance().loginStates.put(handler, state); + } + public static FMLNetworkHandler instance() { return INSTANCE; diff --git a/fml/common/cpw/mods/fml/common/network/ModListRequestPacket.java b/fml/common/cpw/mods/fml/common/network/ModListRequestPacket.java index 01fdfeb506..66a34ae3b1 100644 --- a/fml/common/cpw/mods/fml/common/network/ModListRequestPacket.java +++ b/fml/common/cpw/mods/fml/common/network/ModListRequestPacket.java @@ -5,6 +5,7 @@ import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_RESPONSE; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import net.minecraft.src.NetHandler; @@ -17,6 +18,7 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; +import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; @@ -83,7 +85,18 @@ public class ModListRequestPacket extends FMLPacket if (indexedModList.size()>0) { - // TODO : handle client present but server absent mods + for (Entry e : indexedModList.entrySet()) + { + if (e.getValue().isNetworkMod()) + { + NetworkModHandler missingHandler = FMLNetworkHandler.instance().findNetworkModHandler(e.getValue()); + if (missingHandler.requiresServerSide()) + { + // TODO : what should we do if a mod is marked "serverSideRequired"? Stop the connection? + FMLLog.warning("The mod %s was not found on the server you connected to, but requested that the server side be present", e.getKey()); + } + } + } } Packet250CustomPayload pkt = new Packet250CustomPayload(); diff --git a/fml/common/cpw/mods/fml/common/network/ModListResponsePacket.java b/fml/common/cpw/mods/fml/common/network/ModListResponsePacket.java index 3925631b74..2d7d431b9f 100644 --- a/fml/common/cpw/mods/fml/common/network/ModListResponsePacket.java +++ b/fml/common/cpw/mods/fml/common/network/ModListResponsePacket.java @@ -7,6 +7,7 @@ import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_MISSING; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.logging.Logger; import net.minecraft.src.NetHandler; import net.minecraft.src.NetLoginHandler; @@ -108,12 +109,16 @@ public class ModListResponsePacket extends FMLPacket if (missingClientMods.size()>0 || versionIncorrectMods.size() > 0) { pkt.field_73629_c = FMLPacket.makePacket(MOD_MISSING, missingClientMods, versionIncorrectMods); - FMLLog.fine("User %s connection failed: missing %s, bad versions %s", userName, missingClientMods, versionIncorrectMods); + Logger.getLogger("Minecraft").info(String.format("User %s connection failed: missing %s, bad versions %s", userName, missingClientMods, versionIncorrectMods)); + FMLLog.info("User %s connection failed: missing %s, bad versions %s", userName, missingClientMods, versionIncorrectMods); + // Mark this as bad + FMLNetworkHandler.setHandlerState((NetLoginHandler) netHandler, 3); } else { pkt.field_73629_c = FMLPacket.makePacket(MOD_IDENTIFIERS, netHandler); - FMLLog.fine("User %s connecting with mods %s", userName, modVersions.keySet()); + Logger.getLogger("Minecraft").info(String.format("User %s connecting with mods %s", userName, modVersions.keySet())); + FMLLog.info("User %s connecting with mods %s", userName, modVersions.keySet()); } pkt.field_73628_b = pkt.field_73629_c.length; diff --git a/fml/common/cpw/mods/fml/common/network/ModMissingPacket.java b/fml/common/cpw/mods/fml/common/network/ModMissingPacket.java index a180495a09..d592502d77 100644 --- a/fml/common/cpw/mods/fml/common/network/ModMissingPacket.java +++ b/fml/common/cpw/mods/fml/common/network/ModMissingPacket.java @@ -2,12 +2,29 @@ package cpw.mods.fml.common.network; import java.util.List; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Lists; +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.versioning.ArtifactVersion; +import cpw.mods.fml.common.versioning.DefaultArtifactVersion; +import cpw.mods.fml.common.versioning.VersionRange; + import net.minecraft.src.NetHandler; import net.minecraft.src.NetworkManager; public class ModMissingPacket extends FMLPacket { + private List missing; + private List badVersion; + public ModMissingPacket() { super(Type.MOD_MISSING); @@ -16,24 +33,76 @@ public class ModMissingPacket extends FMLPacket @Override public byte[] generatePacket(Object... data) { - // TODO + ByteArrayDataOutput dat = ByteStreams.newDataOutput(); + List missing = (List) data[0]; List badVersion = (List) data[1]; - return new byte[0]; + dat.writeInt(missing.size()); + for (String missed : missing) + { + ModContainer mc = Loader.instance().getIndexedModList().get(missed); + dat.writeUTF(missed); + dat.writeUTF(mc.getVersion()); + } + dat.writeInt(badVersion.size()); + for (String bad : badVersion) + { + ModContainer mc = Loader.instance().getIndexedModList().get(bad); + dat.writeUTF(bad); + dat.writeUTF(mc.getVersion()); + } + return dat.toByteArray(); } + private static class ModData + { + String modId; + String modVersion; + } @Override public FMLPacket consumePacket(byte[] data) { - // TODO + ByteArrayDataInput dat = ByteStreams.newDataInput(data); + int missingLen = dat.readInt(); + missing = Lists.newArrayListWithCapacity(missingLen); + for (int i = 0; i < missingLen; i++) + { + ModData md = new ModData(); + md.modId = dat.readUTF(); + md.modVersion = dat.readUTF(); + missing.add(md); + } + int badVerLength = dat.readInt(); + badVersion = Lists.newArrayListWithCapacity(badVerLength); + for (int i = 0; i < badVerLength; i++) + { + ModData md = new ModData(); + md.modId = dat.readUTF(); + md.modVersion = dat.readUTF(); + badVersion.add(md); + } return this; } @Override public void execute(NetworkManager network, FMLNetworkHandler handler, NetHandler netHandler, String userName) { - // TODO + FMLCommonHandler.instance().getSidedDelegate().displayMissingMods(this); + } + + public List getModList() + { + Builder builder = ImmutableList.builder(); + for (ModData md : missing) + { + builder.add(new DefaultArtifactVersion(md.modId, VersionRange.createFromVersion(md.modVersion, null))); + } + for (ModData md : badVersion) + { + builder.add(new DefaultArtifactVersion(md.modId, VersionRange.createFromVersion(md.modVersion, null))); + } + return builder.build(); } } diff --git a/fml/common/cpw/mods/fml/server/FMLServerHandler.java b/fml/common/cpw/mods/fml/server/FMLServerHandler.java index 520bdb7b14..c5b0a3a2da 100644 --- a/fml/common/cpw/mods/fml/server/FMLServerHandler.java +++ b/fml/common/cpw/mods/fml/server/FMLServerHandler.java @@ -25,6 +25,7 @@ import cpw.mods.fml.common.ObfuscationReflectionHelper; import cpw.mods.fml.common.Side; import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket; import cpw.mods.fml.common.network.EntitySpawnPacket; +import cpw.mods.fml.common.network.ModMissingPacket; import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration; import cpw.mods.fml.common.registry.LanguageRegistry; @@ -150,4 +151,9 @@ public class FMLServerHandler implements IFMLSidedHandler { throw new RuntimeException("You cannot send a bare packet without a target on the server!"); } + @Override + public void displayMissingMods(ModMissingPacket modMissingPacket) + { + // NOOP on server + } } diff --git a/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Client.launch b/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Client.launch index b768180055..5b742ab122 100644 --- a/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Client.launch +++ b/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Client.launch @@ -15,9 +15,8 @@ - - + diff --git a/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Server.launch b/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Server.launch index 9667c42820..8b2cb94d11 100644 --- a/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Server.launch +++ b/fml/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/FML-Server.launch @@ -6,6 +6,13 @@ + + + + + + +