From 70fbe4f403e190b9fc246972c07985fa021eb316 Mon Sep 17 00:00:00 2001 From: LexManos Date: Mon, 20 Feb 2012 23:50:26 -0800 Subject: [PATCH] Introuduced NetworkMod, a BaseMod extension and replacement for BaseModMP. All mods that are designed to work in the server environment should extend this. NetworkMods will be assigned unique ModIDs by the server, and those IDs will be sent to the client upon connection. Refactored Forge packets to the net.minecraft.src.forge.packets package. And introduced the base ForgePacket class. Added initial ModList request/response. --- .../src/forge/PacketHandlerClient.java | 47 ++++++++++++--- .../src/forge/EntityTrackerInfo.java | 4 +- .../net/minecraft/src/forge/ForgeHooks.java | 30 ++-------- .../minecraft/src/forge/MinecraftForge.java | 41 +++++++++++-- .../net/minecraft/src/forge/NetworkMod.java | 25 ++++++++ .../src/forge/packets/ForgePacket.java | 49 ++++++++++++++++ .../{ => packets}/PacketEntitySpawn.java | 27 +++++++-- .../src/forge/packets/PacketModList.java | 58 +++++++++++++++++++ .../minecraft/src/NetClientHandler.java.patch | 17 +++--- .../net/minecraft/src/ModLoader.java.patch | 29 +++++++++- .../minecraft/src/NetLoginHandler.java.patch | 11 ++-- 11 files changed, 278 insertions(+), 60 deletions(-) create mode 100644 forge/forge_common/net/minecraft/src/forge/NetworkMod.java create mode 100644 forge/forge_common/net/minecraft/src/forge/packets/ForgePacket.java rename forge/forge_common/net/minecraft/src/forge/{ => packets}/PacketEntitySpawn.java (74%) create mode 100644 forge/forge_common/net/minecraft/src/forge/packets/PacketModList.java 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 5ddf23d6e6..57a8093aca 100644 --- a/forge/forge_client/src/net/minecraft/src/forge/PacketHandlerClient.java +++ b/forge/forge_client/src/net/minecraft/src/forge/PacketHandlerClient.java @@ -1,16 +1,18 @@ package net.minecraft.src.forge; 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.List; +import java.util.Map.Entry; import java.util.logging.Level; import net.minecraft.client.Minecraft; -import net.minecraft.src.Entity; -import net.minecraft.src.ModLoader; -import net.minecraft.src.NetworkManager; -import net.minecraft.src.World; -import net.minecraft.src.WorldClient; +import net.minecraft.src.*; +import net.minecraft.src.forge.packets.*; public class PacketHandlerClient implements IPacketHandler { @@ -20,13 +22,16 @@ public class PacketHandlerClient implements IPacketHandler DataInputStream data = new DataInputStream(new ByteArrayInputStream(bytes)); try { + ForgePacket pkt = null; + NetClientHandler net = (NetClientHandler)network.getNetHandler(); + int packetID = data.read(); switch(packetID) { - case ForgeHooks.FORGE_PACKET_SPAWN: - PacketEntitySpawn pkt = new PacketEntitySpawn(); + case ForgePacket.SPAWN: + pkt = new PacketEntitySpawn(); pkt.readData(data); - onEntitySpawnPacket(pkt, data, ModLoader.getMinecraftInstance().theWorld); + onEntitySpawnPacket((PacketEntitySpawn)pkt, data, ModLoader.getMinecraftInstance().theWorld); break; } } @@ -36,7 +41,14 @@ public class PacketHandlerClient implements IPacketHandler e.printStackTrace(); } } - + + /** + * Processes the Entity Spawn packet. And spawns an entity in world as needed. + * If the client has the required client mod. + * @param packet The Spawn Packet + * @param data A stream holding extra data for the entity to read + * @param world The world to spawn the entity in + */ public void onEntitySpawnPacket(PacketEntitySpawn packet, DataInputStream data, World world) { Class cls = MinecraftForge.getEntityClass(packet.modID, packet.typeID); @@ -96,4 +108,21 @@ public class PacketHandlerClient implements IPacketHandler ModLoader.ThrowException(String.format("Error spawning entity of type %d for %s.", packet.typeID, MinecraftForge.getModByID(packet.modID)), e); } } + + /** + * Sends a list of all loaded mods to the server. + * For now, it it simple a String[] of mod.toString() + * @param network The network connection to send the packet on. + */ + private void onModListCheck(NetClientHandler net) + { + PacketModList pkt = new PacketModList(false); + pkt.Mods = new String[ModLoader.getLoadedMods().size()]; + int x = 0; + for(BaseMod mod : (List)ModLoader.getLoadedMods()) + { + pkt.Mods[x++] = mod.toString(); + } + net.addToSendQueue(pkt.getPacket()); + } } diff --git a/forge/forge_common/net/minecraft/src/forge/EntityTrackerInfo.java b/forge/forge_common/net/minecraft/src/forge/EntityTrackerInfo.java index 1e88261e0b..e9444f1b7e 100644 --- a/forge/forge_common/net/minecraft/src/forge/EntityTrackerInfo.java +++ b/forge/forge_common/net/minecraft/src/forge/EntityTrackerInfo.java @@ -4,13 +4,13 @@ import net.minecraft.src.BaseMod; public class EntityTrackerInfo { - public final BaseMod Mod; + public final NetworkMod Mod; public final int ID; public final int Range; public final int UpdateFrequancy; public final boolean SendVelocityInfo; - public EntityTrackerInfo(BaseMod mod, int ID, int range, int updateFrequancy, boolean sendVelocityInfo) + public EntityTrackerInfo(NetworkMod mod, int ID, int range, int updateFrequancy, boolean sendVelocityInfo) { Mod = mod; this.ID = ID; diff --git a/forge/forge_common/net/minecraft/src/forge/ForgeHooks.java b/forge/forge_common/net/minecraft/src/forge/ForgeHooks.java index eadfefaa9f..e1544c3bf2 100644 --- a/forge/forge_common/net/minecraft/src/forge/ForgeHooks.java +++ b/forge/forge_common/net/minecraft/src/forge/ForgeHooks.java @@ -5,6 +5,7 @@ package net.minecraft.src.forge; +import net.minecraft.src.BaseMod; import net.minecraft.src.Block; import net.minecraft.src.Entity; import net.minecraft.src.EntityItem; @@ -20,6 +21,7 @@ import net.minecraft.src.Packet; import net.minecraft.src.Packet1Login; import net.minecraft.src.Packet250CustomPayload; import net.minecraft.src.World; +import net.minecraft.src.forge.packets.PacketEntitySpawn; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -360,29 +362,12 @@ public class ForgeHooks { { return null; } - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - DataOutputStream data = new DataOutputStream(bytes); - try - { - data.writeByte(FORGE_PACKET_SPAWN); - PacketEntitySpawn spawn = new PacketEntitySpawn(entity, info.Mod, info.ID); - spawn.writeData(data); - if (entity instanceof ISpawnHandler) - { - ((ISpawnHandler)entity).writeSpawnData(data); - } - } - catch (IOException e) - { - e.printStackTrace(); - } - Packet250CustomPayload pkt = new Packet250CustomPayload(); - pkt.channel = "Forge"; - pkt.data = bytes.toByteArray(); - pkt.length = pkt.data.length; - return pkt; + PacketEntitySpawn pkt = new PacketEntitySpawn(entity, info.Mod, info.ID); + return pkt.getPacket(); } + + public static Hashtable networkMods = new Hashtable(); public static final int majorVersion=0; public static final int minorVersion=0; @@ -411,8 +396,5 @@ public class ForgeHooks { { return forgePacketHandler; } - //Forge Packet ID Constants. - public static final int FORGE_ID = 0x040E9B47; //"Forge".hashCode(); - public static final int FORGE_PACKET_SPAWN = 1; } diff --git a/forge/forge_common/net/minecraft/src/forge/MinecraftForge.java b/forge/forge_common/net/minecraft/src/forge/MinecraftForge.java index 7c7d28ae2b..9df81093ac 100755 --- a/forge/forge_common/net/minecraft/src/forge/MinecraftForge.java +++ b/forge/forge_common/net/minecraft/src/forge/MinecraftForge.java @@ -15,6 +15,7 @@ import net.minecraft.src.ModLoader; import net.minecraft.src.World; import java.util.*; +import java.util.Map.Entry; public class MinecraftForge { @@ -808,7 +809,7 @@ public class MinecraftForge { * @param sendVelocityInfo If velocity information should be included in the update information. * @return True, if successfully registered. False if the class is already registered. */ - public static boolean registerEntity(Class entityClass, BaseMod mod, int ID, int range, int updateFrequancy, boolean sendVelocityInfo) + public static boolean registerEntity(Class entityClass, NetworkMod mod, int ID, int range, int updateFrequancy, boolean sendVelocityInfo) { if (ForgeHooks.entityTrackerMap.containsKey(entityClass)) { @@ -866,16 +867,44 @@ public class MinecraftForge { * @param id The mod ID * @return The mod, or null if not found */ - public static BaseMod getModByID(int id) + public static NetworkMod getModByID(int id) { - for(BaseMod mod : (List)ModLoader.getLoadedMods()) + return ForgeHooks.networkMods.get(id); + } + + /** + * Returns a unique index number for the specific mod. + * + * @param mod The mod to find + * @return The index number, -1 if no index found + */ + public static int getModID(NetworkMod mod) + { + for (Entry entry : ForgeHooks.networkMods.entrySet()) { - if (mod.toString().hashCode() == id) + if (entry.getValue() == mod) { - return mod; + return entry.getKey(); } } - return null; + return -1; + } + + /** + * Returns a list of mods that are designed to be used over the network. + * @return + */ + public static NetworkMod[] getNetworkMods() + { + ArrayList ret = new ArrayList(); + for(BaseMod mod : (List)ModLoader.getLoadedMods()) + { + if (mod instanceof NetworkMod) + { + ret.add((NetworkMod)mod); + } + } + return ret.toArray(new NetworkMod[0]); } diff --git a/forge/forge_common/net/minecraft/src/forge/NetworkMod.java b/forge/forge_common/net/minecraft/src/forge/NetworkMod.java new file mode 100644 index 0000000000..a7aa76d9e5 --- /dev/null +++ b/forge/forge_common/net/minecraft/src/forge/NetworkMod.java @@ -0,0 +1,25 @@ +package net.minecraft.src.forge; + +import net.minecraft.src.BaseMod; + +/** + * This is for mods that are designed to be used on the server side alone, + * or both the client and server side. This class is used when registering + * various things relating to network traffic. Entity ID's, GUI Id's, etc.. + */ +public abstract class NetworkMod extends BaseMod +{ + /** + * Returns true if every client is required to have this + * mod installed when it is installed on a server. + * @return True if client is required, false if not. + */ + public abstract boolean clientSideRequired(); + + /** + * Returns true if the server is required to have this + * mod when it is installed on the client. + * @return True if server is required, false if not. + */ + public abstract boolean serverSideRequired(); +} diff --git a/forge/forge_common/net/minecraft/src/forge/packets/ForgePacket.java b/forge/forge_common/net/minecraft/src/forge/packets/ForgePacket.java new file mode 100644 index 0000000000..c650a2337e --- /dev/null +++ b/forge/forge_common/net/minecraft/src/forge/packets/ForgePacket.java @@ -0,0 +1,49 @@ +package net.minecraft.src.forge.packets; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; + +import net.minecraft.src.BaseMod; +import net.minecraft.src.ModLoader; +import net.minecraft.src.Packet; +import net.minecraft.src.Packet250CustomPayload; +import net.minecraft.src.forge.ForgeHooks; + +public abstract class ForgePacket +{ + //Forge Packet ID Constants. + public static final int FORGE_ID = 0x040E9B47; //"Forge".hashCode(); + public static final int SPAWN = 1; + public static final int MODLIST = 2; + public static final int MOD_MISSING = 3; + public static final int MOD_IDS = 4; + public static final int OPEN_GUI = 5; + + public Packet getPacket() + { + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + try + { + data.writeByte(getID()); + writeData(data); + } + catch (IOException e) + { + e.printStackTrace(); + } + Packet250CustomPayload pkt = new Packet250CustomPayload(); + pkt.channel = "Forge"; + pkt.data = bytes.toByteArray(); + pkt.length = pkt.data.length; + return pkt; + } + + public abstract void writeData(DataOutputStream data) throws IOException; + public abstract void readData(DataInputStream data) throws IOException; + public abstract int getID(); +} diff --git a/forge/forge_common/net/minecraft/src/forge/PacketEntitySpawn.java b/forge/forge_common/net/minecraft/src/forge/packets/PacketEntitySpawn.java similarity index 74% rename from forge/forge_common/net/minecraft/src/forge/PacketEntitySpawn.java rename to forge/forge_common/net/minecraft/src/forge/packets/PacketEntitySpawn.java index 5d55fff76c..2a29ba47cf 100644 --- a/forge/forge_common/net/minecraft/src/forge/PacketEntitySpawn.java +++ b/forge/forge_common/net/minecraft/src/forge/packets/PacketEntitySpawn.java @@ -1,4 +1,4 @@ -package net.minecraft.src.forge; +package net.minecraft.src.forge.packets; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -7,10 +7,13 @@ import java.io.IOException; import net.minecraft.src.BaseMod; import net.minecraft.src.Entity; import net.minecraft.src.MathHelper; +import net.minecraft.src.forge.ISpawnHandler; +import net.minecraft.src.forge.IThrowableEntity; +import net.minecraft.src.forge.MinecraftForge; +import net.minecraft.src.forge.NetworkMod; -public class PacketEntitySpawn +public class PacketEntitySpawn extends ForgePacket { - public int entityID; public int posX; public int posY; @@ -21,9 +24,10 @@ public class PacketEntitySpawn public int typeID; public int modID; public int throwerID; + private ISpawnHandler handler; public PacketEntitySpawn(){} - public PacketEntitySpawn(Entity ent, BaseMod mod, int type) + public PacketEntitySpawn(Entity ent, NetworkMod mod, int type) { entityID = ent.entityId; @@ -32,7 +36,7 @@ public class PacketEntitySpawn posZ = MathHelper.floor_double(ent.posZ * 32D); typeID = type; - modID = mod.toString().hashCode(); + modID = MinecraftForge.getModID(mod); if (ent instanceof IThrowableEntity) { @@ -52,6 +56,10 @@ public class PacketEntitySpawn speedY = (int)(mY * 8000D); speedZ = (int)(mZ * 8000D); } + if (ent instanceof ISpawnHandler) + { + handler = (ISpawnHandler)ent; + } } public void writeData(DataOutputStream data) throws IOException { @@ -68,6 +76,10 @@ public class PacketEntitySpawn data.writeShort(speedY); data.writeShort(speedZ); } + if (handler != null) + { + handler.writeSpawnData(data); + } } public void readData(DataInputStream data) throws IOException @@ -86,4 +98,9 @@ public class PacketEntitySpawn speedX = data.readShort(); } } + @Override + public int getID() + { + return ForgePacket.SPAWN; + } } diff --git a/forge/forge_common/net/minecraft/src/forge/packets/PacketModList.java b/forge/forge_common/net/minecraft/src/forge/packets/PacketModList.java new file mode 100644 index 0000000000..47191f67a0 --- /dev/null +++ b/forge/forge_common/net/minecraft/src/forge/packets/PacketModList.java @@ -0,0 +1,58 @@ +package net.minecraft.src.forge.packets; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; + +import net.minecraft.src.BaseMod; +import net.minecraft.src.ModLoader; + +public class PacketModList extends ForgePacket +{ + private boolean isServer = false; + public String[] Mods; + public int Length = -1; + + public PacketModList(boolean server) + { + isServer = server; + } + + @Override + public void writeData(DataOutputStream data) throws IOException + { + if (!isServer) + { + data.writeInt(Mods.length); + for(String mod : Mods) + { + data.writeUTF(mod); + } + } + } + + @Override + public void readData(DataInputStream data) throws IOException + { + if (isServer) + { + Length = data.readInt(); + if (Length >= 0) + { + Mods = new String[Length]; + for (int x = 0; x < Length; x++) + { + Mods[x] = data.readUTF(); + } + } + } + } + + @Override + public int getID() + { + return ForgePacket.MODLIST; + } + +} diff --git a/forge/patches/minecraft/net/minecraft/src/NetClientHandler.java.patch b/forge/patches/minecraft/net/minecraft/src/NetClientHandler.java.patch index 46105316b0..8c70a3751c 100644 --- a/forge/patches/minecraft/net/minecraft/src/NetClientHandler.java.patch +++ b/forge/patches/minecraft/net/minecraft/src/NetClientHandler.java.patch @@ -1,15 +1,16 @@ --- ../src_base/minecraft/net/minecraft/src/NetClientHandler.java 0000-00-00 00:00:00.000000000 -0000 +++ ../src_work/minecraft/net/minecraft/src/NetClientHandler.java 0000-00-00 00:00:00.000000000 -0000 -@@ -7,6 +7,8 @@ +@@ -7,6 +7,9 @@ import java.util.*; import java.util.logging.Logger; import net.minecraft.client.Minecraft; +import net.minecraft.src.forge.ForgeHooks; +import net.minecraft.src.forge.MessageManager; ++import net.minecraft.src.forge.packets.ForgePacket; public class NetClientHandler extends NetHandler { -@@ -35,6 +37,8 @@ +@@ -35,6 +38,8 @@ mc = minecraft; Socket socket = new Socket(InetAddress.getByName(s), i); netManager = new NetworkManager(socket, "Client", this); @@ -18,7 +19,7 @@ } public void processReadPackets() -@@ -58,6 +62,27 @@ +@@ -58,6 +63,27 @@ mc.thePlayer.entityId = packet1login.protocolVersion; currentServerMaxPlayers = packet1login.maxPlayers; ((PlayerControllerMP)mc.playerController).setCreative(packet1login.serverMode == 1); @@ -46,7 +47,7 @@ } public void handlePickupSpawn(Packet21PickupSpawn packet21pickupspawn) -@@ -608,7 +633,19 @@ +@@ -608,7 +634,19 @@ } else if (packet2handshake.username.equals("-")) { @@ -61,13 +62,13 @@ + * The C->S mapSeed is set to the current Forge build number, in case we need to do any quick version checks. + */ + Packet1Login pkt = new Packet1Login(mc.session.username, 23); -+ pkt.serverMode = ForgeHooks.FORGE_ID; ++ pkt.serverMode = ForgePacket.FORGE_ID; + pkt.mapSeed = ForgeHooks.buildVersion; + addToSendQueue(pkt); } else { -@@ -620,7 +657,19 @@ +@@ -620,7 +658,19 @@ bufferedreader.close(); if (s1.equalsIgnoreCase("ok")) { @@ -82,13 +83,13 @@ + * The C->S mapSeed is set to the current Forge build number, in case we need to do any quick version checks. + */ + Packet1Login pkt = new Packet1Login(mc.session.username, 23); -+ pkt.serverMode = ForgeHooks.FORGE_ID; ++ pkt.serverMode = ForgePacket.FORGE_ID; + pkt.mapSeed = ForgeHooks.buildVersion; + addToSendQueue(pkt); } else { -@@ -1017,4 +1066,44 @@ +@@ -1017,4 +1067,44 @@ { addToSendQueue(new Packet0KeepAlive(packet0keepalive.randomId)); } diff --git a/forge/patches/minecraft_server/net/minecraft/src/ModLoader.java.patch b/forge/patches/minecraft_server/net/minecraft/src/ModLoader.java.patch index 045abcab87..97c3e29808 100644 --- a/forge/patches/minecraft_server/net/minecraft/src/ModLoader.java.patch +++ b/forge/patches/minecraft_server/net/minecraft/src/ModLoader.java.patch @@ -1,6 +1,33 @@ --- ../src_base/minecraft_server/net/minecraft/src/ModLoader.java 0000-00-00 00:00:00.000000000 -0000 +++ ../src_work/minecraft_server/net/minecraft/src/ModLoader.java 0000-00-00 00:00:00.000000000 -0000 -@@ -1325,6 +1325,7 @@ +@@ -10,6 +10,8 @@ + import java.util.zip.ZipEntry; + import java.util.zip.ZipInputStream; + import net.minecraft.server.MinecraftServer; ++import net.minecraft.src.forge.ForgeHooks; ++import net.minecraft.src.forge.NetworkMod; + + public final class ModLoader + { +@@ -626,6 +628,17 @@ + readFromClassPath(file); + System.out.println("Done."); + props.setProperty("loggingLevel", cfgLoggingLevel.getName()); ++ /* ++ * Gather up a list of network mods and assign them an id ++ */ ++ int x = 0; ++ for (BaseMod mod : (List)modList) ++ { ++ if (mod instanceof NetworkMod) ++ { ++ ForgeHooks.networkMods.put(x++, (NetworkMod)mod); ++ } ++ } + Iterator iterator = modList.iterator(); + do + { +@@ -1325,6 +1338,7 @@ { method_getNextWindowId.invoke(entityplayermp, new Object[0]); int j = field_currentWindowId.getInt(entityplayermp); diff --git a/forge/patches/minecraft_server/net/minecraft/src/NetLoginHandler.java.patch b/forge/patches/minecraft_server/net/minecraft/src/NetLoginHandler.java.patch index 1dad01427d..9f3d6603f3 100644 --- a/forge/patches/minecraft_server/net/minecraft/src/NetLoginHandler.java.patch +++ b/forge/patches/minecraft_server/net/minecraft/src/NetLoginHandler.java.patch @@ -1,6 +1,6 @@ --- ../src_base/minecraft_server/net/minecraft/src/NetLoginHandler.java 0000-00-00 00:00:00.000000000 -0000 +++ ../src_work/minecraft_server/net/minecraft/src/NetLoginHandler.java 0000-00-00 00:00:00.000000000 -0000 -@@ -1,10 +1,14 @@ +@@ -1,10 +1,15 @@ package net.minecraft.src; import java.io.IOException; @@ -12,10 +12,11 @@ +import net.minecraft.src.forge.ForgeHooks; +import net.minecraft.src.forge.ForgeHooksServer; +import net.minecraft.src.forge.MessageManager; ++import net.minecraft.src.forge.packets.ForgePacket; public class NetLoginHandler extends NetHandler { -@@ -29,6 +33,7 @@ +@@ -29,6 +34,7 @@ mcServer = minecraftserver; netManager = new NetworkManager(socket, s, this); netManager.chunkDataSendCounter = 0; @@ -23,13 +24,13 @@ } public void tryLogin() -@@ -129,7 +134,39 @@ +@@ -129,7 +135,39 @@ } entityplayermp.func_20057_k(); - ModLoaderMp.HandleAllLogins(entityplayermp); + -+ if (packet1login.serverMode == ForgeHooks.FORGE_ID) ++ if (packet1login.serverMode == ForgePacket.FORGE_ID) + { + //Pretty hackish place to put it, but it needs to go somewhere + ForgeHooksServer.init(); @@ -53,7 +54,7 @@ + } + pkt.length = pkt.data.length; + netserverhandler.sendPacket(pkt); -+ ++ ForgeHooksServer.sendModListRequest(netManager); + ModLoaderMp.HandleAllLogins(entityplayermp); + } + else