diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index e99801f19..b35c909a4 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -7,7 +7,6 @@ import appeng.api.util.AEPartLocation import li.cil.oc._ import li.cil.oc.api.Network import li.cil.oc.api.detail.ItemInfo -import li.cil.oc.common.item.traits import li.cil.oc.api.internal.Colored import li.cil.oc.api.internal.Rack import li.cil.oc.api.internal.Server @@ -30,6 +29,7 @@ import li.cil.oc.common.recipe.Recipes import li.cil.oc.common.tileentity.Robot import li.cil.oc.common.tileentity.traits.power import li.cil.oc.integration.Mods +import li.cil.oc.integration.util import li.cil.oc.server.component.Keyboard import li.cil.oc.server.machine.Callbacks import li.cil.oc.server.machine.Machine @@ -140,6 +140,15 @@ object EventHandler { } } + def scheduleWirelessRedstone(rs: server.component.RedstoneWireless) { + if (SideTracker.isServer) pendingServer.synchronized { + pendingServer += (() => if (rs.node.network != null) { + util.WirelessRedstone.addReceiver(rs) + util.WirelessRedstone.updateOutput(rs) + }) + } + } + @SubscribeEvent def onAttachCapabilitiesItemStack(event: AttachCapabilitiesEvent[ItemStack]): Unit = { if (!event.getCapabilities.containsKey(traits.Chargeable.KEY)) { @@ -182,7 +191,7 @@ object EventHandler { } @SubscribeEvent - def onServerTick(e: ServerTickEvent) = if (e.phase == TickEvent.Phase.START) { + def onServerTick(e: ServerTickEvent): Any = if (e.phase == TickEvent.Phase.START) { pendingServer.synchronized { val adds = pendingServer.toArray pendingServer.clear() diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 345f8c522..d961d8d76 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -37,6 +37,7 @@ object Mods { val EnderStorage = new SimpleMod(IDs.EnderStorage) val Thaumcraft = new SimpleMod(IDs.Thaumcraft) val Charset = new SimpleMod(IDs.Charset) + val WirelessRedstoneCBE = new SimpleMod(IDs.WirelessRedstoneCBE) // ----------------------------------------------------------------------- // @@ -56,6 +57,7 @@ object Mods { integration.enderstorage.ModEnderStorage, integration.thaumcraft.ModThaumcraft, integration.charset.ModCharset, + integration.wrcbe.ModWRCBE, // We go late to ensure all other mod integration is done, e.g. to // allow properly checking if wireless redstone is present. @@ -102,6 +104,7 @@ object Mods { final val EnderStorage = "enderstorage" final val Thaumcraft = "thaumcraft" final val Charset = "charset" + final val WirelessRedstoneCBE = "wrcbe" } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala index 8ca2a01bd..c856b60e3 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala @@ -12,6 +12,7 @@ import li.cil.oc.common.item.Delegator import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.RedstoneAware import li.cil.oc.integration.util.BundledRedstone +import li.cil.oc.integration.util.WirelessRedstone import li.cil.oc.server.component import net.minecraft.item.ItemStack @@ -25,12 +26,17 @@ object DriverRedstoneCard extends Item with HostAware { else { val isAdvanced = tier(stack) == Tier.Two val hasBundled = BundledRedstone.isAvailable && isAdvanced + val hasWireless = WirelessRedstone.isAvailable && isAdvanced host match { case redstone: BundledRedstoneAware if hasBundled => - new component.Redstone.Bundled(redstone) + if (hasWireless) new component.Redstone.BundledWireless(redstone) + else new component.Redstone.Bundled(redstone) case redstone: RedstoneAware => - new component.Redstone.Vanilla(redstone) - case _ => null + if (hasWireless) new component.Redstone.VanillaWireless(redstone) + else new component.Redstone.Vanilla(redstone) + case _ => + if (hasWireless) new component.Redstone.Wireless(host) + else null } } @@ -47,8 +53,10 @@ object DriverRedstoneCard extends Item with HostAware { if (worksWith(stack)) { val isAdvanced = tier(stack) == Tier.Two val hasBundled = BundledRedstone.isAvailable && isAdvanced + val hasWireless = WirelessRedstone.isAvailable && isAdvanced if (hasBundled) { - classOf[component.Redstone.Bundled] + if (hasWireless) classOf[component.Redstone.BundledWireless] + else classOf[component.Redstone.Bundled] } else { classOf[component.Redstone.Vanilla] diff --git a/src/main/scala/li/cil/oc/integration/util/WirelessRedstone.scala b/src/main/scala/li/cil/oc/integration/util/WirelessRedstone.scala new file mode 100644 index 000000000..dd4e64f13 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/util/WirelessRedstone.scala @@ -0,0 +1,50 @@ +package li.cil.oc.integration.util + +import li.cil.oc.server.component.RedstoneWireless + +import scala.collection.mutable + +object WirelessRedstone { + val systems = mutable.Set.empty[WirelessRedstoneSystem] + + def isAvailable: Boolean = systems.nonEmpty + + def addReceiver(rs: RedstoneWireless) { + systems.foreach(system => try system.addReceiver(rs) catch { + case _: Throwable => // Ignore + }) + } + + def removeReceiver(rs: RedstoneWireless) { + systems.foreach(system => try system.removeReceiver(rs) catch { + case _: Throwable => // Ignore + }) + } + + def updateOutput(rs: RedstoneWireless) { + systems.foreach(system => try system.updateOutput(rs) catch { + case _: Throwable => // Ignore + }) + } + + def removeTransmitter(rs: RedstoneWireless) { + systems.foreach(system => try system.removeTransmitter(rs) catch { + case _: Throwable => // Ignore + }) + } + + def getInput(rs: RedstoneWireless): Boolean = systems.exists(_.getInput(rs)) + + trait WirelessRedstoneSystem { + def addReceiver(rs: RedstoneWireless) + + def removeReceiver(rs: RedstoneWireless) + + def updateOutput(rs: RedstoneWireless) + + def removeTransmitter(rs: RedstoneWireless) + + def getInput(rs: RedstoneWireless): Boolean + } + +} diff --git a/src/main/scala/li/cil/oc/integration/wrcbe/ModWRCBE.scala b/src/main/scala/li/cil/oc/integration/wrcbe/ModWRCBE.scala new file mode 100644 index 000000000..4bf9de59d --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/wrcbe/ModWRCBE.scala @@ -0,0 +1,13 @@ +package li.cil.oc.integration.wrcbe + +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.WirelessRedstone + +object ModWRCBE extends ModProxy { + override def getMod: Mods.SimpleMod = Mods.WirelessRedstoneCBE + + override def initialize() { + WirelessRedstone.systems += WirelessRedstoneCBE + } +} diff --git a/src/main/scala/li/cil/oc/integration/wrcbe/WirelessRedstoneCBE.scala b/src/main/scala/li/cil/oc/integration/wrcbe/WirelessRedstoneCBE.scala new file mode 100644 index 000000000..5ee787d48 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/wrcbe/WirelessRedstoneCBE.scala @@ -0,0 +1,43 @@ +package li.cil.oc.integration.wrcbe + +import codechicken.wirelessredstone.manager.RedstoneEther +import li.cil.oc.integration.util.WirelessRedstone.WirelessRedstoneSystem +import li.cil.oc.server.component.RedstoneWireless + +import scala.language.reflectiveCalls + +object WirelessRedstoneCBE extends WirelessRedstoneSystem { + def addTransmitter(rs: RedstoneWireless) { + if (rs.wirelessOutput && rs.wirelessFrequency > 0) { + RedstoneEther.server.addTransmittingDevice(rs) + } + } + + def removeTransmitter(rs: RedstoneWireless) { + if (rs.wirelessFrequency > 0) { + RedstoneEther.server.removeTransmittingDevice(rs) + } + } + + def addReceiver(rs: RedstoneWireless) { + RedstoneEther.server.addReceivingDevice(rs) + if (rs.wirelessFrequency > 0) { + rs.wirelessInput = RedstoneEther.server.isFreqOn(rs.wirelessFrequency) + } + } + + def removeReceiver(rs: RedstoneWireless) { + RedstoneEther.server.removeReceivingDevice(rs) + } + + def updateOutput(rs: RedstoneWireless) { + if (rs.wirelessOutput) { + addTransmitter(rs) + } + else { + removeTransmitter(rs) + } + } + + def getInput(rs: RedstoneWireless): Boolean = rs.wirelessInput +} diff --git a/src/main/scala/li/cil/oc/server/component/Redstone.scala b/src/main/scala/li/cil/oc/server/component/Redstone.scala index c1d8d384e..b6571aaf4 100644 --- a/src/main/scala/li/cil/oc/server/component/Redstone.scala +++ b/src/main/scala/li/cil/oc/server/component/Redstone.scala @@ -1,10 +1,16 @@ package li.cil.oc.server.component +import java.util + +import li.cil.oc.Constants +import li.cil.oc.api.driver.DeviceInfo.{DeviceAttribute,DeviceClass} import li.cil.oc.api.network.EnvironmentHost import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.RedstoneAware import li.cil.oc.server.component +import scala.collection.convert.WrapAsJava._ + object Redstone { class Vanilla(val redstone: EnvironmentHost with RedstoneAware) @@ -13,4 +19,23 @@ object Redstone { class Bundled(val redstone: EnvironmentHost with BundledRedstoneAware) extends component.RedstoneVanilla with component.RedstoneBundled + class Wireless(val redstone: EnvironmentHost) + extends component.RedstoneWireless + + class VanillaWireless(val redstone: EnvironmentHost with RedstoneAware) + extends component.RedstoneVanilla with component.RedstoneWireless + + class BundledWireless(val redstone: EnvironmentHost with BundledRedstoneAware) + extends component.RedstoneVanilla with component.RedstoneBundled with component.RedstoneWireless { + private final lazy val deviceInfo = Map( + DeviceAttribute.Class -> DeviceClass.Communication, + DeviceAttribute.Description -> "Combined redstone controller", + DeviceAttribute.Vendor -> Constants.DeviceInfo.DefaultVendor, + DeviceAttribute.Product -> "Rx900-M", + DeviceAttribute.Capacity -> "65536", + DeviceAttribute.Width -> "16" + ) + + override def getDeviceInfo: util.Map[String, String] = deviceInfo + } } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala new file mode 100644 index 000000000..5b85bb8c0 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala @@ -0,0 +1,163 @@ +package li.cil.oc.server.component + +import codechicken.lib.vec.Vector3 +import codechicken.wirelessredstone.api.WirelessReceivingDevice +import codechicken.wirelessredstone.api.WirelessTransmittingDevice +import li.cil.oc.Constants +import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute +import li.cil.oc.api.driver.DeviceInfo.DeviceClass +import li.cil.oc.Settings +import li.cil.oc.api.driver.DeviceInfo +import li.cil.oc.api.network.EnvironmentHost +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._ +import li.cil.oc.common.EventHandler +import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs +import li.cil.oc.integration.Mods +import li.cil.oc.integration.util +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.fml.common.Optional + +import scala.collection.convert.WrapAsJava._ + +@Optional.InterfaceList(Array( + new Optional.Interface(iface = "codechicken.wirelessredstone.api.WirelessReceivingDevice", modid = Mods.IDs.WirelessRedstoneCBE), + new Optional.Interface(iface = "codechicken.wirelessredstone.api.WirelessTransmittingDevice", modid = Mods.IDs.WirelessRedstoneCBE) +)) +trait RedstoneWireless extends RedstoneSignaller with WirelessReceivingDevice with WirelessTransmittingDevice with DeviceInfo { + def redstone: EnvironmentHost + + var wirelessFrequency = 0 + + var wirelessInput = false + + var wirelessOutput = false + + // ----------------------------------------------------------------------- // + + private final lazy val deviceInfo = Map( + DeviceAttribute.Class -> DeviceClass.Communication, + DeviceAttribute.Description -> "Wireless redstone controller", + DeviceAttribute.Vendor -> Constants.DeviceInfo.DefaultVendor, + DeviceAttribute.Product -> "Rw400-M", + DeviceAttribute.Capacity -> "1", + DeviceAttribute.Width -> "1" + ) + + override def getDeviceInfo: java.util.Map[String, String] = deviceInfo + + // ----------------------------------------------------------------------- // + + @Callback(doc = """function():number -- Get the wireless redstone input.""") + def getWirelessInput(context: Context, args: Arguments): Array[AnyRef] = { + wirelessInput = util.WirelessRedstone.getInput(this) + result(wirelessInput) + } + + @Callback(direct = true, doc = """function():boolean -- Get the wireless redstone output.""") + def getWirelessOutput(context: Context, args: Arguments): Array[AnyRef] = result(wirelessOutput) + + @Callback(doc = """function(value:boolean):boolean -- Set the wireless redstone output.""") + def setWirelessOutput(context: Context, args: Arguments): Array[AnyRef] = { + val oldValue = wirelessOutput + val newValue = args.checkBoolean(0) + + if (oldValue != newValue) { + wirelessOutput = newValue + + util.WirelessRedstone.updateOutput(this) + + if (Settings.get.redstoneDelay > 0) + context.pause(Settings.get.redstoneDelay) + } + + result(oldValue) + } + + @Callback(direct = true, doc = """function():number -- Get the currently set wireless redstone frequency.""") + def getWirelessFrequency(context: Context, args: Arguments): Array[AnyRef] = result(wirelessFrequency) + + @Callback(doc = """function(frequency:number):number -- Set the wireless redstone frequency to use.""") + def setWirelessFrequency(context: Context, args: Arguments): Array[AnyRef] = { + val oldValue = wirelessFrequency + val newValue = args.checkInteger(0) + + if (oldValue != newValue) { + util.WirelessRedstone.removeReceiver(this) + util.WirelessRedstone.removeTransmitter(this) + + wirelessFrequency = newValue + wirelessInput = false + wirelessOutput = false + + util.WirelessRedstone.addReceiver(this) + + context.pause(0.5) + } + + result(oldValue) + } + + // ----------------------------------------------------------------------- // + + @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) + override def updateDevice(frequency: Int, on: Boolean) { + if (frequency == wirelessFrequency && on != wirelessInput) { + wirelessInput = on + onRedstoneChanged(RedstoneChangedEventArgs(null, if (on) 0 else 1, if (on) 1 else 0)) + } + } + + @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) + override def getTransmitPos = new Vector3(redstone.xPosition, redstone.yPosition, redstone.zPosition) + + @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) + override def getDimension: Int = redstone.world.provider.getDimension + + @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) + override def getFreq: Int = wirelessFrequency + + @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) + override def getAttachedEntity = null + + // ----------------------------------------------------------------------- // + + override def onConnect(node: Node) { + super.onConnect(node) + if (node == this.node) { + EventHandler.scheduleWirelessRedstone(this) + } + } + + override def onDisconnect(node: Node) { + super.onDisconnect(node) + if (node == this.node) { + util.WirelessRedstone.removeReceiver(this) + util.WirelessRedstone.removeTransmitter(this) + wirelessOutput = false + wirelessFrequency = 0 + } + } + + // ----------------------------------------------------------------------- // + + private final val WirelessFrequencyTag = "wirelessFrequency" + private final val WirelessInputTag = "wirelessInput" + private final val WirelessOutputTag = "wirelessOutput" + + override def load(nbt: NBTTagCompound) { + super.load(nbt) + wirelessFrequency = nbt.getInteger(WirelessFrequencyTag) + wirelessInput = nbt.getBoolean(WirelessInputTag) + wirelessOutput = nbt.getBoolean(WirelessOutputTag) + } + + override def save(nbt: NBTTagCompound) { + super.save(nbt) + nbt.setInteger(WirelessFrequencyTag, wirelessFrequency) + nbt.setBoolean(WirelessInputTag, wirelessInput) + nbt.setBoolean(WirelessOutputTag, wirelessOutput) + } +}