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            tryCreatingPacketHandler(container, mod.packetHandler(), mod.channels(), null);
095            if (FMLCommonHandler.instance().getSide().isClient())
096            {
097                if (mod.clientPacketHandlerSpec() != getClientHandlerSpecDefaultValue())
098                {
099                    tryCreatingPacketHandler(container, mod.clientPacketHandlerSpec().packetHandler(), mod.clientPacketHandlerSpec().channels(), Side.CLIENT);
100                }
101            }
102            if (mod.serverPacketHandlerSpec() != getServerHandlerSpecDefaultValue())
103            {
104                tryCreatingPacketHandler(container, mod.serverPacketHandlerSpec().packetHandler(), mod.serverPacketHandlerSpec().channels(), Side.SERVER);
105            }
106    
107            if (mod.connectionHandler() != getConnectionHandlerDefaultValue())
108            {
109                IConnectionHandler instance;
110                try
111                {
112                    instance = mod.connectionHandler().newInstance();
113                }
114                catch (Exception e)
115                {
116                    FMLLog.log(Level.SEVERE, e, "Unable to create connection handler instance %s", mod.connectionHandler().getName());
117                    throw new FMLNetworkException(e);
118                }
119    
120                NetworkRegistry.instance().registerConnectionHandler(instance);
121            }
122        }
123        /**
124         * @param container
125         */
126        private void tryCreatingPacketHandler(ModContainer container, Class<? extends IPacketHandler> clazz, String[] channels, Side side)
127        {
128            if (side!=null && side.isClient() && ! FMLCommonHandler.instance().getSide().isClient())
129            {
130                return;
131            }
132            if (clazz!=getPacketHandlerDefaultValue())
133            {
134                if (channels.length==0)
135                {
136                    FMLLog.log(Level.WARNING, "The mod id %s attempted to register a packet handler without specifying channels for it", container.getModId());
137                }
138                else
139                {
140                    IPacketHandler instance;
141                    try
142                    {
143                        instance = clazz.newInstance();
144                    }
145                    catch (Exception e)
146                    {
147                        FMLLog.log(Level.SEVERE, e, "Unable to create a packet handler instance %s for mod %s", clazz.getName(), container.getModId());
148                        throw new FMLNetworkException(e);
149                    }
150    
151                    for (String channel : channels)
152                    {
153                        NetworkRegistry.instance().registerChannel(instance, channel, side);
154                    }
155                }
156            }
157            else if (channels.length > 0)
158            {
159                FMLLog.warning("The mod id %s attempted to register channels without specifying a packet handler", container.getModId());
160            }
161        }
162        /**
163         * @return
164         */
165        private Object getConnectionHandlerDefaultValue()
166        {
167            try {
168                if (connectionHandlerDefaultValue == null)
169                {
170                    connectionHandlerDefaultValue = NetworkMod.class.getMethod("connectionHandler").getDefaultValue();
171                }
172                return connectionHandlerDefaultValue;
173            }
174            catch (NoSuchMethodException e)
175            {
176                throw new RuntimeException("Derp?", e);
177            }
178        }
179    
180        /**
181         * @return
182         */
183        private Object getPacketHandlerDefaultValue()
184        {
185            try {
186                if (packetHandlerDefaultValue == null)
187                {
188                    packetHandlerDefaultValue = NetworkMod.class.getMethod("packetHandler").getDefaultValue();
189                }
190                return packetHandlerDefaultValue;
191            }
192            catch (NoSuchMethodException e)
193            {
194                throw new RuntimeException("Derp?", e);
195            }
196        }
197    
198        /**
199         * @return
200         */
201        private Object getClientHandlerSpecDefaultValue()
202        {
203            try {
204                if (clientHandlerDefaultValue == null)
205                {
206                    clientHandlerDefaultValue = NetworkMod.class.getMethod("clientPacketHandlerSpec").getDefaultValue();
207                }
208                return clientHandlerDefaultValue;
209            }
210            catch (NoSuchMethodException e)
211            {
212                throw new RuntimeException("Derp?", e);
213            }
214        }
215        /**
216         * @return
217         */
218        private Object getServerHandlerSpecDefaultValue()
219        {
220            try {
221                if (serverHandlerDefaultValue == null)
222                {
223                    serverHandlerDefaultValue = NetworkMod.class.getMethod("serverPacketHandlerSpec").getDefaultValue();
224                }
225                return serverHandlerDefaultValue;
226            }
227            catch (NoSuchMethodException e)
228            {
229                throw new RuntimeException("Derp?", e);
230            }
231        }
232        public boolean requiresClientSide()
233        {
234            return mod.clientSideRequired();
235        }
236    
237        public boolean requiresServerSide()
238        {
239            return mod.serverSideRequired();
240        }
241    
242        public boolean acceptVersion(String version)
243        {
244            if (checkHandler != null)
245            {
246                try
247                {
248                    return (Boolean)checkHandler.invoke(container.getMod(), version);
249                }
250                catch (Exception e)
251                {
252                    FMLLog.log(Level.WARNING, e, "There was a problem invoking the checkhandler method %s for network mod id %s", checkHandler.getName(), container.getModId());
253                    return false;
254                }
255            }
256    
257            if (acceptableRange!=null)
258            {
259                return acceptableRange.containsVersion(new DefaultArtifactVersion(version));
260            }
261    
262            return container.getVersion().equals(version);
263        }
264    
265        public int getLocalId()
266        {
267            return localId;
268        }
269    
270        public int getNetworkId()
271        {
272            return networkId;
273        }
274    
275        public ModContainer getContainer()
276        {
277            return container;
278        }
279    
280        public NetworkMod getMod()
281        {
282            return mod;
283        }
284    
285        public boolean isNetworkMod()
286        {
287            return mod != null;
288        }
289    
290        public void setNetworkId(int value)
291        {
292            this.networkId = value;
293        }
294    }