001 package cpw.mods.fml.common.network; 002 003 import java.util.Arrays; 004 import java.util.concurrent.ConcurrentMap; 005 import java.util.logging.Level; 006 007 import net.minecraft.network.INetworkManager; 008 import net.minecraft.network.packet.NetHandler; 009 010 import com.google.common.base.Throwables; 011 import com.google.common.collect.MapMaker; 012 import com.google.common.primitives.Bytes; 013 import com.google.common.primitives.Ints; 014 import com.google.common.primitives.UnsignedBytes; 015 016 import cpw.mods.fml.common.FMLLog; 017 018 public abstract class FMLPacket 019 { 020 enum Type 021 { 022 /** 023 * Opening salutation from the server to the client -> request all mods from the client 024 */ 025 MOD_LIST_REQUEST(ModListRequestPacket.class, false), 026 /** 027 * The client responds with the list of mods and versions it has. This is verified by the server. 028 */ 029 MOD_LIST_RESPONSE(ModListResponsePacket.class, false), 030 /** 031 * At which point the server tells the client the mod identifiers for this session. 032 */ 033 MOD_IDENTIFIERS(ModIdentifiersPacket.class, false), 034 /** 035 * Or, if there is missing stuff, the server tells the client what's missing and drops the connection. 036 */ 037 MOD_MISSING(ModMissingPacket.class, false), 038 /** 039 * Open a GUI on the client from the server 040 */ 041 GUIOPEN(OpenGuiPacket.class, false), 042 /** 043 * Spawn an entity on the client from the server 044 */ 045 ENTITYSPAWN(EntitySpawnPacket.class, false), 046 /** 047 * Fixes entity location data after spawning 048 */ 049 ENTITYSPAWNADJUSTMENT(EntitySpawnAdjustmentPacket.class, false), 050 /** 051 * The ID map to send to the client 052 */ 053 MOD_IDMAP(ModIdMapPacket.class, true); 054 055 056 private Class<? extends FMLPacket> packetType; 057 private boolean isMultipart; 058 private ConcurrentMap<INetworkManager, FMLPacket> partTracker; 059 060 private Type(Class<? extends FMLPacket> clazz, boolean isMultipart) 061 { 062 this.packetType = clazz; 063 this.isMultipart = isMultipart; 064 } 065 066 FMLPacket make() 067 { 068 try 069 { 070 return this.packetType.newInstance(); 071 } 072 catch (Exception e) 073 { 074 Throwables.propagateIfPossible(e); 075 FMLLog.log(Level.SEVERE, e, "A bizarre critical error occured during packet encoding"); 076 throw new FMLNetworkException(e); 077 } 078 } 079 080 public boolean isMultipart() 081 { 082 return isMultipart; 083 } 084 085 private FMLPacket findCurrentPart(INetworkManager network) 086 { 087 if (partTracker == null) 088 { 089 partTracker = new MapMaker().weakKeys().weakValues().makeMap(); 090 } 091 if (!partTracker.containsKey(network)) 092 { 093 partTracker.put(network, make()); 094 } 095 return partTracker.get(network); 096 } 097 } 098 099 private Type type; 100 101 public static byte[][] makePacketSet(Type type, Object... data) 102 { 103 if (!type.isMultipart()) 104 { 105 return new byte[0][]; 106 } 107 byte[] packetData = type.make().generatePacket(data); 108 109 byte[][] chunks = new byte[packetData.length / 32000 + 1][]; 110 for (int i = 0; i < packetData.length / 32000 + 1; i++) 111 { 112 int len = Math.min(32000, packetData.length - i* 32000); 113 chunks[i] = Bytes.concat(new byte[] { UnsignedBytes.checkedCast(type.ordinal()), UnsignedBytes.checkedCast(i), UnsignedBytes.checkedCast(chunks.length)}, Ints.toByteArray(len), Arrays.copyOfRange(packetData, i * 32000, len)); 114 } 115 return chunks; 116 } 117 public static byte[] makePacket(Type type, Object... data) 118 { 119 byte[] packetData = type.make().generatePacket(data); 120 return Bytes.concat(new byte[] { UnsignedBytes.checkedCast(type.ordinal()) }, packetData ); 121 } 122 123 public static FMLPacket readPacket(INetworkManager network, byte[] payload) 124 { 125 int type = UnsignedBytes.toInt(payload[0]); 126 Type eType = Type.values()[type]; 127 FMLPacket pkt; 128 if (eType.isMultipart()) 129 { 130 pkt = eType.findCurrentPart(network); 131 } 132 else 133 { 134 pkt = eType.make(); 135 } 136 return pkt.consumePacket(Arrays.copyOfRange(payload, 1, payload.length)); 137 } 138 139 public FMLPacket(Type type) 140 { 141 this.type = type; 142 } 143 144 public abstract byte[] generatePacket(Object... data); 145 146 public abstract FMLPacket consumePacket(byte[] data); 147 148 public abstract void execute(INetworkManager network, FMLNetworkHandler handler, NetHandler netHandler, String userName); 149 }