Expanded the Mod check to test for missing mods and display a GUI screen for the client if it is missing any.

The client now downloads NetworkMod ID's from the server upon connecting.
This commit is contained in:
LexManos 2012-02-20 23:54:11 -08:00
parent 70fbe4f403
commit a6f93ed528
6 changed files with 310 additions and 4 deletions

View File

@ -0,0 +1,39 @@
package net.minecraft.src.forge;
import net.minecraft.src.*;
import net.minecraft.src.forge.packets.PacketMissingMods;
public class GuiMissingMods extends GuiScreen
{
PacketMissingMods packet;
public GuiMissingMods(PacketMissingMods pkt)
{
packet = pkt;
}
public void initGui()
{
controlList.clear();
controlList.add(new GuiButton(0, width / 2 - 100, height - 60, StringTranslate.getInstance().translateKey("gui.toMenu")));
}
protected void actionPerformed(GuiButton guibutton)
{
if (guibutton.id == 0)
{
mc.displayGuiScreen(new GuiMainMenu());
}
}
public void drawScreen(int i, int j, float f)
{
drawDefaultBackground();
drawCenteredString(fontRenderer, "The server requires the following mods:", width / 2, height / 2 - 50, 0xffffff);
int y = 0;
for (String mod : packet.Mods)
{
drawCenteredString(fontRenderer, mod, width / 2, (height / 2 - 10) + y++ * 10, 0xffffff);
}
super.drawScreen(i, j, f);
}
}

View File

@ -33,6 +33,26 @@ public class PacketHandlerClient implements IPacketHandler
pkt.readData(data);
onEntitySpawnPacket((PacketEntitySpawn)pkt, data, ModLoader.getMinecraftInstance().theWorld);
break;
case ForgePacket.MODLIST:
/*
pkt = new PacketModList(false);
pkt.readData(data);
*/
onModListCheck(net);
break;
case ForgePacket.MOD_MISSING:
pkt = new PacketMissingMods(false);
pkt.readData(data);
onMissingMods((PacketMissingMods)pkt, net);
break;
case ForgePacket.MOD_IDS:
pkt = new PacketModIDs();
pkt.readData(data);
onModIDs((PacketModIDs)pkt);
break;
}
}
catch(IOException e)
@ -125,4 +145,51 @@ public class PacketHandlerClient implements IPacketHandler
}
net.addToSendQueue(pkt.getPacket());
}
/**
* Received when the client does not have a mod installed that the server requires them to.
* Displays a informative screen, and disconnects from the server.
*
* @param pkt The missing mods packet
* @param net The network handler
*/
private void onMissingMods(PacketMissingMods pkt, NetClientHandler net)
{
net.disconnect();
Minecraft mc = ModLoader.getMinecraftInstance();
mc.changeWorld1(null);
mc.displayGuiScreen(new GuiMissingMods(pkt));
}
/**
* Sets up the list of ID to mod mappings.
* TODO; Make it display an error, and prompt if the user wishes to continue anyways
* if it detects that the server does not have a corresponding mod to one it has installed.
*
* @param pkt The mod id packet
*/
private void onModIDs(PacketModIDs pkt)
{
ForgeHooks.networkMods.clear();
NetworkMod[] mods = MinecraftForge.getNetworkMods();
for (NetworkMod mod : mods)
{
for (Entry<Integer, String> entry : pkt.Mods.entrySet())
{
if (mod.toString().equals(entry.getValue()))
{
ForgeHooks.networkMods.put(entry.getKey(), mod);
}
}
}
ArrayList<NetworkMod> missing = new ArrayList<NetworkMod>();
for (NetworkMod mod : mods)
{
if (MinecraftForge.getModID(mod) == -1 && mod.serverSideRequired())
{
missing.add(mod);
}
}
//TODO: Display error/confirmation screen
}
}

View File

@ -0,0 +1,21 @@
package net.minecraft.src.forge.packets;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PacketMissingMods extends PacketModList
{
public PacketMissingMods(boolean server)
{
super(!server);
}
@Override
public int getID()
{
return ForgePacket.MOD_MISSING;
}
}

View File

@ -0,0 +1,41 @@
package net.minecraft.src.forge.packets;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map.Entry;
public class PacketModIDs extends ForgePacket
{
public Hashtable<Integer, String> Mods = new Hashtable<Integer, String>();
public int Length;
@Override
public void writeData(DataOutputStream data) throws IOException
{
data.writeInt(Mods.size());
for (Entry<Integer, String> entry : Mods.entrySet())
{
data.writeInt(entry.getKey());
data.writeUTF(entry.getValue());
}
}
@Override
public void readData(DataInputStream data) throws IOException
{
Length = data.readInt();
for(int x = 0; x < Length; x++)
{
Mods.put(data.readInt(), data.readUTF());
}
}
@Override
public int getID()
{
return ForgePacket.MOD_IDS;
}
}

