From 03d9b0fef075697af44bdc4d21494df8dc04ec53 Mon Sep 17 00:00:00 2001 From: bdew Date: Tue, 29 Jul 2014 12:43:53 +0300 Subject: [PATCH] Rewrote networking system (experimental) --- build.gradle | 2 +- src/net/bdew/lib/network/Message.scala | 12 +++++ src/net/bdew/lib/network/NetChannel.scala | 50 +++++++++---------- .../lib/network/NetChannelClientHandler.scala | 18 ++++--- .../lib/network/NetChannelServerHandler.scala | 24 +++++---- ...dec.scala => SerializedMessageCodec.scala} | 25 +++++----- 6 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 src/net/bdew/lib/network/Message.scala rename src/net/bdew/lib/network/{NBTMessageToMessageCodec.scala => SerializedMessageCodec.scala} (65%) diff --git a/build.gradle b/build.gradle index f35a994..7d833b1 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { apply plugin: 'scala' apply plugin: 'forge' -version = "1.4.0" +version = "1.4.1" if (project.hasProperty('buildnum')) { project.version = project.version + '.' + project.buildnum diff --git a/src/net/bdew/lib/network/Message.scala b/src/net/bdew/lib/network/Message.scala new file mode 100644 index 0000000..abd2392 --- /dev/null +++ b/src/net/bdew/lib/network/Message.scala @@ -0,0 +1,12 @@ +/* + * Copyright (c) bdew, 2013 - 2014 + * https://github.com/bdew/bdlib + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt + */ + +package net.bdew.lib.network + +abstract class Message extends Serializable diff --git a/src/net/bdew/lib/network/NetChannel.scala b/src/net/bdew/lib/network/NetChannel.scala index 797013d..6207b9c 100644 --- a/src/net/bdew/lib/network/NetChannel.scala +++ b/src/net/bdew/lib/network/NetChannel.scala @@ -9,63 +9,63 @@ package net.bdew.lib.network -import cpw.mods.fml.common.network.{FMLOutboundHandler, NetworkRegistry} +import java.util + +import cpw.mods.fml.common.network.{FMLEmbeddedChannel, FMLOutboundHandler, NetworkRegistry} import cpw.mods.fml.relauncher.Side -import net.minecraft.nbt.NBTTagCompound +import io.netty.channel.{ChannelFutureListener, ChannelHandler} +import net.bdew.lib.{BdLib, Misc} import net.minecraft.entity.player.EntityPlayerMP -import io.netty.channel.{ChannelHandler, ChannelFutureListener} class NetChannel(val name: String) { - val channels = NetworkRegistry.INSTANCE.newChannel(name, new NBTMessageToMessageCodec) + var channels: util.EnumMap[Side, FMLEmbeddedChannel] = null - var serverHandlers = Map.empty[String, (NBTTagCompound, EntityPlayerMP) => Unit] - var clientHandlers = Map.empty[String, (NBTTagCompound) => Unit] + def init() { + channels = NetworkRegistry.INSTANCE.newChannel(name, new SerializedMessageCodec) + BdLib.logInfo("Initialized network channel '%s' for mod '%s'", name, Misc.getActiveModId) + addHandler(Side.SERVER, new NetChannelServerHandler(this)) + addHandler(Side.CLIENT, new NetChannelClientHandler(this)) + } - def regServerHandler(id: String, callable: (NBTTagCompound, EntityPlayerMP) => Unit) = - if (serverHandlers.contains(id)) - sys.error("Command name already in use: %s".format(name)) - else - serverHandlers += (id -> callable) + var clientChain = PartialFunction.empty[Message, Unit] + var serverChain = PartialFunction.empty[(Message, EntityPlayerMP), Unit] - def regClientHandler(id: String, callable: (NBTTagCompound) => Unit) = - if (clientHandlers.contains(id)) - sys.error("Command name already in use: %s".format(name)) - else - clientHandlers += (id -> callable) + def regServerHandler(f: PartialFunction[(Message, EntityPlayerMP), Unit]) = + serverChain = serverChain.orElse(f) - addHandler(Side.SERVER, new NetChannelServerHandler(this)) - addHandler(Side.CLIENT, new NetChannelClientHandler(this)) + def regClientHandler(f: PartialFunction[Message, Unit]) = + clientChain = clientChain.orElse(f) - def addHandler(side: Side, handler: ChannelHandler) { + private def addHandler(side: Side, handler: ChannelHandler) { val ch = channels.get(side) - val name = ch.findChannelHandlerNameForType(classOf[NBTMessageToMessageCodec]) + val name = ch.findChannelHandlerNameForType(classOf[SerializedMessageCodec]) ch.pipeline().addAfter(name, side + "Handler", handler) } - def sendToAll(message: NBTTagCompound) { + def sendToAll(message: Message) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL) channels.get(Side.SERVER).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE) } - def sendTo(message: NBTTagCompound, player: EntityPlayerMP) { + def sendTo(message: Message, player: EntityPlayerMP) { 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(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE) } - def sendToAllAround(message: NBTTagCompound, point: NetworkRegistry.TargetPoint) { + def sendToAllAround(message: Message, point: NetworkRegistry.TargetPoint) { 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(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE) } - def sendToDimension(message: NBTTagCompound, dimensionId: Int) { + def sendToDimension(message: Message, dimensionId: Int) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION) channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(new Integer(dimensionId)) channels.get(Side.SERVER).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE) } - def sendToServer(message: NBTTagCompound) { + def sendToServer(message: Message) { channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER) channels.get(Side.CLIENT).writeAndFlush(message).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE) } diff --git a/src/net/bdew/lib/network/NetChannelClientHandler.scala b/src/net/bdew/lib/network/NetChannelClientHandler.scala index d52aca2..e9a829a 100644 --- a/src/net/bdew/lib/network/NetChannelClientHandler.scala +++ b/src/net/bdew/lib/network/NetChannelClientHandler.scala @@ -10,15 +10,17 @@ package net.bdew.lib.network import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} -import net.minecraft.nbt.NBTTagCompound import net.bdew.lib.BdLib -class NetChannelClientHandler(ch: NetChannel) extends SimpleChannelInboundHandler[NBTTagCompound] { - def channelRead0(ctx: ChannelHandlerContext, msg: NBTTagCompound) { - val cmd = msg.getString("_cmd") - ch.clientHandlers.getOrElse(cmd, { - BdLib.log.error("Unknown command: '%s' from server".format(cmd)) - return - })(msg) +class NetChannelClientHandler(ch: NetChannel) extends SimpleChannelInboundHandler[Message] { + def channelRead0(ctx: ChannelHandlerContext, msg: Message) { + try { + if (ch.clientChain.isDefinedAt(msg)) + ch.clientChain(msg) + else + BdLib.logWarn("Unable to handle message from server: %s", msg) + } catch { + case e: Throwable => BdLib.logErrorException("Error handling packet", e) + } } } diff --git a/src/net/bdew/lib/network/NetChannelServerHandler.scala b/src/net/bdew/lib/network/NetChannelServerHandler.scala index b743e9c..e1915f1 100644 --- a/src/net/bdew/lib/network/NetChannelServerHandler.scala +++ b/src/net/bdew/lib/network/NetChannelServerHandler.scala @@ -9,19 +9,21 @@ package net.bdew.lib.network -import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} -import net.minecraft.nbt.NBTTagCompound import cpw.mods.fml.common.network.NetworkRegistry -import net.minecraft.network.NetHandlerPlayServer +import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} import net.bdew.lib.BdLib +import net.minecraft.network.NetHandlerPlayServer -class NetChannelServerHandler(ch: NetChannel) extends SimpleChannelInboundHandler[NBTTagCompound] { - def channelRead0(ctx: ChannelHandlerContext, msg: NBTTagCompound) { - val cmd = msg.getString("_cmd") - val nh = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get.asInstanceOf[NetHandlerPlayServer].playerEntity - ch.serverHandlers.getOrElse(cmd, { - BdLib.log.error("Unknown command: '%s' from '%s'".format(cmd, nh.getCommandSenderName)) - return - })(msg, nh) +class NetChannelServerHandler(ch: NetChannel) extends SimpleChannelInboundHandler[Message] { + def channelRead0(ctx: ChannelHandlerContext, msg: Message) { + try { + val player = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get.asInstanceOf[NetHandlerPlayServer].playerEntity + if (ch.serverChain.isDefinedAt(msg, player)) + ch.serverChain(msg, player) + else + BdLib.logWarn("Unable to handle message from user %s: %s", player.getDisplayName, msg) + } catch { + case e: Throwable => BdLib.logErrorException("Error handling packet", e) + } } } diff --git a/src/net/bdew/lib/network/NBTMessageToMessageCodec.scala b/src/net/bdew/lib/network/SerializedMessageCodec.scala similarity index 65% rename from src/net/bdew/lib/network/NBTMessageToMessageCodec.scala rename to src/net/bdew/lib/network/SerializedMessageCodec.scala index 4db2ed9..8da08e5 100644 --- a/src/net/bdew/lib/network/NBTMessageToMessageCodec.scala +++ b/src/net/bdew/lib/network/SerializedMessageCodec.scala @@ -9,30 +9,31 @@ package net.bdew.lib.network -import io.netty.handler.codec.MessageToMessageCodec -import cpw.mods.fml.common.network.internal.FMLProxyPacket -import net.minecraft.nbt.{CompressedStreamTools, NBTTagCompound} -import io.netty.channel.ChannelHandlerContext +import java.io.{ObjectInputStream, ObjectOutputStream} import java.util -import java.io.{DataInputStream, DataOutputStream} -import io.netty.buffer.{ByteBufInputStream, ByteBufOutputStream, Unpooled} + import cpw.mods.fml.common.network.NetworkRegistry +import cpw.mods.fml.common.network.internal.FMLProxyPacket +import io.netty.buffer.{ByteBufInputStream, ByteBufOutputStream, Unpooled} import io.netty.channel.ChannelHandler.Sharable +import io.netty.channel.ChannelHandlerContext +import io.netty.handler.codec.MessageToMessageCodec import net.bdew.lib.BdLib @Sharable -class NBTMessageToMessageCodec extends MessageToMessageCodec[FMLProxyPacket, NBTTagCompound] { - def encode(ctx: ChannelHandlerContext, msg: NBTTagCompound, out: util.List[AnyRef]) { +class SerializedMessageCodec extends MessageToMessageCodec[FMLProxyPacket, Message] { + def encode(ctx: ChannelHandlerContext, msg: Message, out: util.List[AnyRef]) { val buff = Unpooled.buffer() - val writer = new DataOutputStream(new ByteBufOutputStream(buff)) - CompressedStreamTools.write(msg, writer) + val writer = new ObjectOutputStream(new ByteBufOutputStream(buff)) + writer.writeObject(msg) val pkt = new FMLProxyPacket(buff, ctx.channel.attr(NetworkRegistry.FML_CHANNEL).get) out.add(pkt) } + def decode(ctx: ChannelHandlerContext, msg: FMLProxyPacket, out: util.List[AnyRef]) { try { - val stream = new DataInputStream(new ByteBufInputStream(msg.payload())) - out.add(CompressedStreamTools.read(stream)) + val reader = new ObjectInputStream(new ByteBufInputStream(msg.payload())) + out.add(reader.readObject()) } catch { case e: Throwable => BdLib.log.error("Error decoding packet", e) }