    001    package cpw.mods.fml.common.network;
    002
    003    import java.util.Arrays;
    004    import java.util.List;
    005    import java.util.Map;
    006    import java.util.Set;
    007    import java.util.logging.Level;
    008
    009    import net.minecraft.entity.player.EntityPlayer;
    010    import net.minecraft.entity.player.EntityPlayerMP;
    011    import net.minecraft.inventory.Container;
    012    import net.minecraft.network.*;
    013    import net.minecraft.network.packet.*;
    014    import net.minecraft.server.MinecraftServer;
    015    import net.minecraft.world.World;
    016
    017    import com.google.common.base.Charsets;
    018    import com.google.common.base.Joiner;
    019    import com.google.common.base.Splitter;
    020    import com.google.common.base.Strings;
    021    import com.google.common.collect.ArrayListMultimap;
    022    import com.google.common.collect.Iterables;
    023    import com.google.common.collect.Lists;
    024    import com.google.common.collect.Maps;
    025    import com.google.common.collect.Multimap;
    026    import com.google.common.collect.Sets;
    027
    028    import cpw.mods.fml.common.FMLCommonHandler;
    029    import cpw.mods.fml.common.FMLLog;
    030    import cpw.mods.fml.common.Loader;
    031    import cpw.mods.fml.common.ModContainer;
    032    import cpw.mods.fml.common.network.FMLPacket.Type;
    033    import cpw.mods.fml.relauncher.Side;
    034
    035    /**
    036     * @author cpw
    037     *
    038     */
    039    public class NetworkRegistry
    040    {
    041
    042        private static final NetworkRegistry INSTANCE = new NetworkRegistry();
    043        /**
    044         * A map of active channels per player
    045         */
    046        private Multimap<Player, String> activeChannels = ArrayListMultimap.create();
    047        /**
    048         * A map of the packet handlers for packets
    049         */
    050        private Multimap<String, IPacketHandler> universalPacketHandlers = ArrayListMultimap.create();
    051        private Multimap<String, IPacketHandler> clientPacketHandlers = ArrayListMultimap.create();
    052        private Multimap<String, IPacketHandler> serverPacketHandlers = ArrayListMultimap.create();
    053        /**
    054         * A linked set of registered connection handlers
    055         */
    056        private Set<IConnectionHandler> connectionHandlers = Sets.newLinkedHashSet();
    057        private Map<ModContainer, IGuiHandler> serverGuiHandlers = Maps.newHashMap();
    058        private Map<ModContainer, IGuiHandler> clientGuiHandlers = Maps.newHashMap();
    059        private List<IChatListener> chatListeners = Lists.newArrayList();
    060
    061        public static NetworkRegistry instance()
    062        {
    063            return INSTANCE;
    064        }
    065        /**
    066         * Get the packet 250 channel registration string
    067         * @return
    068         */
    069        byte[] getPacketRegistry(Side side)
    070        {
    071            return Joiner.on('\0').join(Iterables.concat(Arrays.asList("FML"),universalPacketHandlers.keySet(), side.isClient() ? clientPacketHandlers.keySet() : serverPacketHandlers.keySet())).getBytes(Charsets.UTF_8);
    072        }
    073        /**
    074         * Is the specified channel active for the player?
    075         * @param channel
    076         * @param player
    077         */
    078        public boolean isChannelActive(String channel, Player player)
    079        {
    080            return activeChannels.containsEntry(player,channel);
    081        }
    082        /**
    083         * register a channel to a mod
    084         * @param container
    085         * @param channelName
    086         */
    087        public void registerChannel(IPacketHandler handler, String channelName)
    088        {
    089            if (Strings.isNullOrEmpty(channelName) || (channelName!=null && channelName.length()>16))
    090            {
    091                FMLLog.severe("Invalid channel name '%s' : %s", channelName, Strings.isNullOrEmpty(channelName) ? "Channel name is empty" : "Channel name is too long (16 chars is maximum)");
    092                throw new RuntimeException("Channel name is invalid");
    093
    094            }
    095            universalPacketHandlers.put(channelName, handler);
    096        }
    097
    098        public void registerChannel(IPacketHandler handler, String channelName, Side side)
    099        {
    100            if (side == null)
    101            {
    102                registerChannel(handler, channelName);
    103                return;
    104            }
    105            if (Strings.isNullOrEmpty(channelName) || (channelName!=null && channelName.length()>16))
    106            {
    107                FMLLog.severe("Invalid channel name '%s' : %s", channelName, Strings.isNullOrEmpty(channelName) ? "Channel name is empty" : "Channel name is too long (16 chars is maximum)");
    108                throw new RuntimeException("Channel name is invalid");
    109
    110            }
    111            if (side.isClient())
    112            {
    113                clientPacketHandlers.put(channelName, handler);
    114            }
    115            else
    116            {
    117                serverPacketHandlers.put(channelName, handler);
    118            }
    119        }
    120        /**
    121         * Activate the channel for the player
    122         * @param player
    123         */
    124        void activateChannel(Player player, String channel)
    125        {
    126            activeChannels.put(player, channel);
    127        }
    128        /**
    129         * Deactivate the channel for the player
    130         * @param player
    131         * @param channel
    132         */
    133        void deactivateChannel(Player player, String channel)
    134        {
    135            activeChannels.remove(player, channel);
    136        }
    137        /**
    138         * Register a connection handler
    139         *
    140         * @param handler
    141         */
    142        public void registerConnectionHandler(IConnectionHandler handler)
    143        {
    144            connectionHandlers.add(handler);
    145        }
    146
    147        /**
    148         * Register a chat listener
    149         * @param listener
    150         */
    151        public void registerChatListener(IChatListener listener)
    152        {
    153            chatListeners.add(listener);
    154        }
    155
    156        void playerLoggedIn(EntityPlayerMP player, NetServerHandler netHandler, INetworkManager manager)
    157        {
    158            generateChannelRegistration(player, netHandler, manager);
    159            for (IConnectionHandler handler : connectionHandlers)
    160            {
    161                handler.playerLoggedIn((Player)player, netHandler, manager);
    162            }
    163        }
    164
    165        String connectionReceived(NetLoginHandler netHandler, INetworkManager manager)
    166        {
    167            for (IConnectionHandler handler : connectionHandlers)
    168            {
    169                String kick = handler.connectionReceived(netHandler, manager);
    170                if (!Strings.isNullOrEmpty(kick))
    171                {
    172                    return kick;
    173                }
    174            }
    175            return null;
    176        }
    177
    178        void connectionOpened(NetHandler netClientHandler, String server, int port, INetworkManager networkManager)
    179        {
    180            for (IConnectionHandler handler : connectionHandlers)
    181            {
    182                handler.connectionOpened(netClientHandler, server, port, networkManager);
    183            }
    184        }
    185
    186        void connectionOpened(NetHandler netClientHandler, MinecraftServer server, INetworkManager networkManager)
    187        {
    188            for (IConnectionHandler handler : connectionHandlers)
    189            {
    190                handler.connectionOpened(netClientHandler, server, networkManager);
    191            }
    192        }
    193
    194        void clientLoggedIn(NetHandler clientHandler, INetworkManager manager, Packet1Login login)
    195        {
    196            generateChannelRegistration(clientHandler.getPlayer(), clientHandler, manager);
    197            for (IConnectionHandler handler : connectionHandlers)
    198            {
    199                handler.clientLoggedIn(clientHandler, manager, login);
    200            }
    201        }
    202
    203        void connectionClosed(INetworkManager manager, EntityPlayer player)
    204        {
    205            for (IConnectionHandler handler : connectionHandlers)
    206            {
    207                handler.connectionClosed(manager);
    208            }
    209            activeChannels.removeAll(player);
    210        }
    211
    212        void generateChannelRegistration(EntityPlayer player, NetHandler netHandler, INetworkManager manager)
    213        {
    214            Packet250CustomPayload pkt = new Packet250CustomPayload();
    215            pkt.channel = "REGISTER";
    216            pkt.data = getPacketRegistry(player instanceof EntityPlayerMP ? Side.SERVER : Side.CLIENT);
    217            pkt.length = pkt.data.length;
    218            manager.addToSendQueue(pkt);
    219        }
    220
    221        void handleCustomPacket(Packet250CustomPayload packet, INetworkManager network, NetHandler handler)
    222        {
    223            if ("REGISTER".equals(packet.channel))
    224            {
    225                handleRegistrationPacket(packet, (Player)handler.getPlayer());
    226            }
    227            else if ("UNREGISTER".equals(packet.channel))
    228            {
    229                handleUnregistrationPacket(packet, (Player)handler.getPlayer());
    230            }
    231            else
    232            {
    233                handlePacket(packet, network, (Player)handler.getPlayer());
    234            }
    235        }
    236
    237
    238        private void handlePacket(Packet250CustomPayload packet, INetworkManager network, Player player)
    239        {
    240            String channel = packet.channel;
    241            for (IPacketHandler handler : Iterables.concat(universalPacketHandlers.get(channel), player instanceof EntityPlayerMP ? serverPacketHandlers.get(channel) : clientPacketHandlers.get(channel)))
    242            {
    243                handler.onPacketData(network, packet, player);
    244            }
    245        }
    246
    247        private void handleRegistrationPacket(Packet250CustomPayload packet, Player player)
    248        {
    249            List<String> channels = extractChannelList(packet);
    250            for (String channel : channels)
    251            {
    252                activateChannel(player, channel);
    253            }
    254        }
    255        private void handleUnregistrationPacket(Packet250CustomPayload packet, Player player)
    256        {
    257            List<String> channels = extractChannelList(packet);
    258            for (String channel : channels)
    259            {
    260                deactivateChannel(player, channel);
    261            }
    262        }
    263
    264        private List<String> extractChannelList(Packet250CustomPayload packet)
    265        {
    266            String request = new String(packet.data, Charsets.UTF_8);
    267            List<String> channels = Lists.newArrayList(Splitter.on('\0').split(request));
    268            return channels;
    269        }
    270
    271        public void registerGuiHandler(Object mod, IGuiHandler handler)
    272        {
    273            ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod);
    274            if (mc == null)
    275            {
    276                mc = Loader.instance().activeModContainer();
    277                FMLLog.log(Level.WARNING, "Mod %s attempted to register a gui network handler during a construction phase", mc.getModId());
    278            }
    279            NetworkModHandler nmh = FMLNetworkHandler.instance().findNetworkModHandler(mc);
    280            if (nmh == null)
    281            {
    282                FMLLog.log(Level.FINE, "The mod %s needs to be a @NetworkMod to register a Networked Gui Handler", mc.getModId());
    283            }
    284            else
    285            {
    286                serverGuiHandlers.put(mc, handler);
    287            }
    288            clientGuiHandlers.put(mc, handler);
    289        }
    290        void openRemoteGui(ModContainer mc, EntityPlayerMP player, int modGuiId, World world, int x, int y, int z)
    291        {
    292            IGuiHandler handler = serverGuiHandlers.get(mc);
    293            NetworkModHandler nmh = FMLNetworkHandler.instance().findNetworkModHandler(mc);
    294            if (handler != null && nmh != null)
    295            {
    296                Container container = (Container)handler.getServerGuiElement(modGuiId, player, world, x, y, z);
    297                if (container != null)
    298                {
    299                    player.incrementWindowID();
    300                    player.closeInventory();
    301                    int windowId = player.currentWindowId;
    302                    Packet250CustomPayload pkt = new Packet250CustomPayload();
    303                    pkt.channel = "FML";
    304                    pkt.data = FMLPacket.makePacket(Type.GUIOPEN, windowId, nmh.getNetworkId(), modGuiId, x, y, z);
    305                    pkt.length = pkt.data.length;
    306                    player.playerNetServerHandler.sendPacketToPlayer(pkt);
    307                    player.openContainer = container;
    308                    player.openContainer.windowId = windowId;
    309                    player.openContainer.addCraftingToCrafters(player);
    310                }
    311            }
    312        }
    313        void openLocalGui(ModContainer mc, EntityPlayer player, int modGuiId, World world, int x, int y, int z)
    314        {
    315            IGuiHandler handler = clientGuiHandlers.get(mc);
    316            FMLCommonHandler.instance().showGuiScreen(handler.getClientGuiElement(modGuiId, player, world, x, y, z));
    317        }
    318        public Packet3Chat handleChat(NetHandler handler, Packet3Chat chat)
    319        {
    320            Side s = Side.CLIENT;
    321            if (handler instanceof NetServerHandler)
    322            {
    323                s = Side.SERVER;
    324            }
    325            for (IChatListener listener : chatListeners)
    326            {
    327                chat = s.isClient() ? listener.clientChat(handler, chat) : listener.serverChat(handler, chat);
    328            }
    329
    330            return chat;
    331        }
    332        public void handleTinyPacket(NetHandler handler, Packet131MapData mapData)
    333        {
    334            NetworkModHandler nmh = FMLNetworkHandler.instance().findNetworkModHandler((int)mapData.itemID);
    335            if (nmh == null)
    336            {
    337                FMLLog.info("Received a tiny packet for network id %d that is not recognised here", mapData.itemID);
    338                return;
    339            }
    340            if (nmh.hasTinyPacketHandler())
    341            {
    342                nmh.getTinyPacketHandler().handle(handler, mapData);
    343            }
    344            else
    345            {
    346                FMLLog.info("Received a tiny packet for a network mod that does not accept tiny packets %s", nmh.getContainer().getModId());
    347            }
    348        }
    349    }