diff --git a/fml/src/main/java/cpw/mods/fml/common/network/FMLEventChannel.java b/fml/src/main/java/cpw/mods/fml/common/network/FMLEventChannel.java new file mode 100644 index 000000000..7e5267831 --- /dev/null +++ b/fml/src/main/java/cpw/mods/fml/common/network/FMLEventChannel.java @@ -0,0 +1,88 @@ +package cpw.mods.fml.common.network; + +import io.netty.channel.ChannelHandlerContext; +import java.util.EnumMap; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.NetHandlerPlayServer; +import cpw.mods.fml.common.eventhandler.EventBus; +import cpw.mods.fml.common.network.internal.FMLProxyPacket; +import cpw.mods.fml.relauncher.Side; + +public class FMLEventChannel { + private EnumMap channels; + private EventBus eventBus; + + FMLEventChannel(String name) + { + this.channels = NetworkRegistry.INSTANCE.newChannel(name, new NetworkEventFiringHandler(this)); + this.eventBus = new EventBus(); + } + + public void register(Object object) + { + this.eventBus.register(object); + } + + public void unregister(Object object) + { + this.eventBus.unregister(object); + } + + void fireRead(FMLProxyPacket msg, ChannelHandlerContext ctx) + { + FMLNetworkEvent.CustomPacketEvent event = null; + if (msg.handler() instanceof NetHandlerPlayClient) + { + NetHandlerPlayClient client = (NetHandlerPlayClient) msg.handler(); + event = new FMLNetworkEvent.ClientCustomPacketEvent(client.func_147298_b(), msg); + } + else if (msg.handler() instanceof NetHandlerPlayServer) + { + NetHandlerPlayServer server = (NetHandlerPlayServer) msg.handler(); + event = new FMLNetworkEvent.ServerCustomPacketEvent(server.func_147362_b(), msg); + } + if (event != null) + { + this.eventBus.post(event); + if (event.reply != null) + { + ctx.channel().attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.REPLY); + ctx.writeAndFlush(event.reply); + } + } + } + + public void sendToAll(FMLProxyPacket pkt) + { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL); + channels.get(Side.SERVER).writeAndFlush(pkt); + } + + public void sendTo(FMLProxyPacket pkt, EntityPlayerMP player) + { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER); + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player); + channels.get(Side.SERVER).writeAndFlush(pkt); + } + + public void sendToAllAround(FMLProxyPacket pkt, NetworkRegistry.TargetPoint point) + { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT); + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point); + channels.get(Side.SERVER).writeAndFlush(pkt); + } + + public void sendToDimension(FMLProxyPacket pkt, int dimensionId) + { + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION); + channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimensionId); + channels.get(Side.SERVER).writeAndFlush(pkt); + } + + public void sendToServer(FMLProxyPacket pkt) + { + channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER); + channels.get(Side.CLIENT).writeAndFlush(pkt); + } +} diff --git a/fml/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java b/fml/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java index 652396fee..e2f26f9bf 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/FMLNetworkEvent.java @@ -5,6 +5,8 @@ import net.minecraft.network.NetworkManager; import net.minecraft.network.play.INetHandlerPlayClient; import net.minecraft.network.play.INetHandlerPlayServer; import cpw.mods.fml.common.eventhandler.Event; +import cpw.mods.fml.common.network.internal.FMLProxyPacket; +import cpw.mods.fml.relauncher.Side; public class FMLNetworkEvent extends Event { public final T handler; @@ -49,4 +51,49 @@ public class FMLNetworkEvent extends Event { super((INetHandlerPlayClient) manager.func_150729_e(), INetHandlerPlayClient.class, manager); } } + + public static abstract class CustomPacketEvent extends FMLNetworkEvent { + /** + * The packet that generated the event + */ + public final FMLProxyPacket packet; + + /** + * Set this packet to reply to the originator + */ + public FMLProxyPacket reply; + CustomPacketEvent(S thing, Class type, NetworkManager manager, FMLProxyPacket packet) + { + super(thing, type, manager); + this.packet = packet; + } + + public abstract Side side(); + } + + public static class ClientCustomPacketEvent extends CustomPacketEvent { + public ClientCustomPacketEvent(NetworkManager manager, FMLProxyPacket packet) + { + super((INetHandlerPlayClient) manager.func_150729_e(), INetHandlerPlayClient.class, manager, packet); + } + + @Override + public Side side() + { + return Side.CLIENT; + } + } + + public static class ServerCustomPacketEvent extends CustomPacketEvent { + public ServerCustomPacketEvent(NetworkManager manager, FMLProxyPacket packet) + { + super((INetHandlerPlayServer) manager.func_150729_e(), INetHandlerPlayServer.class, manager, packet); + } + + @Override + public Side side() + { + return Side.SERVER; + } + } } diff --git a/fml/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java b/fml/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java index cb570ecbb..d2a168e18 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/FMLOutboundHandler.java @@ -31,12 +31,26 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { } @Override - public List selectNetworks(Object args) + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) { return null; } }, + REPLY + { + @Override + public void validateArgs(Object args) + { + // NOOP + } + + @Override + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) + { + return ImmutableList.of(packet.getDispatcher()); + } + }, PLAYER { @Override @@ -48,7 +62,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { } } @Override - public List selectNetworks(Object args) + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) { EntityPlayerMP player = (EntityPlayerMP) args; NetworkDispatcher dispatcher = player.field_71135_a.field_147371_a.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); @@ -63,7 +77,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { } @SuppressWarnings("unchecked") @Override - public List selectNetworks(Object args) + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) { ImmutableList.Builder builder = ImmutableList.builder(); for (EntityPlayerMP player : (List)FMLCommonHandler.instance().getMinecraftServerInstance().func_71203_ab().field_72404_b) @@ -86,7 +100,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { } @SuppressWarnings("unchecked") @Override - public List selectNetworks(Object args) + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) { int dimension = (Integer)args; ImmutableList.Builder builder = ImmutableList.builder(); @@ -114,7 +128,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { @SuppressWarnings("unchecked") @Override - public List selectNetworks(Object args) + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) { TargetPoint tp = (TargetPoint)args; ImmutableList.Builder builder = ImmutableList.builder(); @@ -144,7 +158,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { throw new RuntimeException("Cannot set TOSERVER as a target on the server"); } @Override - public List selectNetworks(Object args) + public List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet) { NetworkManager clientConnection = FMLCommonHandler.instance().getClientToServerNetworkManager(); return clientConnection == null ? ImmutableList.of() : ImmutableList.of(clientConnection.channel().attr(NetworkDispatcher.FML_DISPATCHER).get()); @@ -152,7 +166,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { }; public abstract void validateArgs(Object args); - public abstract List selectNetworks(Object args); + public abstract List selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet); } @Override @@ -162,6 +176,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { { return; } + FMLProxyPacket pkt = (FMLProxyPacket) msg; OutboundTarget outboundTarget; Object args = null; NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); @@ -182,7 +197,7 @@ public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter { outboundTarget.validateArgs(args); } - List dispatchers = outboundTarget.selectNetworks(args); + List dispatchers = outboundTarget.selectNetworks(args, ctx, pkt); // This will drop the messages into the output queue at the embedded channel if (dispatchers == null) diff --git a/fml/src/main/java/cpw/mods/fml/common/network/NetworkEventFiringHandler.java b/fml/src/main/java/cpw/mods/fml/common/network/NetworkEventFiringHandler.java new file mode 100644 index 000000000..25a118955 --- /dev/null +++ b/fml/src/main/java/cpw/mods/fml/common/network/NetworkEventFiringHandler.java @@ -0,0 +1,29 @@ +package cpw.mods.fml.common.network; + +import cpw.mods.fml.common.network.internal.FMLProxyPacket; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +/** + * Use this handler as the only thing in your channel, to receive network events + * whenever your channel receives a message. + * Note: it will not forward on to other handlers. + * + * @author cpw + * + */ +public class NetworkEventFiringHandler extends SimpleChannelInboundHandler { + private FMLEventChannel eventChannel; + + NetworkEventFiringHandler(FMLEventChannel fmlEventChannel) + { + this.eventChannel = fmlEventChannel; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FMLProxyPacket msg) throws Exception + { + eventChannel.fireRead(msg,ctx); + } + +} diff --git a/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java b/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java index b37a7ff62..8facac2e1 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java @@ -127,6 +127,10 @@ public enum NetworkRegistry return result; } + public FMLEventChannel newEventDrivenChannel(String name) + { + return new FMLEventChannel(name); + } /** * INTERNAL Create a new channel pair with the specified name and channel handlers. * This is used internally in forge and FML diff --git a/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index 07c2cd8e0..ba43bec04 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -67,7 +67,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple public static final AttributeKey FML_DISPATCHER = new AttributeKey("fml:dispatcher"); public static final AttributeKey IS_LOCAL = new AttributeKey("fml:isLocal"); - private final NetworkManager manager; + public final NetworkManager manager; private final ServerConfigurationManager scm; private EntityPlayerMP player; private ConnectionState state; @@ -259,6 +259,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple else if (NetworkRegistry.INSTANCE.hasChannel(channelName, Side.CLIENT)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); + proxy.setDispatcher(this); context.fireChannelRead(proxy); return true; } @@ -293,6 +294,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple else if (NetworkRegistry.INSTANCE.hasChannel(channelName, Side.SERVER)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); + proxy.setDispatcher(this); context.fireChannelRead(proxy); return true; } diff --git a/fml/src/main/java/cpw/mods/fml/common/network/internal/FMLProxyPacket.java b/fml/src/main/java/cpw/mods/fml/common/network/internal/FMLProxyPacket.java index 69d5f58a1..f3cd82d28 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/internal/FMLProxyPacket.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/internal/FMLProxyPacket.java @@ -3,15 +3,15 @@ package cpw.mods.fml.common.network.internal; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.embedded.EmbeddedChannel; - import java.io.IOException; - import net.minecraft.network.INetHandler; +import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.client.C17PacketCustomPayload; import net.minecraft.network.play.server.S3FPacketCustomPayload; import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.handshake.NetworkDispatcher; import cpw.mods.fml.relauncher.Side; public class FMLProxyPacket extends Packet { @@ -19,6 +19,7 @@ public class FMLProxyPacket extends Packet { private Side target; private final ByteBuf payload; private INetHandler netHandler; + private NetworkDispatcher dispatcher; private FMLProxyPacket(byte[] payload, String channel) { @@ -92,4 +93,19 @@ public class FMLProxyPacket extends Packet { { this.target = target; } + + public void setDispatcher(NetworkDispatcher networkDispatcher) + { + this.dispatcher = networkDispatcher; + } + + public NetworkManager getOrigin() + { + return this.dispatcher != null ? this.dispatcher.manager : null; + } + + public NetworkDispatcher getDispatcher() + { + return this.dispatcher; + } }