Fix up network negotiation - now it will disconnect with a nice

error screen if there are missing mods on the client vs server
This commit is contained in:
Christian 2012-08-26 22:13:43 -04:00
parent b32dea398b
commit 5a6275f0e1
11 changed files with 185 additions and 9 deletions

View File

@ -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));
}
}

View File

@ -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_)
{

View File

@ -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_);
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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<String, ModContainer> 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();

View File

@ -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;

View File

@ -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<ModData> missing;
private List<ModData> 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<String> missing = (List<String>) data[0];
List<String> badVersion = (List<String>) 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<ArtifactVersion> getModList()
{
Builder<ArtifactVersion> builder = ImmutableList.<ArtifactVersion>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();
}
}

View File

@ -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
}
}

View File

@ -15,9 +15,8 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;FML-Client&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;FML-Client&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;simpletestmod&quot; type=&quot;1&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;FML-Client&quot; type=&quot;1&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;FML-MockMod&quot; type=&quot;1&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;simpletestmod&quot; type=&quot;1&quot;/&gt;&#10;"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="Start"/>

View File

@ -6,6 +6,13 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;FML-Client&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;FML-Client&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;FML-MockMod&quot; type=&quot;1&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;simpletestmod&quot; type=&quot;1&quot;/&gt;&#10;"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="net.minecraft.server.MinecraftServer"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="FML-Client"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:FML-Client/jars}"/>