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 }