From a5e718bb16cb51965f64fc0611a1682ca6b0b0c9 Mon Sep 17 00:00:00 2001 From: Vexatos Date: Fri, 3 Feb 2017 17:39:15 +0100 Subject: [PATCH] Allow debug cards to send messages to one another and text to a player's clipboard. Also added a command for sending messages to a debug card. Closes #2253. --- .../opencomputers/doc/en_US/item/debugCard.md | 2 + .../li/cil/oc/client/PacketHandler.scala | 5 ++ .../scala/li/cil/oc/server/PacketSender.scala | 8 +++ .../oc/server/command/CommandHandler.scala | 1 + .../command/SendDebugMessageCommand.scala | 26 +++++++++ .../cil/oc/server/component/DebugCard.scala | 57 ++++++++++++++++--- .../cil/oc/server/network/DebugNetwork.scala | 25 ++++++++ 7 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 src/main/scala/li/cil/oc/server/command/SendDebugMessageCommand.scala create mode 100644 src/main/scala/li/cil/oc/server/network/DebugNetwork.scala diff --git a/src/main/resources/assets/opencomputers/doc/en_US/item/debugCard.md b/src/main/resources/assets/opencomputers/doc/en_US/item/debugCard.md index 624803cac..aa35df5a7 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/item/debugCard.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/item/debugCard.md @@ -5,3 +5,5 @@ The debug card is a creative-only item that was originally only intended to make debugging things easier, by automating some processes. It has since gotten a bunch more functionality, making it quite useful for custom map-making. Note that you can use sneak-activate while holding the card to bind it to you or unbind it, meaning `runCommand` will be performed using your permission levels instead of the default OpenComputers ones. + +A debug card can receive messages similar to a [linked card](linkedCard.md), firing a `debug_message` event. You can send such a message using either another debug card's `sendDebugMessage` or the Minecraft command `/oc_sendDebugMessage` (or `/oc_sdbg`). diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 0f55229b1..6cc0ac44a 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -46,6 +46,7 @@ object PacketHandler extends CommonPacketHandler { case PacketType.Analyze => onAnalyze(p) case PacketType.ChargerState => onChargerState(p) case PacketType.ClientLog => onClientLog(p) + case PacketType.Clipboard => onClipboard(p) case PacketType.ColorChange => onColorChange(p) case PacketType.ComputerState => onComputerState(p) case PacketType.ComputerUserList => onComputerUserList(p) @@ -133,6 +134,10 @@ object PacketHandler extends CommonPacketHandler { OpenComputers.log.info(p.readUTF()) } + def onClipboard(p: PacketParser) { + GuiScreen.setClipboardString(p.readUTF()) + } + def onColorChange(p: PacketParser) = p.readTileEntity[Colored]() match { case Some(t) => diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index c5359e2cf..9ccc93ac9 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -67,6 +67,14 @@ object PacketSender { pb.sendToPlayer(player) } + def sendClipboard(player: EntityPlayerMP, text: String) { + val pb = new SimplePacketBuilder(PacketType.Clipboard) + + pb.writeUTF(text) + + pb.sendToPlayer(player) + } + def sendColorChange(t: Colored) { val pb = new SimplePacketBuilder(PacketType.ColorChange) diff --git a/src/main/scala/li/cil/oc/server/command/CommandHandler.scala b/src/main/scala/li/cil/oc/server/command/CommandHandler.scala index 509e7d3a8..d728eaeaa 100644 --- a/src/main/scala/li/cil/oc/server/command/CommandHandler.scala +++ b/src/main/scala/li/cil/oc/server/command/CommandHandler.scala @@ -11,5 +11,6 @@ object CommandHandler { e.registerServerCommand(WirelessRenderingCommand) e.registerServerCommand(SpawnComputerCommand) e.registerServerCommand(DebugWhitelistCommand) + e.registerServerCommand(SendDebugMessageCommand) } } diff --git a/src/main/scala/li/cil/oc/server/command/SendDebugMessageCommand.scala b/src/main/scala/li/cil/oc/server/command/SendDebugMessageCommand.scala new file mode 100644 index 000000000..1340985b2 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/command/SendDebugMessageCommand.scala @@ -0,0 +1,26 @@ +package li.cil.oc.server.command + +import li.cil.oc.api.Network +import li.cil.oc.common.command.SimpleCommand +import li.cil.oc.server.network.DebugNetwork +import net.minecraft.command.ICommandSender +import net.minecraft.command.WrongUsageException + +object SendDebugMessageCommand extends SimpleCommand("oc_sendDebugMessage") { + aliases += "oc_sdbg" + + override def getCommandUsage(sender: ICommandSender): String = name + " [message...]" + + override def processCommand(sender: ICommandSender, args: Array[String]): Unit = { + if (args == null || args.length == 0) { + throw new WrongUsageException("no destination address specified.") + } + val destination = args(0) + DebugNetwork.getEndpoint(destination).foreach { endpoint => + val packet = Network.newPacket(sender.getCommandSenderName, destination, 0, args.drop(1).toList.toArray[AnyRef]) + endpoint.receivePacket(packet) + } + } + + override def getRequiredPermissionLevel = 2 +} diff --git a/src/main/scala/li/cil/oc/server/component/DebugCard.scala b/src/main/scala/li/cil/oc/server/component/DebugCard.scala index 99ade4b53..a1be1d594 100644 --- a/src/main/scala/li/cil/oc/server/component/DebugCard.scala +++ b/src/main/scala/li/cil/oc/server/component/DebugCard.scala @@ -12,10 +12,14 @@ import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.api.network.Environment import li.cil.oc.api.network.Node +import li.cil.oc.api.network.Packet import li.cil.oc.api.network.SidedEnvironment import li.cil.oc.api.network.Visibility import li.cil.oc.api.prefab import li.cil.oc.api.prefab.AbstractValue +import li.cil.oc.server.PacketSender +import li.cil.oc.server.network.DebugNetwork +import li.cil.oc.server.network.DebugNetwork.DebugNode import li.cil.oc.server.component.DebugCard.{AccessContext, CommandSender} import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedArguments._ @@ -44,7 +48,7 @@ import net.minecraftforge.fluids.IFluidHandler import scala.collection.convert.WrapAsScala._ import scala.collection.mutable -class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { +class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment with DebugNode { override val node = Network.newNode(this, Visibility.Neighbors). withComponent("debug"). withConnector(). @@ -190,21 +194,58 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { // ----------------------------------------------------------------------- // + @Callback(doc = """function(player:string, text:string) -- Sends text to the specified player's clipboard if possible.""") + def sendToClipboard(context: Context, args: Arguments): Array[AnyRef] = { + checkAccess() + Option(MinecraftServer.getServer.getConfigurationManager.func_152612_a(args.checkString(0))) match { + case Some(player) => + PacketSender.sendClipboard(player, args.checkString(1)) + result(true) + case _ => + result(false, "no such player") + } + } + + @Callback(doc = """function(address:string, data...) -- Sends data to the debug card with the specified address.""") + def sendToDebugCard(context: Context, args: Arguments): Array[AnyRef] = { + checkAccess() + val destination = args.checkString(0) + DebugNetwork.getEndpoint(destination).filter(_ != this).foreach{endpoint => + // Cast to iterable to use Scala's toArray instead of the Arguments' one (which converts byte arrays to Strings). + val packet = Network.newPacket(node.address, destination, 0, args.drop(1).asInstanceOf[java.lang.Iterable[AnyRef]].toArray) + endpoint.receivePacket(packet) + } + result() + } + + override def receivePacket(packet: Packet) { + val distance = 0 + node.sendToReachable("computer.signal", Seq("debug_message", packet.source, Int.box(packet.port), Double.box(distance)) ++ packet.data: _*) + } + + override def address: String = if(node != null) node.address() else "debug" + + // ----------------------------------------------------------------------- // + override def onConnect(node: Node): Unit = { super.onConnect(node) - if (node == this.node) remoteNodePosition.foreach { - case (x, y, z) => - remoteNode = findNode(x, y, z) - remoteNode match { - case Some(other) => node.connect(other) - case _ => remoteNodePosition = None - } + if (node == this.node) { + DebugNetwork.add(this) + remoteNodePosition.foreach { + case (x, y, z) => + remoteNode = findNode(x, y, z) + remoteNode match { + case Some(other) => node.connect(other) + case _ => remoteNodePosition = None + } + } } } override def onDisconnect(node: Node): Unit = { super.onDisconnect(node) if (node == this.node) { + DebugNetwork.remove(this) remoteNode.foreach(other => other.disconnect(node)) } else if (remoteNode.contains(node)) { diff --git a/src/main/scala/li/cil/oc/server/network/DebugNetwork.scala b/src/main/scala/li/cil/oc/server/network/DebugNetwork.scala new file mode 100644 index 000000000..4702e7fca --- /dev/null +++ b/src/main/scala/li/cil/oc/server/network/DebugNetwork.scala @@ -0,0 +1,25 @@ +package li.cil.oc.server.network + +import li.cil.oc.api.network.Packet + +import scala.collection.mutable + +object DebugNetwork { + val cards = mutable.WeakHashMap.empty[DebugNode, Unit] + + def add(card: DebugNode) { + cards.put(card, Unit) + } + + def remove(card: DebugNode) { + cards.remove(card) + } + + def getEndpoint(tunnel: String) = cards.keys.find(_.address == tunnel) + + trait DebugNode { + def address: String + + def receivePacket(packet: Packet): Unit + } +}