View File

@ -2,8 +2,8 @@ package net.minecraft.src.forge;
import java.util.Map;
import net.minecraft.src.Entity;
import net.minecraft.src.EntityTracker;
import net.minecraft.src.*;
import net.minecraft.src.forge.packets.PacketModList;
public class ForgeHooksServer
{
@ -26,6 +26,12 @@ public class ForgeHooksServer
return false;
}
public static void sendModListRequest(NetworkManager net)
{
PacketModList pkt = new PacketModList(true);
((NetServerHandler)net.getNetHandler()).sendPacket(pkt.getPacket());
}
private static boolean hasInit = false;
public static void init()

View File

@ -1,11 +1,143 @@
package net.minecraft.src.forge;
import net.minecraft.src.NetworkManager;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import net.minecraft.server.MinecraftServer;
import net.minecraft.src.*;
import net.minecraft.src.forge.packets.*;
public class PacketHandlerServer implements IPacketHandler
{
@Override
public void onPacketData(NetworkManager network, String channel, byte[] data)
public void onPacketData(NetworkManager network, String channel, byte[] bytes)
{
NetServerHandler net = (NetServerHandler)network.getNetHandler();
DataInputStream data = new DataInputStream(new ByteArrayInputStream(bytes));
ForgePacket pkt = null;
try
{
int packetID = data.read();
switch(packetID)
{
case ForgePacket.MODLIST:
pkt = new PacketModList(true);
pkt.readData(data);
onModListResponse(net, (PacketModList)pkt);
break;
}
}
catch(IOException e)
{
ModLoader.getLogger().log(Level.SEVERE, "Exception in PacketHandlerServer.onPacketData", e);
e.printStackTrace();
}
}
private void onModListResponse(NetServerHandler net, PacketModList pkt) throws IOException
{
if (pkt.Length < 0)
{
net.kickPlayer("Invalid mod list response, Size: " + pkt.Length);
return;
}
if (pkt.Mods.length == 0)
{
ModLoader.getLogger().log(Level.INFO, net.getUsername() + " joined with no mods");
}
else
{
ModLoader.getLogger().log(Level.INFO, net.getUsername() + " joined with: " + Arrays.toString(pkt.Mods).replaceAll("mod_", ""));
}
//TODO: Write a 'banned mods' system and do the checks here
NetworkMod[] serverMods = MinecraftForge.getNetworkMods();
ArrayList<NetworkMod> missing = new ArrayList<NetworkMod>();
for (NetworkMod mod : serverMods)
{
if (!mod.clientSideRequired())
{
continue;
}
boolean found = true;
for (String modName : pkt.Mods)
{
if (modName.equals(mod.toString()))
{
found = false;
break;
}
}
if (!found)
{
missing.add(mod);
}
}
if (missing.size() > 0)
{
doMissingMods(net, missing);
}
else
{
sendModIDs(net, serverMods);
}
}
/**
* Sends the user a list of mods they are missing and then disconnects them
* @param net The network handler
*/
private void doMissingMods(NetServerHandler net, ArrayList<NetworkMod> list)
{
PacketMissingMods pkt = new PacketMissingMods(true);
pkt.Mods = new String[list.size()];
int x = 0;
for(NetworkMod mod : list)
{
pkt.Mods[x++] = mod.toString();
}
net.sendPacket(pkt.getPacket());
disconnectUser(net);
}
/**
* Sends a list of mod id mappings to the client.
* Only mod ID's are sent, not item or blocks.
*
* @param net The network handler
* @param list A list of network mods
*/
private void sendModIDs(NetServerHandler net, NetworkMod[] list)
{
PacketModIDs pkt = new PacketModIDs();
for (NetworkMod mod : list)
{
pkt.Mods.put(MinecraftForge.getModID(mod), mod.toString());
}
net.sendPacket(pkt.getPacket());
}
/**
* Disconnects the player just like kicking them, just without the kick message.
* @param net The network handler
*/
private void disconnectUser(NetServerHandler net)
{
MinecraftServer mc = ModLoader.getMinecraftServerInstance();
net.getPlayerEntity().func_30002_A();
net.netManager.serverShutdown();
mc.configManager.sendPacketToAllPlayers(new Packet3Chat("\247e" + net.getUsername() + " left the game."));
mc.configManager.playerLoggedOut(net.getPlayerEntity());
net.connectionClosed = true;
}
}