    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.shiftedIndex == 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    }