001 package cpw.mods.fml.common.network; 002 003 import java.lang.reflect.Method; 004 import java.util.Set; 005 import java.util.logging.Level; 006 007 import com.google.common.base.Strings; 008 009 import cpw.mods.fml.common.FMLCommonHandler; 010 import cpw.mods.fml.common.FMLLog; 011 import cpw.mods.fml.common.ModContainer; 012 import cpw.mods.fml.common.Side; 013 import cpw.mods.fml.common.discovery.ASMDataTable; 014 import cpw.mods.fml.common.discovery.ASMDataTable.ASMData; 015 import cpw.mods.fml.common.versioning.DefaultArtifactVersion; 016 import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException; 017 import cpw.mods.fml.common.versioning.VersionRange; 018 019 public class NetworkModHandler 020 { 021 private static Object connectionHandlerDefaultValue; 022 private static Object packetHandlerDefaultValue; 023 private static Object clientHandlerDefaultValue; 024 private static Object serverHandlerDefaultValue; 025 026 private static int assignedIds = 1; 027 028 private int localId; 029 private int networkId; 030 031 private ModContainer container; 032 private NetworkMod mod; 033 private Method checkHandler; 034 035 private VersionRange acceptableRange; 036 037 public NetworkModHandler(ModContainer container, NetworkMod modAnnotation) 038 { 039 this.container = container; 040 this.mod = modAnnotation; 041 this.localId = assignedIds++; 042 this.networkId = this.localId; 043 } 044 public NetworkModHandler(ModContainer container, Class<?> networkModClass, ASMDataTable table) 045 { 046 this(container, networkModClass.getAnnotation(NetworkMod.class)); 047 if (this.mod == null) 048 { 049 return; 050 } 051 052 Set<ASMData> versionCheckHandlers = table.getAnnotationsFor(container).get(NetworkMod.VersionCheckHandler.class.getName()); 053 String versionCheckHandlerMethod = null; 054 for (ASMData vch : versionCheckHandlers) 055 { 056 if (vch.getClassName().equals(networkModClass.getName())) 057 { 058 versionCheckHandlerMethod = vch.getObjectName(); 059 break; 060 } 061 } 062 if (versionCheckHandlerMethod != null) 063 { 064 try 065 { 066 Method checkHandlerMethod = networkModClass.getDeclaredMethod(versionCheckHandlerMethod, String.class); 067 if (checkHandlerMethod.isAnnotationPresent(NetworkMod.VersionCheckHandler.class)) 068 { 069 this.checkHandler = checkHandlerMethod; 070 } 071 } 072 catch (Exception e) 073 { 074 FMLLog.log(Level.WARNING, e, "The declared version check handler method %s on network mod id %s is not accessible", versionCheckHandlerMethod, container.getModId()); 075 } 076 } 077 078 if (this.checkHandler == null) 079 { 080 String versionBounds = mod.versionBounds(); 081 if (!Strings.isNullOrEmpty(versionBounds)) 082 { 083 try 084 { 085 this.acceptableRange = VersionRange.createFromVersionSpec(versionBounds); 086 } 087 catch (InvalidVersionSpecificationException e) 088 { 089 FMLLog.log(Level.WARNING, e, "Invalid bounded range %s specified for network mod id %s", versionBounds, container.getModId()); 090 } 091 } 092 } 093 094 FMLLog.finest("Testing mod %s to very it can accept it's own version in a remote connection", container.getModId()); 095 boolean acceptsSelf = acceptVersion(container.getVersion()); 096 if (!acceptsSelf) 097 { 098 FMLLog.severe("The mod %s appears to reject it's own version number (%s) in it's version handling. This is likely a severe bug in the mod!", container.getModId(), container.getVersion()); 099 } 100 else 101 { 102 FMLLog.finest("The mod %s accepts it's own version (%s)", container.getModId(), container.getVersion()); 103 } 104 105 tryCreatingPacketHandler(container, mod.packetHandler(), mod.channels(), null); 106 if (FMLCommonHandler.instance().getSide().isClient()) 107 { 108 if (mod.clientPacketHandlerSpec() != getClientHandlerSpecDefaultValue()) 109 { 110 tryCreatingPacketHandler(container, mod.clientPacketHandlerSpec().packetHandler(), mod.clientPacketHandlerSpec().channels(), Side.CLIENT); 111 } 112 } 113 if (mod.serverPacketHandlerSpec() != getServerHandlerSpecDefaultValue()) 114 { 115 tryCreatingPacketHandler(container, mod.serverPacketHandlerSpec().packetHandler(), mod.serverPacketHandlerSpec().channels(), Side.SERVER); 116 } 117 118 if (mod.connectionHandler() != getConnectionHandlerDefaultValue()) 119 { 120 IConnectionHandler instance; 121 try 122 { 123 instance = mod.connectionHandler().newInstance(); 124 } 125 catch (Exception e) 126 { 127 FMLLog.log(Level.SEVERE, e, "Unable to create connection handler instance %s", mod.connectionHandler().getName()); 128 throw new FMLNetworkException(e); 129 } 130 131 NetworkRegistry.instance().registerConnectionHandler(instance); 132 } 133 } 134 /** 135 * @param container 136 */ 137 private void tryCreatingPacketHandler(ModContainer container, Class<? extends IPacketHandler> clazz, String[] channels, Side side) 138 { 139 if (side!=null && side.isClient() && ! FMLCommonHandler.instance().getSide().isClient()) 140 { 141 return; 142 } 143 if (clazz!=getPacketHandlerDefaultValue()) 144 { 145 if (channels.length==0) 146 { 147 FMLLog.log(Level.WARNING, "The mod id %s attempted to register a packet handler without specifying channels for it", container.getModId()); 148 } 149 else 150 { 151 IPacketHandler instance; 152 try 153 { 154 instance = clazz.newInstance(); 155 } 156 catch (Exception e) 157 { 158 FMLLog.log(Level.SEVERE, e, "Unable to create a packet handler instance %s for mod %s", clazz.getName(), container.getModId()); 159 throw new FMLNetworkException(e); 160 } 161 162 for (String channel : channels) 163 { 164 NetworkRegistry.instance().registerChannel(instance, channel, side); 165 } 166 } 167 } 168 else if (channels.length > 0) 169 { 170 FMLLog.warning("The mod id %s attempted to register channels without specifying a packet handler", container.getModId()); 171 } 172 } 173 /** 174 * @return 175 */ 176 private Object getConnectionHandlerDefaultValue() 177 { 178 try { 179 if (connectionHandlerDefaultValue == null) 180 { 181 connectionHandlerDefaultValue = NetworkMod.class.getMethod("connectionHandler").getDefaultValue(); 182 } 183 return connectionHandlerDefaultValue; 184 } 185 catch (NoSuchMethodException e) 186 { 187 throw new RuntimeException("Derp?", e); 188 } 189 } 190 191 /** 192 * @return 193 */ 194 private Object getPacketHandlerDefaultValue() 195 { 196 try { 197 if (packetHandlerDefaultValue == null) 198 { 199 packetHandlerDefaultValue = NetworkMod.class.getMethod("packetHandler").getDefaultValue(); 200 } 201 return packetHandlerDefaultValue; 202 } 203 catch (NoSuchMethodException e) 204 { 205 throw new RuntimeException("Derp?", e); 206 } 207 } 208 209 /** 210 * @return 211 */ 212 private Object getClientHandlerSpecDefaultValue() 213 { 214 try { 215 if (clientHandlerDefaultValue == null) 216 { 217 clientHandlerDefaultValue = NetworkMod.class.getMethod("clientPacketHandlerSpec").getDefaultValue(); 218 } 219 return clientHandlerDefaultValue; 220 } 221 catch (NoSuchMethodException e) 222 { 223 throw new RuntimeException("Derp?", e); 224 } 225 } 226 /** 227 * @return 228 */ 229 private Object getServerHandlerSpecDefaultValue() 230 { 231 try { 232 if (serverHandlerDefaultValue == null) 233 { 234 serverHandlerDefaultValue = NetworkMod.class.getMethod("serverPacketHandlerSpec").getDefaultValue(); 235 } 236 return serverHandlerDefaultValue; 237 } 238 catch (NoSuchMethodException e) 239 { 240 throw new RuntimeException("Derp?", e); 241 } 242 } 243 public boolean requiresClientSide() 244 { 245 return mod.clientSideRequired(); 246 } 247 248 public boolean requiresServerSide() 249 { 250 return mod.serverSideRequired(); 251 } 252 253 public boolean acceptVersion(String version) 254 { 255 if (checkHandler != null) 256 { 257 try 258 { 259 return (Boolean)checkHandler.invoke(container.getMod(), version); 260 } 261 catch (Exception e) 262 { 263 FMLLog.log(Level.WARNING, e, "There was a problem invoking the checkhandler method %s for network mod id %s", checkHandler.getName(), container.getModId()); 264 return false; 265 } 266 } 267 268 if (acceptableRange!=null) 269 { 270 return acceptableRange.containsVersion(new DefaultArtifactVersion(version)); 271 } 272 273 return container.getVersion().equals(version); 274 } 275 276 public int getLocalId() 277 { 278 return localId; 279 } 280 281 public int getNetworkId() 282 { 283 return networkId; 284 } 285 286 public ModContainer getContainer() 287 { 288 return container; 289 } 290 291 public NetworkMod getMod() 292 { 293 return mod; 294 } 295 296 public boolean isNetworkMod() 297 { 298 return mod != null; 299 } 300 301 public void setNetworkId(int value) 302 { 303 this.networkId = value; 304 } 305 }