diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 2d13c36f19..b8f5b18a98 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -81,3 +81,19 @@ this.field_71424_I.func_76319_b(); this.field_71423_H = func_71386_F(); } +@@ -2046,6 +2063,7 @@ + networkmanager.func_150725_a(new C00Handshake(4, socketaddress.toString(), 0, EnumConnectionState.LOGIN), new GenericFutureListener[0]); + networkmanager.func_150725_a(new C00PacketLoginStart(this.func_110432_I().func_148256_e()), new GenericFutureListener[0]); + this.field_71453_ak = networkmanager; ++ FMLClientHandler.instance().currentConnection(networkmanager, true); + } + + public void func_71403_a(WorldClient p_71403_1_) +@@ -2076,6 +2094,7 @@ + + this.field_71451_h = null; + this.field_71453_ak = null; ++ FMLClientHandler.instance().currentConnection(null, p_71353_1_ == null); + + if (this.field_71461_s != null) + { diff --git a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java index 23bc4a305c..b151bce675 100644 --- a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java +++ b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java @@ -30,6 +30,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.launchwrapper.Launch; +import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; import net.minecraft.world.World; @@ -122,6 +123,8 @@ public class FMLClientHandler implements IFMLSidedHandler private Map resourcePackMap; + private NetworkManager networkConnection; + /** * Called to start the whole game off * @@ -564,4 +567,15 @@ public class FMLClientHandler implements IFMLSidedHandler ObfuscationReflectionHelper.setPrivateValue(MinecraftServer.class, server, true, "field_71296"+"_Q","serverIs"+"Running"); } } + + @Override + public NetworkManager getClientToServerNetworkManager() + { + return this.networkConnection; + } + + public void currentConnection(NetworkManager networkManager, boolean shouldChange) + { + if (shouldChange) this.networkConnection = networkManager; + } } diff --git a/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java b/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java index 51848fa61a..b06299f421 100644 --- a/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java +++ b/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java @@ -26,6 +26,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; import net.minecraft.world.World; import net.minecraft.world.storage.SaveHandler; @@ -490,4 +491,9 @@ public class FMLCommonHandler public void bootstrap() { } + + public NetworkManager getClientToServerNetworkManager() + { + return sidedDelegate.getClientToServerNetworkManager(); + } } diff --git a/src/main/java/cpw/mods/fml/common/FMLModContainer.java b/src/main/java/cpw/mods/fml/common/FMLModContainer.java index 7d8a63c8e0..cebec194b0 100644 --- a/src/main/java/cpw/mods/fml/common/FMLModContainer.java +++ b/src/main/java/cpw/mods/fml/common/FMLModContainer.java @@ -494,7 +494,6 @@ public class FMLModContainer implements ModContainer Method factoryMethod = gatherAnnotations(clazz); modInstance = getLanguageAdapter().getNewInstance(this,clazz, modClassLoader, factoryMethod); - isNetworkMod = FMLNetworkHandler.instance().registerNetworkMod(this, clazz, event.getASMHarvestedData()); if (fingerprintNotPresent) { eventBus.post(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints), expectedFingerprint)); diff --git a/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java b/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java index 20e37f3313..cfff05dca5 100644 --- a/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java +++ b/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java @@ -15,6 +15,7 @@ package cpw.mods.fml.common; import java.util.List; import net.minecraft.entity.Entity; +import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; import cpw.mods.fml.common.network.packet.EntitySpawnAdjustmentPacket; import cpw.mods.fml.common.network.packet.EntitySpawnPacket; @@ -53,4 +54,6 @@ public interface IFMLSidedHandler String getCurrentLanguage(); void serverStopped(); + + NetworkManager getClientToServerNetworkManager(); } diff --git a/src/main/java/cpw/mods/fml/common/Loader.java b/src/main/java/cpw/mods/fml/common/Loader.java index c3b6b9013f..58f93eaf71 100644 --- a/src/main/java/cpw/mods/fml/common/Loader.java +++ b/src/main/java/cpw/mods/fml/common/Loader.java @@ -564,9 +564,9 @@ public class Loader return ""; } StringBuilder ret = new StringBuilder(); - List branding = FMLCommonHandler.instance().getBrandings(); + List branding = FMLCommonHandler.instance().getBrandings(false); - Joiner.on(' ').skipNulls().appendTo(ret, branding.subList(1, branding.size())); + Joiner.on(' ').skipNulls().appendTo(ret, branding); if (modController != null) { modController.printModStates(ret); diff --git a/src/main/java/cpw/mods/fml/common/ModContainer.java b/src/main/java/cpw/mods/fml/common/ModContainer.java index c92de9f75a..ee837ff62f 100644 --- a/src/main/java/cpw/mods/fml/common/ModContainer.java +++ b/src/main/java/cpw/mods/fml/common/ModContainer.java @@ -141,6 +141,4 @@ public interface ModContainer public Class getCustomResourcePackClass(); Map getSharedModDescriptor(); - - NetworkModHolder getNetworkModHolder(); } diff --git a/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java b/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java index b98230bd8a..947664e03c 100644 --- a/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java +++ b/src/main/java/cpw/mods/fml/common/network/FMLIndexedMessageToMessageCodec.java @@ -7,8 +7,10 @@ import gnu.trove.map.hash.TObjectByteHashMap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelHandler.Sharable; import io.netty.handler.codec.MessageToMessageCodec; +@Sharable public abstract class FMLIndexedMessageToMessageCodec extends MessageToMessageCodec { private TByteObjectHashMap> discriminators = new TByteObjectHashMap>(); private TObjectByteHashMap> types = new TObjectByteHashMap>(); diff --git a/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java b/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java new file mode 100644 index 0000000000..80b7427e06 --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java @@ -0,0 +1,42 @@ +package cpw.mods.fml.common.network; + +import java.util.List; + +import cpw.mods.fml.common.network.NetworkRegistry.OutboundTarget; +import cpw.mods.fml.common.network.handshake.NetworkDispatcher; +import cpw.mods.fml.relauncher.Side; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; + +public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception + { + if (!(msg instanceof FMLProxyPacket)) + { + return; + } + OutboundTarget outboundTarget; + Object args = null; + if (ctx.channel().attr(NetworkRegistry.CHANNEL_SOURCE).get() == Side.CLIENT) + { + outboundTarget = OutboundTarget.TOSERVER; + } + else + { + outboundTarget = ctx.channel().attr(NetworkRegistry.FML_MESSAGETARGET).get(); + args = ctx.channel().attr(NetworkRegistry.FML_MESSAGETARGETARGS).get(); + + outboundTarget.validateArgs(args); + } + List dispatchers = outboundTarget.selectNetworks(args); + + for (NetworkDispatcher dispatcher : dispatchers) + { + dispatcher.sendProxy((FMLProxyPacket) msg); + } + + } + +} diff --git a/src/main/java/cpw/mods/fml/common/network/FMLProxyPacket.java b/src/main/java/cpw/mods/fml/common/network/FMLProxyPacket.java index 412aaca1ae..3dd78e2d29 100644 --- a/src/main/java/cpw/mods/fml/common/network/FMLProxyPacket.java +++ b/src/main/java/cpw/mods/fml/common/network/FMLProxyPacket.java @@ -6,6 +6,8 @@ import io.netty.channel.embedded.EmbeddedChannel; import java.io.IOException; +import cpw.mods.fml.relauncher.Side; + import net.minecraft.network.INetHandler; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; @@ -14,6 +16,7 @@ import net.minecraft.network.play.server.S3FPacketCustomPayload; public class FMLProxyPacket extends Packet { final String channel; + private Side target; private final ByteBuf payload; private INetHandler netHandler; @@ -25,11 +28,13 @@ public class FMLProxyPacket extends Packet { public FMLProxyPacket(S3FPacketCustomPayload original) { this(original.func_149168_d(), original.func_149169_c()); + this.target = Side.CLIENT; } public FMLProxyPacket(C17PacketCustomPayload original) { this(original.func_149558_e(), original.func_149559_c()); + this.target = Side.SERVER; } public FMLProxyPacket(ByteBuf payload, String channel) @@ -53,7 +58,7 @@ public class FMLProxyPacket extends Packet { public void func_148833_a(INetHandler inethandler) { this.netHandler = inethandler; - EmbeddedChannel internalChannel = NetworkRegistry.INSTANCE.getChannel(this.channel); + EmbeddedChannel internalChannel = NetworkRegistry.INSTANCE.getChannel(this.channel, this.target); if (internalChannel != null) { internalChannel.writeInbound(this); diff --git a/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java b/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java index c56b32780f..447e905776 100644 --- a/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java +++ b/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java @@ -12,23 +12,30 @@ package cpw.mods.fml.common.network; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.MessageToMessageCodec; import io.netty.util.AttributeKey; import java.util.EnumMap; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.logging.Level; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.NetworkManager; import net.minecraft.world.World; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.network.handshake.NetworkDispatcher; import cpw.mods.fml.relauncher.Side; /** @@ -38,7 +45,7 @@ import cpw.mods.fml.relauncher.Side; public enum NetworkRegistry { INSTANCE; - private Map channels = Maps.newConcurrentMap(); + private EnumMap> channels = Maps.newEnumMap(Side.class); private Map serverGuiHandlers = Maps.newHashMap(); private Map clientGuiHandlers = Maps.newHashMap(); @@ -46,6 +53,7 @@ public enum NetworkRegistry * Set in the {@link ChannelHandlerContext} */ public static final AttributeKey FML_CHANNEL = new AttributeKey("fml:channelName"); + public static final AttributeKey CHANNEL_SOURCE = new AttributeKey("fml:channelSource"); public static final AttributeKey FML_MESSAGETARGET = new AttributeKey("fml:outboundTarget"); public static final AttributeKey FML_MESSAGETARGETARGS = new AttributeKey("fml:outboundTargetArgs"); @@ -53,35 +61,200 @@ public enum NetworkRegistry private NetworkRegistry() { + channels.put(Side.CLIENT, Maps.newConcurrentMap()); + channels.put(Side.SERVER, Maps.newConcurrentMap()); } + public class TargetPoint { + public TargetPoint(int dimension, double x, double y, double z, double range) + { + this.x = x; + this.y = y; + this.z = z; + this.range = range; + this.dimension = dimension; + } + public final double x; + public final double y; + public final double z; + public final double range; + public final int dimension; + } public enum OutboundTarget { - PLAYER, ALL, DIMENSION, ALLAROUNDPOINT; + PLAYER + { + @Override + public void validateArgs(Object args) + { + if (!(args instanceof EntityPlayerMP)) + { + throw new RuntimeException("PLAYER target expects a Player arg"); + } + } + @Override + public List selectNetworks(Object args) + { + EntityPlayerMP player = (EntityPlayerMP) args; + NetworkDispatcher dispatcher = player.field_71135_a.field_147371_a.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); + return ImmutableList.of(dispatcher); + } + }, + ALL + { + @Override + public void validateArgs(Object args) + { + } + @SuppressWarnings("unchecked") + @Override + public List selectNetworks(Object args) + { + ImmutableList.Builder builder = ImmutableList.builder(); + for (EntityPlayerMP player : (List)FMLCommonHandler.instance().getMinecraftServerInstance().func_71203_ab().field_72404_b) + { + NetworkDispatcher dispatcher = player.field_71135_a.field_147371_a.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); + builder.add(dispatcher); + } + return builder.build(); + } + }, + DIMENSION + { + @Override + public void validateArgs(Object args) + { + if (!(args instanceof Integer)) + { + throw new RuntimeException("DIMENSION expects an integer argument"); + } + } + @SuppressWarnings("unchecked") + @Override + public List selectNetworks(Object args) + { + int dimension = (Integer)args; + ImmutableList.Builder builder = ImmutableList.builder(); + for (EntityPlayerMP player : (List)FMLCommonHandler.instance().getMinecraftServerInstance().func_71203_ab().field_72404_b) + { + if (dimension == player.field_71093_bK) + { + NetworkDispatcher dispatcher = player.field_71135_a.field_147371_a.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); + builder.add(dispatcher); + } + } + return builder.build(); + } + }, + ALLAROUNDPOINT + { + @Override + public void validateArgs(Object args) + { + if (!(args instanceof TargetPoint)) + { + throw new RuntimeException("ALLAROUNDPOINT expects a TargetPoint argument"); + } + } + + @SuppressWarnings("unchecked") + @Override + public List selectNetworks(Object args) + { + TargetPoint tp = (TargetPoint)args; + ImmutableList.Builder builder = ImmutableList.builder(); + for (EntityPlayerMP player : (List)FMLCommonHandler.instance().getMinecraftServerInstance().func_71203_ab().field_72404_b) + { + if (player.field_71093_bK == tp.dimension) + { + double d4 = tp.x - player.field_70165_t; + double d5 = tp.y - player.field_70163_u; + double d6 = tp.z - player.field_70161_v; + + if (d4 * d4 + d5 * d5 + d6 * d6 < tp.range * tp.range) + { + NetworkDispatcher dispatcher = player.field_71135_a.field_147371_a.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); + builder.add(dispatcher); + } + } + } + return builder.build(); + } + }, + TOSERVER + { + @Override + public void validateArgs(Object args) + { + throw new RuntimeException("Cannot set TOSERVER as a target on the server"); + } + @Override + public List selectNetworks(Object args) + { + NetworkManager clientConnection = FMLCommonHandler.instance().getClientToServerNetworkManager(); + return clientConnection == null ? ImmutableList.of() : ImmutableList.of(clientConnection.channel().attr(NetworkDispatcher.FML_DISPATCHER).get()); + } + }; + + public abstract void validateArgs(Object args); + public abstract List selectNetworks(Object args); } static class FMLEmbeddedChannel extends EmbeddedChannel { - private final String channelName; - public FMLEmbeddedChannel(String channelName) + public FMLEmbeddedChannel(String channelName, Side source, ChannelHandler... handlers) { - super(); - this.channelName = channelName; + super(handlers); + this.attr(FML_CHANNEL).set(channelName); + this.attr(CHANNEL_SOURCE).set(source); + this.pipeline().addFirst(new FMLOutboundHandler()); } } - public EmbeddedChannel newChannel(String name) + /** + * Create a new synchronous message channel pair based on netty. + * There are two channels created : one for each logical side (considered as the source of an outbound message) + * The returned map will contain a value for each logical side, though both will only be working in the + * integrated server case. + * + * The channel expects to read and write using {@link FMLProxyPacket}. All operation is synchronous, as the + * asynchronous behaviour occurs at a lower level in netty. + * + * The first handler in the pipeline is special and should not be removed or moved from the head - it transforms + * packets from the outbound of this pipeline into custom packets, based on the current {@link AttributeKey} value + * {@link NetworkRegistry#FML_MESSAGETARGET} and {@link NetworkRegistry#FML_MESSAGETARGETARGS} set on the channel. + * For the client to server channel (source side : CLIENT) this is fixed as "TOSERVER". For SERVER to CLIENT packets, + * several possible values exist. + * + * Mod Messages should be transformed using a something akin to a {@link MessageToMessageCodec}. FML provides + * a utility codec, {@link FMLIndexedMessageToMessageCodec} that transforms from {@link FMLProxyPacket} to a mod + * message using a message discriminator byte. This is optional, but highly recommended for use. + * + * Note also that the handlers supplied need to be {@link ChannelHandler.Shareable} - they are injected into two + * channels. + * + * @param name + * @param handlers + * @return + */ + public EnumMap newChannel(String name, ChannelHandler... handlers) { - if (channels.containsKey(name) || name.startsWith("MC|") || name.startsWith("\u0001")) + if (channels.containsKey(name) || name.startsWith("MC|") || name.startsWith("\u0001") || name.startsWith("FML")) { throw new RuntimeException("That channel is already registered"); } - FMLEmbeddedChannel channel = new FMLEmbeddedChannel(name); - channels.put(name,channel); - return channel; + EnumMap result = Maps.newEnumMap(Side.class); + + for (Side side : Side.values()) + { + FMLEmbeddedChannel channel = new FMLEmbeddedChannel(name, side, handlers); + channels.get(side).put(name,channel); + result.put(side, channel); + } + return result; } - public EmbeddedChannel getChannel(String name) + public EmbeddedChannel getChannel(String name, Side source) { - return channels.get(name); + return channels.get(source).get(name); } /* *//** @@ -295,18 +468,10 @@ public enum NetworkRegistry ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod); if (mc == null) { - FMLLog.log(Level.SEVERE, "Mod %s attempted to register a gui network handler during a construction phase", mc.getModId()); + FMLLog.log(Level.SEVERE, "Mod of type %s attempted to register a gui network handler during a construction phase", mod.getClass().getName()); throw new RuntimeException("Invalid attempt to create a GUI during mod construction. Use an EventHandler instead"); } - NetworkModHolder nmh = mc.getNetworkModHolder(); - if (nmh == null) - { - FMLLog.log(Level.FINE, "The mod %s needs to be a @NetworkMod to register a Networked Gui Handler", mc.getModId()); - } - else - { - serverGuiHandlers.put(mc, handler); - } + serverGuiHandlers.put(mc, handler); clientGuiHandlers.put(mc, handler); } /* void openRemoteGui(ModContainer mc, EntityPlayerMP player, int modGuiId, World world, int x, int y, int z) @@ -335,8 +500,8 @@ public enum NetworkRegistry FMLCommonHandler.instance().showGuiScreen(handler.getClientGuiElement(modGuiId, player, world, x, y, z)); } - public boolean hasChannel(String channelName) + public boolean hasChannel(String channelName, Side source) { - return channels.containsKey(channelName); + return channels.get(source).containsKey(channelName); } } diff --git a/src/main/java/cpw/mods/fml/common/network/NetworkSide.java b/src/main/java/cpw/mods/fml/common/network/NetworkSide.java deleted file mode 100644 index 05679a00be..0000000000 --- a/src/main/java/cpw/mods/fml/common/network/NetworkSide.java +++ /dev/null @@ -1,26 +0,0 @@ -package cpw.mods.fml.common.network; - -import cpw.mods.fml.relauncher.Side; - -public abstract class NetworkSide { - public static final ServerSide SERVER = new ServerSide(); - public static final ClientSide CLIENT = new ClientSide(); - public final Side side; - NetworkSide(Side side) { - this.side = side; - } - - public static final class ServerSide extends NetworkSide { - private ServerSide() - { - super(Side.SERVER); - } - } - - public static final class ClientSide extends NetworkSide { - private ClientSide() - { - super(Side.CLIENT); - } - } -} diff --git a/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java b/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java index b91b7be10f..31b06cc44b 100644 --- a/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java +++ b/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java @@ -1,17 +1,15 @@ package cpw.mods.fml.common.network.handshake; +import io.netty.buffer.ByteBuf; + import java.util.List; -import com.google.common.base.Joiner; import com.google.common.collect.Lists; -import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.NetworkRegistry; -import io.netty.buffer.ByteBuf; - public abstract class FMLHandshakeMessage { public static class ServerHello extends FMLHandshakeMessage { private byte serverProtocolVersion; diff --git a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index 1bd8434b23..56039f8be9 100644 --- a/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -207,7 +207,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler { handshakeChannel.writeInbound(proxy); return true; } - else if (NetworkRegistry.INSTANCE.hasChannel(channelName)) + else if (NetworkRegistry.INSTANCE.hasChannel(channelName, Side.CLIENT)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); context.fireChannelRead(proxy); @@ -230,7 +230,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler { handshakeChannel.writeInbound(proxy); return true; } - else if (NetworkRegistry.INSTANCE.hasChannel(channelName)) + else if (NetworkRegistry.INSTANCE.hasChannel(channelName, Side.SERVER)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); context.fireChannelRead(proxy); diff --git a/src/main/java/cpw/mods/fml/server/FMLServerHandler.java b/src/main/java/cpw/mods/fml/server/FMLServerHandler.java index 96e267436b..e0622d2d79 100644 --- a/src/main/java/cpw/mods/fml/server/FMLServerHandler.java +++ b/src/main/java/cpw/mods/fml/server/FMLServerHandler.java @@ -23,6 +23,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import net.minecraft.entity.Entity; +import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; import net.minecraft.util.StringTranslate; @@ -234,4 +235,9 @@ public class FMLServerHandler implements IFMLSidedHandler { // NOOP } + @Override + public NetworkManager getClientToServerNetworkManager() + { + throw new RuntimeException("Missing"); + } }