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