package de.take_weiland.mods.commons.net; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.network.NetworkRegistry; import de.take_weiland.mods.commons.internal.FMLPacketHandlerImpl; import de.take_weiland.mods.commons.internal.SevenCommons; import de.take_weiland.mods.commons.internal.SevenCommonsLoader; import de.take_weiland.mods.commons.util.SCReflector; import net.minecraft.network.INetworkManager; import net.minecraft.network.NetLoginHandler; import net.minecraft.network.NetServerHandler; import net.minecraft.network.packet.NetHandler; import javax.annotation.ParametersAreNonnullByDefault; import java.util.logging.Logger; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndexes; /** * <p>Methods for Network related utilities and setting up your packet handling.</p> */ @ParametersAreNonnullByDefault public final class Network { /** * gets the INetworkManager associated with the given NetHandler * * @param netHandler the NetHandler to get the INetworkManager from * @return the INetworkManager */ public static INetworkManager getNetworkManager(NetHandler netHandler) { if (!netHandler.isServerHandler()) { return SevenCommons.proxy.getNetworkManagerFromClient(netHandler); } else if (netHandler instanceof NetServerHandler) { return ((NetServerHandler) netHandler).netManager; } else { return ((NetLoginHandler) netHandler).myTCPConnection; } } /** * <p>Create a new network channel that uses the custom payload packet to send packets.</p> * <p>Each of your packet types has to extend {@link de.take_weiland.mods.commons.net.ModPacket} to use this system.</p> * <p>This method must only be used during mod loading (PreInit, Init, etc. phases).</p> * <p>This method returns a {@code PacketHandlerBuilder} to enable the following fluid interface: * <code><pre> * PacketHandler myChannel = Network.newChannel("example") * .register(PacketA.class) * .register(PacketB.class) * .build(); * </pre></code></p> * @param channel the channel to use * @return a new PacketHandlerBuilder for registering your Packet classes */ public static PacketHandlerBuilder newChannel(String channel) { ModContainer mc = Loader.instance().activeModContainer(); if (mc == null) { throw new IllegalStateException("Tried to register a packet channel outside of mod-loading!"); } return new PacketHandlerBuilder(checkChannel(mc.getModId(), channel)); } private static String checkChannel(String activeMod, String channel) { checkNotNull(channel, "Channel cannot be null"); checkArgument(!channel.isEmpty() && channel.length() <= 16, "Invalid channel name"); checkArgument(!isReserved(channel), "Reserved channel"); if (isRegistered(channel)) { logger.warning(String.format("Channel %s is already registered while registering it for %s!", channel, activeMod)); } return channel; } private static boolean isRegistered(String channel) { NetworkRegistry nr = NetworkRegistry.instance(); SCReflector r = SCReflector.instance; return r.getUniversalPacketHandlers(nr).containsKey(channel) || r.getClientPacketHandlers(nr).containsKey(channel) || r.getServerPacketHandlers(nr).containsKey(channel); } private static boolean isReserved(String channel) { return channel.equals("REGISTER") || channel.equals("UNREGISTER") || channel.startsWith("MC|"); } /** * <p>Create a new MCDataInputStream that reads from the given byte array.</p> * @param buf the array to read from * @return an MCDataInputStream */ public static MCDataInput newDataInput(byte[] buf) { return newDataInput(buf, 0, buf.length); } /** * <p>Create a new MCDataInputStream that reads at most {@code len} bytes from the given byte array, starting at position * {@code pos}.</p> * @param buf the array to read from * @param off the starting position * @param len the number of bytes to read * @return an MCDataInputStream */ public static MCDataInput newDataInput(byte[] buf, int off, int len) { checkArgument(len >= 0, "len must be >= 0"); checkArgument(off >= 0, "off must be >= 0"); checkPositionIndexes(off, off + len, checkNotNull(buf, "buf").length); return new MCDataInputImpl(buf, off, len); } /** * <p>Create a new MCDataOutputStream with a default initial capacity.</p> * @return an MCDataOutputStream */ public static MCDataOutput newDataOutput() { return newDataOutput(FMLPacketHandlerImpl.STREAMS_INITIAL_CAP); } /** * <p>Create a new MCDataOutputStream with the given initial capacity.</p> * @param initialCapacity the initial capacity for the backing byte array * @return an MCDataOuputStream */ public static MCDataOutput newDataOutput(int initialCapacity) { checkArgument(initialCapacity >= 0, "initialCapacity must be >= 0"); final int initialCap = initialCapacity; return new MCDataOutputImpl(initialCap); } static final Logger logger = SevenCommonsLoader.scLogger("Packet System"); private Network() { } }