From 0285d4bfda942471496faac96833322d6b6d5760 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 14 Aug 2015 14:36:18 +0200 Subject: [PATCH 1/2] Change usage of gitref in versioning As git ref hash can't be used to order versions it should be only used to denote differences between them. By using plus sign instead of hyphen many version compression scripts and similar will stop confusing custom build versions. It is also then compatible with SemVer version 2 ordering rules as for point 10 and 11. It also was moved at the end so it is more obvious that it a metadata. http://semver.org --- build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 534615fb7..e688714dd 100644 --- a/build.gradle +++ b/build.gradle @@ -45,12 +45,13 @@ def getGitRef() { if (System.getenv("BUILD_NUMBER") != null) version += ".${System.getenv("BUILD_NUMBER")}" -else - version += "-" + getGitRef() if (config.oc.subversion != null && config.oc.subversion != "") version += "-${config.oc.subversion}" +if (System.getenv("BUILD_NUMBER") == null) + version += "+" + getGitRef() + ext.simpleVersion = version version = "MC${config.minecraft.version}-${project.version}" From 54b7019a1174eecd86d025a045a19cdc17b778fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 23 Aug 2015 21:43:30 +0200 Subject: [PATCH 2/2] Added relay block to replace switch and access point; has slot for wlan card or linked card to upgrade accordingly. Closes #1334. --- .../doc/en_US/block/accessPoint.md | 2 + .../opencomputers/doc/en_US/block/index.md | 3 +- .../doc/en_US/block/netSplitter.md | 2 +- .../opencomputers/doc/en_US/block/relay.md | 13 + .../doc/en_US/block/serverRack.md | 2 +- .../opencomputers/doc/en_US/block/switch.md | 2 + .../opencomputers/doc/en_US/item/lanCard.md | 2 +- .../assets/opencomputers/lang/en_US.lang | 7 +- .../opencomputers/recipes/default.recipes | 9 +- .../opencomputers/recipes/gregtech.recipes | 4 +- .../opencomputers/recipes/hardmode.recipes | 4 +- .../textures/gui/upgrade_tab.png | Bin 0 -> 185 bytes src/main/scala/li/cil/oc/Constants.scala | 1 + .../scala/li/cil/oc/client/GuiHandler.scala | 10 +- .../li/cil/oc/client/PacketHandler.scala | 2 +- src/main/scala/li/cil/oc/client/Proxy.scala | 1 + .../scala/li/cil/oc/client/Textures.scala | 1 + .../scala/li/cil/oc/client/gui/Relay.scala | 122 ++++++++ .../scala/li/cil/oc/client/gui/Switch.scala | 1 + .../renderer/tileentity/SwitchRenderer.scala | 2 +- .../scala/li/cil/oc/common/GuiHandler.scala | 2 + src/main/scala/li/cil/oc/common/GuiType.scala | 1 + .../li/cil/oc/common/InventorySlots.scala | 7 + .../li/cil/oc/common/block/AccessPoint.scala | 1 + .../scala/li/cil/oc/common/block/Relay.scala | 34 +++ .../scala/li/cil/oc/common/block/Switch.scala | 1 + .../li/cil/oc/common/container/Relay.scala | 33 ++ .../li/cil/oc/common/container/Switch.scala | 1 + .../scala/li/cil/oc/common/init/Blocks.scala | 6 +- .../li/cil/oc/common/recipe/Recipes.scala | 6 + .../oc/common/tileentity/AccessPoint.scala | 5 +- .../li/cil/oc/common/tileentity/Relay.scala | 282 ++++++++++++++++++ .../li/cil/oc/common/tileentity/Switch.scala | 45 +-- .../common/tileentity/traits/SwitchLike.scala | 27 ++ .../computercraft/PeripheralProvider.scala | 4 +- .../computercraft/SwitchPeripheral.scala | 10 +- .../scala/li/cil/oc/server/PacketSender.scala | 2 +- .../cil/oc/server/component/LinkedCard.scala | 6 +- .../oc/server/network/QuantumNetwork.scala | 17 +- 39 files changed, 608 insertions(+), 72 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/doc/en_US/block/relay.md create mode 100644 src/main/resources/assets/opencomputers/textures/gui/upgrade_tab.png create mode 100644 src/main/scala/li/cil/oc/client/gui/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/block/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/container/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/tileentity/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md b/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md index 5dde0da28..78bacc26c 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md @@ -2,6 +2,8 @@ ![AAA](oredict:oc:accessPoint) +*This block is deprecated and will be removed in a future version.* Craft it into a [relay](relay.md) to avoid losing it. + The access point is the wireless version of the [switch](switch.md). It can be used to separate subnetworks so that machines in them will not see [components](../general/computer.md) in other networks, while still allowing to send network messages to the machines in other networks. In addition to that, this block can act as a repeater: it can re-send wired messages as wired messages to other devices; or wireless messages as wired or wireless messages. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/index.md b/src/main/resources/assets/opencomputers/doc/en_US/block/index.md index a33f40557..26a47e734 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/index.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/index.md @@ -36,10 +36,9 @@ Keep in mind that some of these may not be available, depending on the recipe se * [Disassembler](disassembler.md) ## Networking -* [Access Point](accessPoint.md) * [Cable](cable.md) * [Net Splitter](netSplitter.md) -* [Switch](switch.md) +* [Relay](relay.md) ## Power management * [Capacitor](capacitor.md) diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md b/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md index 230e4484f..f6c02a752 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md @@ -2,6 +2,6 @@ ![*.net *.split](oredict:oc:netSplitter) -The net splitter is a device that allows controlling connectivity between subnetworks. Unlike the [switch](switch.md) or [power converter](powerConverter.md) it directly connects adjacent subnetworks, i.e. components can be accessed. Each side's connectivity can be toggled using a wrench (e.g. the [scrench](../item/wrench.md)). When a redstone signal is applied to the net splitter, all sides' connectivity is inverted. +The net splitter is a device that allows controlling connectivity between subnetworks. Unlike the [relay](relay.md) or [power converter](powerConverter.md) it directly connects adjacent subnetworks, i.e. components can be accessed. Each side's connectivity can be toggled using a wrench (e.g. the [scrench](../item/wrench.md)). When a redstone signal is applied to the net splitter, all sides' connectivity is inverted. This block can therefore be used to toggle connectivity to certain parts of a component network. Use a [redstone I/O block](redstone.md) or [redstone cards](../item/redstoneCard1.md) to automate the net splitter. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/relay.md b/src/main/resources/assets/opencomputers/doc/en_US/block/relay.md new file mode 100644 index 000000000..212369838 --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/relay.md @@ -0,0 +1,13 @@ +# Relay + +![Building bridges.](oredict:oc:relay) + +The relay can be used to allow different subnetworks to send network messages to each other, without exposing components to [computers](../general/computer.md) in other networks. Keeping components local is usually a good idea, to avoid [computers](../general/computer.md) using the wrong [screen](screen1.md) or to avoid component overflows to happen (causing [computers](../general/computer.md) to crash and refuse to boot up). + +The relay can be upgraded by inserting a [wireless network card](../item/wlanCard.md) to also relay messages wirelessly. Wireless messages can be received and relayed by other relays with a wireless network card, or by [computers](../general/computer.md) with a wireless network card. + +Alternatively the relay can be upgraded using [linked cards](../item/linkedCard.md). In this case it will forward messages through the tunnel provided by the linked card, too; at the usual cost, so make sure the relay is sufficiently powered. + +Relays do *not* keep track of which packets they forwarded recently, so avoid cycles in your network or you may receive the same packet multiple times. Due to the limited buffer size of relays, sending messages too frequently will result in packet loss. You can upgrade your relays to increase the speed with which they relay messages, as well as their internal message queue size. + +Packets are only re-sent a certain number of times, so chaining an arbitrary number of relays is not possible. By default, a packet will be re-sent up to five times. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md b/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md index 49f1df835..5630023b4 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md @@ -6,4 +6,4 @@ A server rack houses up to four [servers](../item/server1.md). A [server](../ite Each [server](../item/server1.md) in a server rack can only communicate with one "face" of the server rack at a time - or none at all. Which side each [server](../item/server1.md) is connected to can be configured in the server rack's GUI. Beware that the sides are from the point of view of the server rack, i.e. if you are looking at the front of the server rack, `sides.right` will be to your left and vice versa. -Server racks act as [switch](switch.md) and [power distributor](powerDistributor.md) in one. The switch mode of the server rack can be configured in its GUI, with the two options being internal and external. In external mode the server rack will behave like a normal [switch](switch.md). In internal mode, messages are only passed to the [servers](../item/server1.md) in the rack, and will not be automatically relayed to the other faces of the rack. [Servers](../item/server1.md) will still be able to send messages to each other. This allows using server racks as advanced [switches](switch.md) that can perform filter and mapping operations, for example. +Server racks act as [relay](relay.md) and [power distributor](powerDistributor.md) in one. The switch mode of the server rack can be configured in its GUI, with the two options being internal and external. In external mode the server rack will behave like a normal [relay](relay.md). In internal mode, messages are only passed to the [servers](../item/server1.md) in the rack, and will not be automatically relayed to the other faces of the rack. [Servers](../item/server1.md) will still be able to send messages to each other. This allows using server racks as advanced [relays](relay.md) that can perform filter and mapping operations, for example. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md b/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md index a607e0cfd..35ad59fd4 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md @@ -2,6 +2,8 @@ ![Building bridges.](oredict:oc:switch) +*This block is deprecated and will be removed in a future version.* Craft it into a [relay](relay.md) to avoid losing it. + The switch can be used to allow different subnetworks to send network messages to each other, without exposing components to [computers](../general/computer.md) in other networks. Keeping components local is usually a good idea, to avoid [computers](../general/computer.md) using the wrong [screen](screen1.md) or to avoid component overflows to happen (causing [computers](../general/computer.md) to crash and refuse to boot up). There is also a wireless variation of this block, called the [access point](accessPoint.md), which will also relay messages wirelessly. Wireless messages can be received and relayed by other [access points](accessPoint.md), or by [computers](../general/computer.md) with a [wireless network card](../item/wlanCard.md). diff --git a/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md b/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md index 3fbd8a6c4..fc730e035 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md @@ -2,4 +2,4 @@ ![Enter the network.](oredict:oc:lanCard) -The network card allows [computers](../general/computer.md) to send and receive network messages. Messages (or packets) can be broadcasted to all receiving nodes in a subnetwork, or sent to a specific node with a specified address. [Switches](../block/switch.md) and [access points](../block/accessPoint.md) can be used to bridge multiple subnetworks by relaying messages between the subnetworks they are connected to. It is also possible to send a targeted message if the receiver is in another subnetwork, if the networks are connected via one or more [switches](../block/switch.md). +The network card allows [computers](../general/computer.md) to send and receive network messages. Messages (or packets) can be broadcasted to all receiving nodes in a subnetwork, or sent to a specific node with a specified address. [Relays](../block/relay.md) can be used to bridge multiple subnetworks by relaying messages between the subnetworks they are connected to. It is also possible to send a targeted message if the receiver is in another subnetwork, if the networks are connected via one or more [relays](../block/relay.md). diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 6d8d2cdb6..12020008f 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -3,7 +3,7 @@ # Use [nl] to for a line break. # Blocks -tile.oc.accessPoint.name=Access Point +tile.oc.accessPoint.name=§cAccess Point§7 tile.oc.adapter.name=Adapter tile.oc.assembler.name=Electronics Assembler tile.oc.cable.name=Cable @@ -29,13 +29,14 @@ tile.oc.print.name=3D Print tile.oc.printer.name=3D Printer tile.oc.raid.name=Raid tile.oc.redstone.name=Redstone I/O +tile.oc.relay.name=Relay tile.oc.robot.name=Robot tile.oc.robotAfterimage.name=Robot tile.oc.screen1.name=Screen (Tier 1) tile.oc.screen2.name=Screen (Tier 2) tile.oc.screen3.name=Screen (Tier 3) tile.oc.serverRack.name=Server Rack -tile.oc.switch.name=Switch +tile.oc.switch.name=§cSwitch§7 tile.oc.netSplitter.name=Net Splitter tile.oc.waypoint.name=Waypoint @@ -235,6 +236,7 @@ oc:container.Disassembler=Disassembler oc:container.DiskDrive=Disk Drive oc:container.Printer=Printer oc:container.Raid=Raid +oc:container.Relay=Relay oc:container.Server=Server oc:container.ServerRack=Server Rack oc:container.Switch=Switch @@ -328,6 +330,7 @@ oc:tooltip.RedstoneCard.RedNet=§fRedNet§7 is §asupported§7. oc:tooltip.RedstoneCard.WirelessCBE=§fWireless Redstone (ChickenBones)§7 is §asupported§7. oc:tooltip.RedstoneCard.WirelessSV=§fWireless Redstone (SlimeVoid)§7 is §asupported§7. oc:tooltip.RedstoneCard=Allows reading and emitting redstone signals around the computer or robot. +oc:tooltip.Relay=Allows connecting different networks to each other. Only network messages will be passed along, components will not be visible through this. Use this to separate networks while still allowing communication using Network Cards, for example. oc:tooltip.Robot=Unlike computers, robots can move around and interact with the world much like a player can.[nl] §cCan not connect to external components.§7 # The underscore makes sure this isn't hidden with the rest of the tooltip. oc:tooltip.Robot_Level=§fLevel§7: §a%s§7 diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index e44ddf5bc..2350ace4a 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -504,11 +504,6 @@ interweb { [string, string, string]] } -accessPoint { - input: [[ingotIron, "oc:wlanCard", ingotIron] - ["oc:cable", "oc:lanCard", "oc:cable"] - [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] -} adapter { input: [[ingotIron, "oc:cable", ingotIron] ["oc:cable", "oc:circuitChip1", "oc:cable"] @@ -607,7 +602,7 @@ powerDistributor { serverRack { input: [["oc:circuitChip2", "oc:wlanCard", "oc:circuitChip2"] [fenceIron, chest, fenceIron] - ["oc:switch", "oc:materialCircuitBoardPrinted", "oc:powerDistributor"]] + ["oc:relay", "oc:materialCircuitBoardPrinted", "oc:powerDistributor"]] } raid { input: [[nuggetIron, "oc:cpu3", nuggetIron] @@ -619,7 +614,7 @@ redstone { [blockRedstone, "oc:redstoneCard1", blockRedstone] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] } -switch { +relay { input: [[ingotIron, "oc:cable", ingotIron] ["oc:cable", "oc:lanCard", "oc:cable"] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] diff --git a/src/main/resources/assets/opencomputers/recipes/gregtech.recipes b/src/main/resources/assets/opencomputers/recipes/gregtech.recipes index 4c95c8eb8..f2b3768c7 100644 --- a/src/main/resources/assets/opencomputers/recipes/gregtech.recipes +++ b/src/main/resources/assets/opencomputers/recipes/gregtech.recipes @@ -318,7 +318,7 @@ powerDistributor { serverRack { input: [[craftingToolScrewdriver, "oc:wlanCard", craftingToolWrench] ["ic2.reactorVentDiamond", chest, "ic2.reactorVentDiamond"] - ["oc:switch", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] + ["oc:relay", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] } redstone { # 32731 = Activity Detector @@ -326,7 +326,7 @@ redstone { [{item="gt.metaitem.01", subID=32731}, {block="gt.blockcasings", subID=2}, "oc:redstoneCard1"] ["oc:circuitChip2", "oc:materialCircuitBoardPrinted", "oc:circuitChip2"]] } -switch { +relay { input: [["", "oc:lanCard", ""] ["oc:cable", {block="gt.blockcasings", subID=2}, "oc:cable"] ["oc:materialCircuitBoardPrinted", craftingToolWrench, "oc:materialCircuitBoardPrinted"]] diff --git a/src/main/resources/assets/opencomputers/recipes/hardmode.recipes b/src/main/resources/assets/opencomputers/recipes/hardmode.recipes index ed930d4f3..fe0614746 100644 --- a/src/main/resources/assets/opencomputers/recipes/hardmode.recipes +++ b/src/main/resources/assets/opencomputers/recipes/hardmode.recipes @@ -363,14 +363,14 @@ powerDistributor { serverRack { input: [["oc:circuitChip3", "oc:wlanCard", "oc:circuitChip3"] [fenceIron, chest, fenceIron] - ["oc:switch", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] + ["oc:relay", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] } redstone { input: [[ingotIron, "oc:circuitChip3", ingotIron] [blockRedstone, "oc:redstoneCard1", blockRedstone] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] } -switch { +relay { input: [[ingotIron, "oc:cable", ingotIron] ["oc:cable", "oc:lanCard", "oc:cable"] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] diff --git a/src/main/resources/assets/opencomputers/textures/gui/upgrade_tab.png b/src/main/resources/assets/opencomputers/textures/gui/upgrade_tab.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca3b14c7ac35ec4c60bc29b73c7c404fff85c51 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6L!3-p`v&?;flw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlBK`oM5ZBPq(EtDc19``e9Ro6|Snj0*Ijki?e!)QQe}>=N z_=14~`kpS1Ar-fh5)QFNL`X<%WK?_e=nRh!&zT5@!z+Gl5IoM+@RD)20XOrvl%q@n a2@Ll?ur`bTUn~sN%HZkh=d#Wzp$PyQ9zNOt literal 0 HcmV?d00001 diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index 10646c14d..78b5ac786 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -31,6 +31,7 @@ object Constants { final val Printer = "printer" final val Raid = "raid" final val Redstone = "redstone" + final val Relay = "relay" final val Robot = "robot" final val RobotAfterimage = "robotAfterimage" final val ScreenTier1 = "screen1" diff --git a/src/main/scala/li/cil/oc/client/GuiHandler.scala b/src/main/scala/li/cil/oc/client/GuiHandler.scala index 44190606b..08882733e 100644 --- a/src/main/scala/li/cil/oc/client/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/client/GuiHandler.scala @@ -34,12 +34,14 @@ object GuiHandler extends CommonGuiHandler { new gui.DiskDrive(player.inventory, t) case t: tileentity.Printer if id == GuiType.Printer.id => new gui.Printer(player.inventory, t) - case t: tileentity.Raid if id == GuiType.Raid.id => - new gui.Raid(player.inventory, t) - case t: tileentity.RobotProxy if id == GuiType.Robot.id => - new gui.Robot(player.inventory, t.robot) case t: tileentity.ServerRack if id == GuiType.Rack.id => new gui.ServerRack(player.inventory, t) + case t: tileentity.Raid if id == GuiType.Raid.id => + new gui.Raid(player.inventory, t) + case t: tileentity.Relay if id == GuiType.Relay.id => + new gui.Relay(player.inventory, t) + case t: tileentity.RobotProxy if id == GuiType.Robot.id => + new gui.Robot(player.inventory, t.robot) case t: tileentity.Screen if id == GuiType.Screen.id => new gui.Screen(t.origin.buffer, t.tier > 0, () => t.origin.hasKeyboard, () => t.origin.buffer.isRenderingEnabled) case t: tileentity.Switch if id == GuiType.Switch.id => diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 9cf57901b..e05f3c4d9 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -423,7 +423,7 @@ object PacketHandler extends CommonPacketHandler { } def onSwitchActivity(p: PacketParser) = - p.readTileEntity[Switch]() match { + p.readTileEntity[traits.SwitchLike]() match { case Some(t) => t.lastMessage = System.currentTimeMillis() case _ => // Invalid packet. } diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index aa96dcb65..45930095c 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -67,6 +67,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.ServerRack], ServerRackRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Switch], SwitchRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.AccessPoint], SwitchRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Relay], SwitchRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 78b84868e..195f400da 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -43,6 +43,7 @@ object Textures { val guiRobotSelection = new ResourceLocation(Settings.resourceDomain, "textures/gui/robot_selection.png") val guiServer = new ResourceLocation(Settings.resourceDomain, "textures/gui/server.png") val guiSlot = new ResourceLocation(Settings.resourceDomain, "textures/gui/slot.png") + val guiUpgradeTab = new ResourceLocation(Settings.resourceDomain, "textures/gui/upgrade_tab.png") val guiWaypoint = new ResourceLocation(Settings.resourceDomain, "textures/gui/waypoint.png") val blockCaseFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/CaseFrontOn.png") diff --git a/src/main/scala/li/cil/oc/client/gui/Relay.scala b/src/main/scala/li/cil/oc/client/gui/Relay.scala new file mode 100644 index 000000000..c6f578e67 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/gui/Relay.scala @@ -0,0 +1,122 @@ +package li.cil.oc.client.gui + +import java.lang.Iterable +import java.text.DecimalFormat +import java.util + +import codechicken.nei.VisiblityData +import codechicken.nei.api.INEIGuiHandler +import codechicken.nei.api.TaggedInventoryArea +import cpw.mods.fml.common.Optional +import li.cil.oc.Localization +import li.cil.oc.client.Textures +import li.cil.oc.common.container +import li.cil.oc.common.tileentity +import li.cil.oc.integration.Mods +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.client.renderer.Tessellator +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.item.ItemStack +import org.lwjgl.opengl.GL11 +import org.lwjgl.util.Rectangle + +@Optional.Interface(iface = "codechicken.nei.api.INEIGuiHandler", modid = Mods.IDs.NotEnoughItems) +class Relay(playerInventory: InventoryPlayer, val relay: tileentity.Relay) extends DynamicGuiContainer(new container.Relay(playerInventory, relay)) with INEIGuiHandler { + private val format = new DecimalFormat("#.##hz") + + private val tabPosition = new Rectangle(xSize, 10, 23, 26) + + override protected def drawSecondaryBackgroundLayer(): Unit = { + super.drawSecondaryBackgroundLayer() + + // Tab background. + GL11.glColor4f(1, 1, 1, 1) + Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.guiUpgradeTab) + val x = windowX + tabPosition.getX + val y = windowY + tabPosition.getY + val w = tabPosition.getWidth + val h = tabPosition.getHeight + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(x, y + h, zLevel, 0, 1) + t.addVertexWithUV(x + w, y + h, zLevel, 1, 1) + t.addVertexWithUV(x + w, y, zLevel, 1, 0) + t.addVertexWithUV(x, y, zLevel, 0, 0) + t.draw() + } + + override def mouseClicked(mouseX: Int, mouseY: Int, button: Int): Unit = { + // So MC doesn't throw away the item in the upgrade slot when we're trying to pick it up... + val originalWidth = xSize + try { + xSize += tabPosition.getWidth + super.mouseClicked(mouseX, mouseY, button) + } + finally { + xSize = originalWidth + } + } + + override def mouseMovedOrUp(mouseX: Int, mouseY: Int, button: Int): Unit = { + // So MC doesn't throw away the item in the upgrade slot when we're trying to pick it up... + val originalWidth = xSize + try { + xSize += tabPosition.getWidth + super.mouseMovedOrUp(mouseX, mouseY, button) + } + finally { + xSize = originalWidth + } + } + + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) + fontRendererObj.drawString( + Localization.localizeImmediately(relay.getInventoryName), + 8, 6, 0x404040) + + fontRendererObj.drawString( + Localization.Switch.TransferRate, + 14, 20, 0x404040) + fontRendererObj.drawString( + Localization.Switch.PacketsPerCycle, + 14, 39, 0x404040) + fontRendererObj.drawString( + Localization.Switch.QueueSize, + 14, 58, 0x404040) + + fontRendererObj.drawString( + format.format(20f / inventoryContainer.relayDelay), + 108, 20, 0x404040) + fontRendererObj.drawString( + inventoryContainer.packetsPerCycleAvg + " / " + inventoryContainer.relayAmount, + 108, 39, thresholdBasedColor(inventoryContainer.packetsPerCycleAvg, math.ceil(inventoryContainer.relayAmount / 2f).toInt, inventoryContainer.relayAmount)) + fontRendererObj.drawString( + inventoryContainer.queueSize + " / " + inventoryContainer.maxQueueSize, + 108, 58, thresholdBasedColor(inventoryContainer.queueSize, inventoryContainer.maxQueueSize / 2, inventoryContainer.maxQueueSize)) + } + + private def thresholdBasedColor(value: Int, yellow: Int, red: Int) = { + if (value < yellow) 0x009900 + else if (value < red) 0x999900 + else 0x990000 + } + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def modifyVisiblity(gui: GuiContainer, currentVisibility: VisiblityData): VisiblityData = null + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def getItemSpawnSlots(gui: GuiContainer, stack: ItemStack): Iterable[Integer] = null + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def getInventoryAreas(gui: GuiContainer): util.List[TaggedInventoryArea] = null + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def handleDragNDrop(gui: GuiContainer, mouseX: Int, mouseY: Int, stack: ItemStack, button: Int): Boolean = false + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def hideItemPanelSlot(gui: GuiContainer, x: Int, y: Int, w: Int, h: Int): Boolean = { + new Rectangle(x - windowX, y - windowY, w, h).intersects(tabPosition) + } +} diff --git a/src/main/scala/li/cil/oc/client/gui/Switch.scala b/src/main/scala/li/cil/oc/client/gui/Switch.scala index ea2dc471f..e58511a44 100644 --- a/src/main/scala/li/cil/oc/client/gui/Switch.scala +++ b/src/main/scala/li/cil/oc/client/gui/Switch.scala @@ -7,6 +7,7 @@ import li.cil.oc.common.container import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer +// TODO Remove in 1.7 class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) extends DynamicGuiContainer(new container.Switch(playerInventory, switch)) { private val format = new DecimalFormat("#.##hz") diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala index 4491c9c85..b2fbe27b4 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala @@ -13,7 +13,7 @@ object SwitchRenderer extends TileEntitySpecialRenderer { override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float) { RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") - val switch = tileEntity.asInstanceOf[tileentity.Switch] + val switch = tileEntity.asInstanceOf[tileentity.traits.SwitchLike] val activity = math.max(0, 1 - (System.currentTimeMillis() - switch.lastMessage) / 1000.0) if (activity > 0) { GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) diff --git a/src/main/scala/li/cil/oc/common/GuiHandler.scala b/src/main/scala/li/cil/oc/common/GuiHandler.scala index ff56edec2..6ce0419bd 100644 --- a/src/main/scala/li/cil/oc/common/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/common/GuiHandler.scala @@ -28,6 +28,8 @@ abstract class GuiHandler extends IGuiHandler { new container.Printer(player.inventory, t) case t: tileentity.Raid if id == GuiType.Raid.id => new container.Raid(player.inventory, t) + case t: tileentity.Relay if id == GuiType.Relay.id => + new container.Relay(player.inventory, t) case t: tileentity.RobotProxy if id == GuiType.Robot.id => new container.Robot(player.inventory, t.robot) case t: tileentity.ServerRack if id == GuiType.Rack.id => diff --git a/src/main/scala/li/cil/oc/common/GuiType.scala b/src/main/scala/li/cil/oc/common/GuiType.scala index 864bdbf39..5eda4b249 100644 --- a/src/main/scala/li/cil/oc/common/GuiType.scala +++ b/src/main/scala/li/cil/oc/common/GuiType.scala @@ -26,6 +26,7 @@ object GuiType extends ScalaEnum { val Printer = new EnumVal { def name = "Printer"; def subType = GuiType.Category.Block } val Rack = new EnumVal { def name = "Rack"; def subType = GuiType.Category.Block } val Raid = new EnumVal { def name = "Raid"; def subType = GuiType.Category.Block } + val Relay = new EnumVal { def name = "Relay"; def subType = GuiType.Category.Block } val Robot = new EnumVal { def name = "Robot"; def subType = GuiType.Category.Block } val Screen = new EnumVal { def name = "Screen"; def subType = GuiType.Category.Block } val Server = new EnumVal { def name = "Server"; def subType = GuiType.Category.Item } diff --git a/src/main/scala/li/cil/oc/common/InventorySlots.scala b/src/main/scala/li/cil/oc/common/InventorySlots.scala index 6961b5bd4..1ac7ef962 100644 --- a/src/main/scala/li/cil/oc/common/InventorySlots.scala +++ b/src/main/scala/li/cil/oc/common/InventorySlots.scala @@ -120,6 +120,13 @@ object InventorySlots { ) ) + val relay = Array( + InventorySlot(Slot.CPU, Tier.Three), + InventorySlot(Slot.Memory, Tier.Three), + InventorySlot(Slot.HDD, Tier.Three), + InventorySlot(Slot.Card, Tier.Three) + ) + val switch = Array( InventorySlot(Slot.CPU, Tier.Three), InventorySlot(Slot.Memory, Tier.Three), diff --git a/src/main/scala/li/cil/oc/common/block/AccessPoint.scala b/src/main/scala/li/cil/oc/common/block/AccessPoint.scala index f181c86ef..2ae339da7 100644 --- a/src/main/scala/li/cil/oc/common/block/AccessPoint.scala +++ b/src/main/scala/li/cil/oc/common/block/AccessPoint.scala @@ -4,6 +4,7 @@ import li.cil.oc.Settings import li.cil.oc.common.tileentity import net.minecraft.world.World +// TODO Remove in 1.7 class AccessPoint extends Switch with traits.PowerAcceptor { override protected def customTextures = Array( None, diff --git a/src/main/scala/li/cil/oc/common/block/Relay.scala b/src/main/scala/li/cil/oc/common/block/Relay.scala new file mode 100644 index 000000000..1a420de04 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/Relay.scala @@ -0,0 +1,34 @@ +package li.cil.oc.common.block + +import li.cil.oc.Settings +import li.cil.oc.client.Textures +import li.cil.oc.common.GuiType +import li.cil.oc.common.tileentity +import net.minecraft.client.renderer.texture.IIconRegister +import net.minecraft.world.World + +class Relay extends SimpleBlock with traits.GUI with traits.PowerAcceptor { + override protected def customTextures = Array( + None, + Some("SwitchTop"), + Some("SwitchSide"), + Some("SwitchSide"), + Some("SwitchSide"), + Some("SwitchSide") + ) + + override def registerBlockIcons(iconRegister: IIconRegister) = { + super.registerBlockIcons(iconRegister) + Textures.Switch.iconSideActivity = iconRegister.registerIcon(Settings.resourceDomain + ":SwitchSideOn") + } + + // ----------------------------------------------------------------------- // + + override def guiType = GuiType.Relay + + override def energyThroughput = Settings.get.accessPointRate + + override def hasTileEntity(metadata: Int) = true + + override def createTileEntity(world: World, metadata: Int) = new tileentity.Relay() +} diff --git a/src/main/scala/li/cil/oc/common/block/Switch.scala b/src/main/scala/li/cil/oc/common/block/Switch.scala index fb4d4514b..29335e0fb 100644 --- a/src/main/scala/li/cil/oc/common/block/Switch.scala +++ b/src/main/scala/li/cil/oc/common/block/Switch.scala @@ -7,6 +7,7 @@ import li.cil.oc.common.tileentity import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.world.World +// TODO Remove in 1.7 class Switch extends SimpleBlock with traits.GUI { override protected def customTextures = Array( None, diff --git a/src/main/scala/li/cil/oc/common/container/Relay.scala b/src/main/scala/li/cil/oc/common/container/Relay.scala new file mode 100644 index 000000000..d9ee4a54f --- /dev/null +++ b/src/main/scala/li/cil/oc/common/container/Relay.scala @@ -0,0 +1,33 @@ +package li.cil.oc.common.container + +import li.cil.oc.common.Slot +import li.cil.oc.common.tileentity +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.nbt.NBTTagCompound + +class Relay(playerInventory: InventoryPlayer, relay: tileentity.Relay) extends Player(playerInventory, relay) { + addSlotToContainer(151, 15, Slot.CPU) + addSlotToContainer(151, 34, Slot.Memory) + addSlotToContainer(151, 53, Slot.HDD) + addSlotToContainer(178, 15, Slot.Card) + addPlayerInventorySlots(8, 84) + + def relayDelay = synchronizedData.getInteger("relayDelay") + + def relayAmount = synchronizedData.getInteger("relayAmount") + + def maxQueueSize = synchronizedData.getInteger("maxQueueSize") + + def packetsPerCycleAvg = synchronizedData.getInteger("packetsPerCycleAvg") + + def queueSize = synchronizedData.getInteger("queueSize") + + override protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = { + synchronizedData.setInteger("relayDelay", relay.relayDelay) + synchronizedData.setInteger("relayAmount", relay.relayAmount) + synchronizedData.setInteger("maxQueueSize", relay.maxQueueSize) + synchronizedData.setInteger("packetsPerCycleAvg", relay.packetsPerCycleAvg()) + synchronizedData.setInteger("queueSize", relay.queue.size) + super.detectCustomDataChanges(nbt) + } +} diff --git a/src/main/scala/li/cil/oc/common/container/Switch.scala b/src/main/scala/li/cil/oc/common/container/Switch.scala index ae6c16254..78d884368 100644 --- a/src/main/scala/li/cil/oc/common/container/Switch.scala +++ b/src/main/scala/li/cil/oc/common/container/Switch.scala @@ -5,6 +5,7 @@ import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer import net.minecraft.nbt.NBTTagCompound +// TODO Remove in 1.7 class Switch(playerInventory: InventoryPlayer, switch: tileentity.Switch) extends Player(playerInventory, switch) { addSlotToContainer(151, 15, Slot.CPU) addSlotToContainer(151, 34, Slot.Memory) diff --git a/src/main/scala/li/cil/oc/common/init/Blocks.scala b/src/main/scala/li/cil/oc/common/init/Blocks.scala index 7acf21d27..73ea7bea2 100644 --- a/src/main/scala/li/cil/oc/common/init/Blocks.scala +++ b/src/main/scala/li/cil/oc/common/init/Blocks.scala @@ -30,6 +30,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Printer], Settings.namespace + "printer") GameRegistry.registerTileEntity(classOf[tileentity.Raid], Settings.namespace + "raid") GameRegistry.registerTileEntity(classOf[tileentity.Redstone], Settings.namespace + "redstone") + GameRegistry.registerTileEntity(classOf[tileentity.Relay], Settings.namespace + "relay") GameRegistry.registerTileEntity(classOf[tileentity.RobotProxy], Settings.namespace + "robot") GameRegistry.registerTileEntity(classOf[tileentity.Switch], Settings.namespace + "switch") GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen") @@ -37,7 +38,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter") GameRegistry.registerTileEntity(classOf[tileentity.Waypoint], Settings.namespace + "waypoint") - Recipes.addBlock(new AccessPoint(), Constants.BlockName.AccessPoint, "oc:accessPoint") + Items.registerBlock(new AccessPoint(), Constants.BlockName.AccessPoint) Recipes.addBlock(new Adapter(), Constants.BlockName.Adapter, "oc:adapter") Recipes.addBlock(new Assembler(), Constants.BlockName.Assembler, "oc:assembler") Recipes.addBlock(new Cable(), Constants.BlockName.Cable, "oc:cable") @@ -57,11 +58,12 @@ object Blocks { Recipes.addBlock(new PowerDistributor(), Constants.BlockName.PowerDistributor, "oc:powerDistributor") Recipes.addBlock(new Raid(), Constants.BlockName.Raid, "oc:raid") Recipes.addBlock(new Redstone(), Constants.BlockName.Redstone, "oc:redstone") + Recipes.addBlock(new Relay(), Constants.BlockName.Relay, "oc:relay") Recipes.addBlock(new Screen(Tier.One), Constants.BlockName.ScreenTier1, "oc:screen1") Recipes.addBlock(new Screen(Tier.Three), Constants.BlockName.ScreenTier3, "oc:screen3") Recipes.addBlock(new Screen(Tier.Two), Constants.BlockName.ScreenTier2, "oc:screen2") Recipes.addBlock(new ServerRack(), Constants.BlockName.ServerRack, "oc:serverRack") - Recipes.addBlock(new Switch(), Constants.BlockName.Switch, "oc:switch") + Items.registerBlock(new Switch(), Constants.BlockName.Switch) Items.registerBlock(new Case(Tier.Four), Constants.BlockName.CaseCreative) Items.registerBlock(new Microcontroller(), Constants.BlockName.Microcontroller) diff --git a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala index 6bab1aba8..9e1aa47e8 100644 --- a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala +++ b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala @@ -316,6 +316,12 @@ object Recipes { GameRegistry.addRecipe(new ExtendedShapelessOreRecipe( lightPrint, print.createItemStack(1), new ItemStack(net.minecraft.init.Blocks.glowstone))) + + // Switch/AccessPoint -> Relay conversion + GameRegistry.addShapelessRecipe(api.Items.get(Constants.BlockName.Relay).createItemStack(1), + api.Items.get(Constants.BlockName.AccessPoint).createItemStack(1)) + GameRegistry.addShapelessRecipe(api.Items.get(Constants.BlockName.Relay).createItemStack(1), + api.Items.get(Constants.BlockName.Switch).createItemStack(1)) } catch { case e: Throwable => OpenComputers.log.error("Error parsing recipes, you may not be able to craft any items from this mod!", e) diff --git a/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala b/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala index 8cc3586e4..0c40bc06c 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala @@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.Constants.NBT import net.minecraftforge.common.util.ForgeDirection +// TODO Remove in 1.7 class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor { var strength = Settings.get.maxWirelessRange @@ -25,6 +26,8 @@ class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor withComponent("access_point"). create()) + override def isWirelessEnabled = true + // ----------------------------------------------------------------------- // @SideOnly(Side.CLIENT) @@ -78,7 +81,7 @@ class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet) { super.relayPacket(sourceSide, packet) - if (strength > 0 && (sourceSide != None || isRepeater)) { + if (strength > 0 && (sourceSide.isDefined || isRepeater)) { val cost = Settings.get.wirelessCostPerRange val tryChangeBuffer = sourceSide match { case Some(side) => diff --git a/src/main/scala/li/cil/oc/common/tileentity/Relay.scala b/src/main/scala/li/cil/oc/common/tileentity/Relay.scala new file mode 100644 index 000000000..81ddfeeb4 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/Relay.scala @@ -0,0 +1,282 @@ +package li.cil.oc.common.tileentity + +import com.google.common.base.Charsets +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly +import dan200.computercraft.api.peripheral.IComputerAccess +import li.cil.oc.Constants +import li.cil.oc.Localization +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.Driver +import li.cil.oc.api.machine.Arguments +import li.cil.oc.api.machine.Callback +import li.cil.oc.api.machine.Context +import li.cil.oc.api.network.Analyzable +import li.cil.oc.api.network.Connector +import li.cil.oc.api.network.Node +import li.cil.oc.api.network.Packet +import li.cil.oc.api.network.Visibility +import li.cil.oc.api.network.WirelessEndpoint +import li.cil.oc.common.InventorySlots +import li.cil.oc.common.Slot +import li.cil.oc.common.item +import li.cil.oc.common.item.Delegator +import li.cil.oc.integration.Mods +import li.cil.oc.integration.opencomputers.DriverLinkedCard +import li.cil.oc.server.network.QuantumNetwork +import li.cil.oc.util.ExtendedNBT._ +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT +import net.minecraftforge.common.util.ForgeDirection + +class Relay extends traits.SwitchLike with traits.ComponentInventory with traits.PowerAcceptor with Analyzable with WirelessEndpoint with QuantumNetwork.QuantumNode { + lazy final val WirelessNetworkCard = api.Items.get(Constants.ItemName.WirelessNetworkCard) + lazy final val LinkedCard = api.Items.get(Constants.ItemName.LinkedCard) + + var strength = Settings.get.maxWirelessRange + + var isRepeater = true + + var isWirelessEnabled = false + + var isLinkedEnabled = false + + var tunnel = "creative" + + val componentNodes = Array.fill(6)(api.Network.newNode(this, Visibility.Network). + withComponent("access_point"). + create()) + + override def canUpdate = isServer + + // ----------------------------------------------------------------------- // + + @SideOnly(Side.CLIENT) + override protected def hasConnector(side: ForgeDirection) = true + + override protected def connector(side: ForgeDirection) = sidedNode(side) match { + case connector: Connector => Option(connector) + case _ => None + } + + override def energyThroughput = Settings.get.accessPointRate + + // ----------------------------------------------------------------------- // + + override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float): Array[Node] = { + if (isWirelessEnabled) { + player.addChatMessage(Localization.Analyzer.WirelessStrength(strength)) + Array(componentNodes(side)) + } + else null + } + + // ----------------------------------------------------------------------- // + + @Callback(direct = true, doc = """function():number -- Get the signal strength (range) used when relaying messages.""") + def getStrength(context: Context, args: Arguments): Array[AnyRef] = synchronized(result(strength)) + + @Callback(doc = """function(strength:number):number -- Set the signal strength (range) used when relaying messages.""") + def setStrength(context: Context, args: Arguments): Array[AnyRef] = synchronized { + strength = math.max(args.checkDouble(0), math.min(0, Settings.get.maxWirelessRange)) + result(strength) + } + + @Callback(direct = true, doc = """function():boolean -- Get whether the access point currently acts as a repeater (resend received wireless packets wirelessly).""") + def isRepeater(context: Context, args: Arguments): Array[AnyRef] = synchronized(result(isRepeater)) + + @Callback(doc = """function(enabled:boolean):boolean -- Set whether the access point should act as a repeater.""") + def setRepeater(context: Context, args: Arguments): Array[AnyRef] = synchronized { + isRepeater = args.checkBoolean(0) + result(isRepeater) + } + + // ----------------------------------------------------------------------- // + + protected def queueMessage(source: String, destination: String, port: Int, answerPort: Int, args: Array[AnyRef]) { + for (computer <- computers.map(_.asInstanceOf[IComputerAccess])) { + val address = s"cc${computer.getID}_${computer.getAttachmentName}" + if (source != address && Option(destination).forall(_ == address) && openPorts(computer).contains(port)) + computer.queueEvent("modem_message", Array(Seq(computer.getAttachmentName, Int.box(port), Int.box(answerPort)) ++ args.map { + case x: Array[Byte] => new String(x, Charsets.UTF_8) + case x => x + }: _*)) + } + } + + // ----------------------------------------------------------------------- // + + override def receivePacket(packet: Packet, source: WirelessEndpoint): Unit = { + if (isWirelessEnabled) { + tryEnqueuePacket(None, packet) + } + } + + override def receivePacket(packet: Packet): Unit = { + if (isLinkedEnabled) { + tryEnqueuePacket(None, packet) + } + } + + override def tryEnqueuePacket(sourceSide: Option[ForgeDirection], packet: Packet): Boolean = { + if (Mods.ComputerCraft.isAvailable) { + packet.data.headOption match { + case Some(answerPort: java.lang.Double) => queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1)) + case _ => queueMessage(packet.source, packet.destination, packet.port, -1, packet.data) + } + } + super.tryEnqueuePacket(sourceSide, packet) + } + + override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet): Unit = { + super.relayPacket(sourceSide, packet) + + val tryChangeBuffer = sourceSide match { + case Some(side) => + (amount: Double) => plugs(side.ordinal).node.asInstanceOf[Connector].tryChangeBuffer(amount) + case _ => + (amount: Double) => plugs.exists(_.node.asInstanceOf[Connector].tryChangeBuffer(amount)) + } + + if (isWirelessEnabled && strength > 0 && (sourceSide.isDefined || isRepeater)) { + val cost = Settings.get.wirelessCostPerRange + if (tryChangeBuffer(-strength * cost)) { + api.Network.sendWirelessPacket(this, strength, packet) + } + } + + if (isLinkedEnabled && (sourceSide.isDefined || isRepeater)) { + val cost = packet.size / 32.0 + Settings.get.wirelessCostPerRange * Settings.get.maxWirelessRange * 5 + if (tryChangeBuffer(-cost)) { + val endpoints = QuantumNetwork.getEndpoints(tunnel).filter(_ != this) + for (endpoint <- endpoints) { + endpoint.receivePacket(packet) + } + } + } + + onSwitchActivity() + } + + // ----------------------------------------------------------------------- // + + override protected def createNode(plug: Plug) = api.Network.newNode(plug, Visibility.Network). + withConnector(math.round(Settings.get.bufferAccessPoint)). + create() + + override protected def onPlugConnect(plug: Plug, node: Node) { + super.onPlugConnect(plug, node) + if (node == plug.node) { + api.Network.joinWirelessNetwork(this) + } + if (plug.isPrimary) + plug.node.connect(componentNodes(plug.side.ordinal())) + else + componentNodes(plug.side.ordinal).remove() + } + + override protected def onPlugDisconnect(plug: Plug, node: Node) { + super.onPlugDisconnect(plug, node) + if (node == plug.node) { + api.Network.leaveWirelessNetwork(this) + } + if (plug.isPrimary && node != plug.node) + plug.node.connect(componentNodes(plug.side.ordinal())) + else + componentNodes(plug.side.ordinal).remove() + } + + // ----------------------------------------------------------------------- // + + override protected def onItemAdded(slot: Int, stack: ItemStack) { + super.onItemAdded(slot, stack) + updateLimits(slot, stack) + } + + private def updateLimits(slot: Int, stack: ItemStack) { + Option(Driver.driverFor(stack, getClass)) match { + case Some(driver) if driver.slot(stack) == Slot.CPU => + relayDelay = math.max(1, relayBaseDelay - ((driver.tier(stack) + 1) * relayDelayPerUpgrade)) + case Some(driver) if driver.slot(stack) == Slot.Memory => + relayAmount = math.max(1, relayBaseAmount + (Delegator.subItem(stack) match { + case Some(ram: item.Memory) => (ram.tier + 1) * relayAmountPerUpgrade + case _ => (driver.tier(stack) + 1) * (relayAmountPerUpgrade * 2) + })) + case Some(driver) if driver.slot(stack) == Slot.HDD => + maxQueueSize = math.max(1, queueBaseSize + (driver.tier(stack) + 1) * queueSizePerUpgrade) + case Some(driver) if driver.slot(stack) == Slot.Card => + val descriptor = api.Items.get(stack) + if (descriptor == WirelessNetworkCard) { + isWirelessEnabled = true + } + if (descriptor == LinkedCard) { + val data = DriverLinkedCard.dataTag(stack) + if (data.hasKey(Settings.namespace + "tunnel")) { + tunnel = data.getString(Settings.namespace + "tunnel") + isLinkedEnabled = true + QuantumNetwork.add(this) + } + } + case _ => // Dafuq u doin. + } + } + + override protected def onItemRemoved(slot: Int, stack: ItemStack) { + super.onItemRemoved(slot, stack) + Driver.driverFor(stack, getClass) match { + case driver if driver.slot(stack) == Slot.CPU => relayDelay = relayBaseDelay + case driver if driver.slot(stack) == Slot.Memory => relayAmount = relayBaseAmount + case driver if driver.slot(stack) == Slot.HDD => maxQueueSize = queueBaseSize + case driver if driver.slot(stack) == Slot.Card => + isWirelessEnabled = false + isLinkedEnabled = false + QuantumNetwork.remove(this) + } + } + + override def getSizeInventory = InventorySlots.relay.length + + override def isItemValidForSlot(slot: Int, stack: ItemStack) = + Option(Driver.driverFor(stack, getClass)).fold(false)(driver => { + val provided = InventorySlots.relay(slot) + val tierSatisfied = driver.slot(stack) == provided.slot && driver.tier(stack) <= provided.tier + val cardTypeSatisfied = if (provided.slot == Slot.Card) api.Items.get(stack) == WirelessNetworkCard || api.Items.get(stack) == LinkedCard else true + tierSatisfied && cardTypeSatisfied + }) + + // ----------------------------------------------------------------------- // + + override def readFromNBTForServer(nbt: NBTTagCompound) { + super.readFromNBTForServer(nbt) + for (slot <- items.indices) items(slot) collect { + case stack => updateLimits(slot, stack) + } + + if (nbt.hasKey(Settings.namespace + "strength")) { + strength = nbt.getDouble(Settings.namespace + "strength") max 0 min Settings.get.maxWirelessRange + } + if (nbt.hasKey(Settings.namespace + "isRepeater")) { + isRepeater = nbt.getBoolean(Settings.namespace + "isRepeater") + } + nbt.getTagList(Settings.namespace + "componentNodes", NBT.TAG_COMPOUND).toArray[NBTTagCompound]. + zipWithIndex.foreach { + case (tag, index) => componentNodes(index).load(tag) + } + } + + override def writeToNBTForServer(nbt: NBTTagCompound) = { + super.writeToNBTForServer(nbt) + nbt.setDouble(Settings.namespace + "strength", strength) + nbt.setBoolean(Settings.namespace + "isRepeater", isRepeater) + nbt.setNewTagList(Settings.namespace + "componentNodes", componentNodes.map { + case node: Node => + val tag = new NBTTagCompound() + node.save(tag) + tag + case _ => new NBTTagCompound() + }) + } +} diff --git a/src/main/scala/li/cil/oc/common/tileentity/Switch.scala b/src/main/scala/li/cil/oc/common/tileentity/Switch.scala index 1ee39015a..794893d9a 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Switch.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Switch.scala @@ -3,26 +3,21 @@ package li.cil.oc.common.tileentity import com.google.common.base.Charsets import dan200.computercraft.api.peripheral.IComputerAccess import li.cil.oc.api.Driver -import li.cil.oc.api.network.Message import li.cil.oc.api.network.Packet import li.cil.oc.common.InventorySlots import li.cil.oc.common.Slot import li.cil.oc.common.item import li.cil.oc.common.item.Delegator import li.cil.oc.integration.Mods -import li.cil.oc.server.PacketSender import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.ForgeDirection -import scala.collection.mutable +// TODO Remove in 1.7 +class Switch extends traits.SwitchLike with traits.NotAnalyzable with traits.ComponentInventory { + override def isWirelessEnabled = false -class Switch extends traits.Hub with traits.NotAnalyzable with traits.ComponentInventory { - var lastMessage = 0L - - val computers = mutable.Buffer.empty[AnyRef] - - val openPorts = mutable.Map.empty[AnyRef, mutable.Set[Int]] + override def isLinkedEnabled = false override def canUpdate = isServer @@ -41,29 +36,19 @@ class Switch extends traits.Hub with traits.NotAnalyzable with traits.ComponentI // ----------------------------------------------------------------------- // - override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet) { - super.relayPacket(sourceSide, packet) - val now = System.currentTimeMillis() - if (now - lastMessage >= (relayDelay - 1) * 50) { - lastMessage = now - PacketSender.sendSwitchActivity(this) - } - } - - override protected def onPlugMessage(plug: Plug, message: Message) { - super.onPlugMessage(plug, message) - if (message.name == "network.message" && Mods.ComputerCraft.isAvailable) { - message.data match { - case Array(packet: Packet) => - packet.data.headOption match { - case Some(answerPort: java.lang.Double) => - queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1)) - case _ => - queueMessage(packet.source, packet.destination, packet.port, -1, packet.data) - } - case _ => + override def tryEnqueuePacket(sourceSide: Option[ForgeDirection], packet: Packet): Boolean = { + if (Mods.ComputerCraft.isAvailable) { + packet.data.headOption match { + case Some(answerPort: java.lang.Double) => queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1)) + case _ => queueMessage(packet.source, packet.destination, packet.port, -1, packet.data) } } + super.tryEnqueuePacket(sourceSide, packet) + } + + override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet) { + super.relayPacket(sourceSide, packet) + onSwitchActivity() } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala new file mode 100644 index 000000000..9b14c128a --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala @@ -0,0 +1,27 @@ +package li.cil.oc.common.tileentity.traits + +import li.cil.oc.server.PacketSender + +import scala.collection.mutable + +trait SwitchLike extends Hub { + def relayDelay: Int + + def isWirelessEnabled: Boolean + + def isLinkedEnabled: Boolean + + val computers = mutable.Buffer.empty[AnyRef] + + val openPorts = mutable.Map.empty[AnyRef, mutable.Set[Int]] + + var lastMessage = 0L + + def onSwitchActivity(): Unit = { + val now = System.currentTimeMillis() + if (now - lastMessage >= (relayDelay - 1) * 50) { + lastMessage = now + PacketSender.sendSwitchActivity(this) + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala b/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala index b2e54e940..5f17cf9df 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala @@ -2,7 +2,7 @@ package li.cil.oc.integration.computercraft import dan200.computercraft.api.ComputerCraftAPI import dan200.computercraft.api.peripheral.IPeripheralProvider -import li.cil.oc.common.tileentity.Switch +import li.cil.oc.common.tileentity.traits.SwitchLike import net.minecraft.world.World object PeripheralProvider extends IPeripheralProvider { @@ -11,7 +11,7 @@ object PeripheralProvider extends IPeripheralProvider { } override def getPeripheral(world: World, x: Int, y: Int, z: Int, side: Int) = world.getTileEntity(x, y, z) match { - case switch: Switch => new SwitchPeripheral(switch) + case switch: SwitchLike => new SwitchPeripheral(switch) case _ => null } } diff --git a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala index 804b6bb47..234e93e4b 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala @@ -8,8 +8,7 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.machine.Context import li.cil.oc.api.network.Component -import li.cil.oc.common.tileentity.AccessPoint -import li.cil.oc.common.tileentity.Switch +import li.cil.oc.common.tileentity.traits.SwitchLike import li.cil.oc.util.ResultWrapper._ import net.minecraftforge.common.util.ForgeDirection @@ -17,7 +16,7 @@ import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsScala._ import scala.collection.mutable -class SwitchPeripheral(val switch: Switch) extends IPeripheral { +class SwitchPeripheral(val switch: SwitchLike) extends IPeripheral { private val methods = Map[String, (IComputerAccess, ILuaContext, Array[AnyRef]) => Array[AnyRef]]( // Generic modem methods. "open" -> ((computer, context, arguments) => { @@ -86,7 +85,10 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral { // OC specific. "isAccessPoint" -> ((computer, context, arguments) => { - result(switch.isInstanceOf[AccessPoint]) + result(switch.isWirelessEnabled) + }), + "isTunnel" -> ((computer, context, arguments) => { + result(switch.isLinkedEnabled) }), "maxPacketSize" -> ((computer, context, arguments) => { result(Settings.get.maxNetworkPacketSize) diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index df0ba86e4..406462a4a 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -392,7 +392,7 @@ object PacketSender { pb.sendToPlayersNearTileEntity(t) } - def sendSwitchActivity(t: tileentity.Switch) { + def sendSwitchActivity(t: tileentity.traits.SwitchLike) { val pb = new SimplePacketBuilder(PacketType.SwitchActivity) pb.writeTileEntity(t) diff --git a/src/main/scala/li/cil/oc/server/component/LinkedCard.scala b/src/main/scala/li/cil/oc/server/component/LinkedCard.scala index be88a0bc4..62fadcb94 100644 --- a/src/main/scala/li/cil/oc/server/component/LinkedCard.scala +++ b/src/main/scala/li/cil/oc/server/component/LinkedCard.scala @@ -12,7 +12,7 @@ import net.minecraft.nbt.NBTTagCompound import scala.collection.convert.WrapAsScala._ -class LinkedCard extends prefab.ManagedEnvironment { +class LinkedCard extends prefab.ManagedEnvironment with QuantumNetwork.QuantumNode { override val node = Network.newNode(this, Visibility.Network). withComponent("tunnel", Visibility.Neighbors). withConnector(). @@ -28,8 +28,8 @@ class LinkedCard extends prefab.ManagedEnvironment { // 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, null, 0, args.asInstanceOf[java.lang.Iterable[AnyRef]].toArray) if (node.tryChangeBuffer(-(packet.size / 32.0 + Settings.get.wirelessCostPerRange * Settings.get.maxWirelessRange * 5))) { - for (card <- endpoints) { - card.receivePacket(packet) + for (endpoint <- endpoints) { + endpoint.receivePacket(packet) } result(true) } diff --git a/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala b/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala index ce56d5f01..ca6284836 100644 --- a/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala +++ b/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala @@ -1,20 +1,27 @@ package li.cil.oc.server.network -import li.cil.oc.server.component.LinkedCard +import li.cil.oc.api.network.Packet import scala.collection.mutable // Just because the name if so fancy! object QuantumNetwork { - val tunnels = mutable.Map.empty[String, mutable.WeakHashMap[LinkedCard, Unit]] + val tunnels = mutable.Map.empty[String, mutable.WeakHashMap[QuantumNode, Unit]] - def add(card: LinkedCard) { + def add(card: QuantumNode) { tunnels.getOrElseUpdate(card.tunnel, mutable.WeakHashMap.empty).put(card, Unit) } - def remove(card: LinkedCard) { + def remove(card: QuantumNode) { tunnels.get(card.tunnel).foreach(_.remove(card)) } - def getEndpoints(tunnel: String) = tunnels.get(tunnel).fold(Iterable.empty[LinkedCard])(_.keys) + def getEndpoints(tunnel: String) = tunnels.get(tunnel).fold(Iterable.empty[QuantumNode])(_.keys) + + trait QuantumNode { + def tunnel: String + + def receivePacket(packet: Packet): Unit + } + }