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