From a6f93ed5281f3dee7511c8494bc891c8506e868f Mon Sep 17 00:00:00 2001 From: LexManos Date: Mon, 20 Feb 2012 23:54:11 -0800 Subject: [PATCH] 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. --- .../minecraft/src/forge/GuiMissingMods.java | 39 +++++ .../src/forge/PacketHandlerClient.java | 67 +++++++++ .../src/forge/packets/PacketMissingMods.java | 21 +++ .../src/forge/packets/PacketModIDs.java | 41 ++++++ .../minecraft/src/forge/ForgeHooksServer.java | 10 +- .../src/forge/PacketHandlerServer.java | 136 +++++++++++++++++- 6 files changed, 310 insertions(+), 4 deletions(-) create mode 100644 forge/forge_client/src/net/minecraft/src/forge/GuiMissingMods.java create mode 100644 forge/forge_common/net/minecraft/src/forge/packets/PacketMissingMods.java create mode 100644 forge/forge_common/net/minecraft/src/forge/packets/PacketModIDs.java diff --git a/forge/forge_client/src/net/minecraft/src/forge/GuiMissingMods.java b/forge/forge_client/src/net/minecraft/src/forge/GuiMissingMods.java new file mode 100644 index 000000000..f015eba9e --- /dev/null +++ b/forge/forge_client/src/net/minecraft/src/forge/GuiMissingMods.java @@ -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); + } +} diff --git a/forge/forge_client/src/net/minecraft/src/forge/PacketHandlerClient.java b/forge/forge_client/src/net/minecraft/src/forge/PacketHandlerClient.java index 57a8093ac..9052238ae 100644 --- a/forge/forge_client/src/net/minecraft/src/forge/PacketHandlerClient.java +++ b/forge/forge_client/src/net/minecraft/src/forge/PacketHandlerClient.java @@ -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 entry : pkt.Mods.entrySet()) + { + if (mod.toString().equals(entry.getValue())) + { + ForgeHooks.networkMods.put(entry.getKey(), mod); + } + } + } + ArrayList missing = new ArrayList(); + for (NetworkMod mod : mods) + { + if (MinecraftForge.getModID(mod) == -1 && mod.serverSideRequired()) + { + missing.add(mod); + } + } + //TODO: Display error/confirmation screen + } } diff --git a/forge/forge_common/net/minecraft/src/forge/packets/PacketMissingMods.java b/forge/forge_common/net/minecraft/src/forge/packets/PacketMissingMods.java new file mode 100644 index 000000000..c36f1cee6 --- /dev/null +++ b/forge/forge_common/net/minecraft/src/forge/packets/PacketMissingMods.java @@ -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; + } + +} diff --git a/forge/forge_common/net/minecraft/src/forge/packets/PacketModIDs.java b/forge/forge_common/net/minecraft/src/forge/packets/PacketModIDs.java new file mode 100644 index 000000000..6a3298823 --- /dev/null +++ b/forge/forge_common/net/minecraft/src/forge/packets/PacketModIDs.java @@ -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 Mods = new Hashtable(); + public int Length; + + @Override + public void writeData(DataOutputStream data) throws IOException + { + data.writeInt(Mods.size()); + for (Entry 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; + } + +} diff --git a/forge/forge_server/src/net/minecraft/src/forge/ForgeHooksServer.java b/forge/forge_server/src/net/minecraft/src/forge/ForgeHooksServer.java index cf60baf9a..682cc6499 100644 --- a/forge/forge_server/src/net/minecraft/src/forge/ForgeHooksServer.java +++ b/forge/forge_server/src/net/minecraft/src/forge/ForgeHooksServer.java @@ -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() diff --git a/forge/forge_server/src/net/minecraft/src/forge/PacketHandlerServer.java b/forge/forge_server/src/net/minecraft/src/forge/PacketHandlerServer.java index 13a3c53ca..eaca8c126 100644 --- a/forge/forge_server/src/net/minecraft/src/forge/PacketHandlerServer.java +++ b/forge/forge_server/src/net/minecraft/src/forge/PacketHandlerServer.java @@ -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 missing = new ArrayList(); + 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 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; } }