Merge branch 'master-MC1.7.10' into master-MC1.10

# Conflicts:
#	src/main/scala/li/cil/oc/client/PacketHandler.scala
#	src/main/scala/li/cil/oc/common/block/RedstoneAware.scala
#	src/main/scala/li/cil/oc/common/tileentity/Charger.scala
#	src/main/scala/li/cil/oc/common/tileentity/Print.scala
#	src/main/scala/li/cil/oc/common/tileentity/Rack.scala
#	src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala
#	src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala
#	src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala
#	src/main/scala/li/cil/oc/integration/computercraft/BundledRedstoneProvider.scala
#	src/main/scala/li/cil/oc/server/PacketSender.scala
This commit is contained in:
payonel 2018-11-03 14:12:12 -07:00
commit ade302d15c
19 changed files with 364 additions and 126 deletions

View File

@ -373,7 +373,7 @@ oc:tooltip.UpgradeExperience=This upgrade allows robots to accumulate experience
oc:tooltip.UpgradeGenerator=Can be used to generate energy from fuel on the go. Burns items to generate energy over time, based on their fuel value.[nl] §fEfficiency§7: §a%s%%§7 oc:tooltip.UpgradeGenerator=Can be used to generate energy from fuel on the go. Burns items to generate energy over time, based on their fuel value.[nl] §fEfficiency§7: §a%s%%§7
oc:tooltip.UpgradeHover=This upgrade allows robots to fly higher above the ground without having to climb walls.[nl] Maximum height: §f%s§7 oc:tooltip.UpgradeHover=This upgrade allows robots to fly higher above the ground without having to climb walls.[nl] Maximum height: §f%s§7
oc:tooltip.UpgradeInventory=This upgrade provides inventory space to a robot or drone. Without one of these, they will not be able to store items internally. oc:tooltip.UpgradeInventory=This upgrade provides inventory space to a robot or drone. Without one of these, they will not be able to store items internally.
oc:tooltip.UpgradeInventoryController=This upgrade allows robots and drones more control in how it interacts with external inventories, and allows robots to swap their equipped tool with an item in their inventory. oc:tooltip.UpgradeInventoryController=This upgrade allows robots and drones more control in how it interact with external inventories, and allows robots to swap their equipped tool with an item in their inventory.
oc:tooltip.UpgradeMF=Allows adapters to access blocks they are not adjacent to. oc:tooltip.UpgradeMF=Allows adapters to access blocks they are not adjacent to.
oc:tooltip.UpgradeMF.Linked=§fConnection established§7 oc:tooltip.UpgradeMF.Linked=§fConnection established§7
oc:tooltip.UpgradeMF.Unlinked=§fNo connection§7 oc:tooltip.UpgradeMF.Unlinked=§fNo connection§7

View File

@ -59,7 +59,9 @@ local function loadConfig()
save = {{"control", "s"}}, save = {{"control", "s"}},
close = {{"control", "w"}}, close = {{"control", "w"}},
find = {{"control", "f"}}, find = {{"control", "f"}},
findnext = {{"control", "g"}, {"control", "n"}, {"f3"}} findnext = {{"control", "g"}, {"control", "n"}, {"f3"}},
cut = {{"control", "k"}},
uncut = {{"control", "u"}}
} }
-- Generate config file if it didn't exist. -- Generate config file if it didn't exist.
if not config then if not config then
@ -87,6 +89,11 @@ local buffer = {}
local scrollX, scrollY = 0, 0 local scrollX, scrollY = 0, 0
local config = loadConfig() local config = loadConfig()
local cutBuffer = {}
-- cutting is true while we're in a cutting operation and set to false when cursor changes lines
-- basically, whenever you change lines, the cutting operation ends, so the next time you cut a new buffer will be created
local cutting = false
local getKeyBindHandler -- forward declaration for refind() local getKeyBindHandler -- forward declaration for refind()
local function helpStatusText() local function helpStatusText()
@ -110,7 +117,9 @@ local function helpStatusText()
end end
return prettifyKeybind("Save", "save") .. return prettifyKeybind("Save", "save") ..
prettifyKeybind("Close", "close") .. prettifyKeybind("Close", "close") ..
prettifyKeybind("Find", "find") prettifyKeybind("Find", "find") ..
prettifyKeybind("Cut", "cut") ..
prettifyKeybind("Uncut", "uncut")
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -240,7 +249,12 @@ local function setCursor(nbx, nby)
term.setCursor(nbx - scrollX, nby - scrollY) term.setCursor(nbx - scrollX, nby - scrollY)
--update with term lib --update with term lib
nbx, nby = getCursor() nbx, nby = getCursor()
gpu.set(x + w - 10, y + h, text.padLeft(string.format("%d,%d", nby, nbx), 10)) local locstring = string.format("%d,%d", nby, nbx)
if #cutBuffer > 0 then
locstring = string.format("(#%d) %s", #cutBuffer, locstring)
end
locstring = text.padLeft(locstring, 10)
gpu.set(x + w - #locstring, y + h, locstring)
end end
local function highlight(bx, by, length, enabled) local function highlight(bx, by, length, enabled)
@ -316,6 +330,7 @@ local function up(n)
if cby > 1 then if cby > 1 then
setCursor(cbx, cby - n) setCursor(cbx, cby - n)
end end
cutting = false
end end
local function down(n) local function down(n)
@ -324,6 +339,7 @@ local function down(n)
if cby < #buffer then if cby < #buffer then
setCursor(cbx, cby + n) setCursor(cbx, cby + n)
end end
cutting = false
end end
local function delete(fullRow) local function delete(fullRow)
@ -398,6 +414,7 @@ local function enter()
end end
setCursor(1, cby + 1) setCursor(1, cby + 1)
setStatus(helpStatusText()) setStatus(helpStatusText())
cutting = false
end end
local findText = "" local findText = ""
@ -452,6 +469,25 @@ local function find()
setStatus(helpStatusText()) setStatus(helpStatusText())
end end
local function cut()
if not cutting then
cutBuffer = {}
end
local cbx, cby = getCursor()
table.insert(cutBuffer, buffer[cby])
delete(true)
cutting = true
home()
end
local function uncut()
home()
for _, line in ipairs(cutBuffer) do
insert(line)
enter()
end
end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
local keyBindHandlers = { local keyBindHandlers = {
@ -542,7 +578,9 @@ local keyBindHandlers = {
findText = "" findText = ""
find() find()
end, end,
findnext = find findnext = find,
cut = cut,
uncut = uncut
} }
getKeyBindHandler = function(code) getKeyBindHandler = function(code)

View File

@ -499,9 +499,9 @@ object PacketHandler extends CommonPacketHandler {
def onRedstoneState(p: PacketParser) = def onRedstoneState(p: PacketParser) =
p.readTileEntity[RedstoneAware]() match { p.readTileEntity[RedstoneAware]() match {
case Some(t) => case Some(t) =>
t.isOutputEnabled = p.readBoolean() t.setOutputEnabled(p.readBoolean())
for (d <- EnumFacing.values) { for (d <- EnumFacing.values) {
t.output(d, p.readByte()) t.setOutput(d, p.readByte())
} }
case _ => // Invalid packet. case _ => // Invalid packet.
} }

View File

@ -30,7 +30,7 @@ abstract class RedstoneAware extends SimpleBlock /* with IRedNetOmniNode TODO MF
override def getWeakPower(state: IBlockState, world: IBlockAccess, pos: BlockPos, side: EnumFacing) = override def getWeakPower(state: IBlockState, world: IBlockAccess, pos: BlockPos, side: EnumFacing) =
world.getTileEntity(pos) match { world.getTileEntity(pos) match {
case redstone: tileentity.traits.RedstoneAware if side != null => redstone.output(side.getOpposite) max 0 case redstone: tileentity.traits.RedstoneAware if side != null => redstone.getOutput(side.getOpposite) max 0
case _ => super.getWeakPower(state, world, pos, side) case _ => super.getWeakPower(state, world, pos, side)
} }
@ -44,9 +44,9 @@ abstract class RedstoneAware extends SimpleBlock /* with IRedNetOmniNode TODO MF
case t: tileentity.traits.BundledRedstoneAware => for (side <- EnumFacing.values) { case t: tileentity.traits.BundledRedstoneAware => for (side <- EnumFacing.values) {
world.getBlock(position.offset(side)) match { world.getBlock(position.offset(side)) match {
case block: IRedNetNetworkContainer => case block: IRedNetNetworkContainer =>
case _ => for (color <- 0 until 16) { case _ => for (color <- 0 until 16) {
t.rednetInput(side, color, 0) t.setRednetInput(side, color, 0)
} }
} }
} }
case _ => case _ =>
@ -66,13 +66,13 @@ abstract class RedstoneAware extends SimpleBlock /* with IRedNetOmniNode TODO MF
override def getOutputValue(world: World, x: Int, y: Int, z: Int, side: EnumFacing, color: Int) = override def getOutputValue(world: World, x: Int, y: Int, z: Int, side: EnumFacing, color: Int) =
world.getTileEntity(x, y, z) match { world.getTileEntity(x, y, z) match {
case t: tileentity.traits.BundledRedstoneAware => t.bundledOutput(side, color) case t: tileentity.traits.BundledRedstoneAware => t.getBundledOutput(side, color)
case _ => 0 case _ => 0
} }
override def getOutputValues(world: World, x: Int, y: Int, z: Int, side: EnumFacing) = override def getOutputValues(world: World, x: Int, y: Int, z: Int, side: EnumFacing) =
world.getTileEntity(x, y, z) match { world.getTileEntity(x, y, z) match {
case t: tileentity.traits.BundledRedstoneAware => t.bundledOutput(side) case t: tileentity.traits.BundledRedstoneAware => t.getBundledOutput(side)
case _ => Array.fill(16)(0) case _ => Array.fill(16)(0)
} }
@ -81,7 +81,7 @@ abstract class RedstoneAware extends SimpleBlock /* with IRedNetOmniNode TODO MF
override def onInputsChanged(world: World, x: Int, y: Int, z: Int, side: EnumFacing, inputValues: Array[Int]) = override def onInputsChanged(world: World, x: Int, y: Int, z: Int, side: EnumFacing, inputValues: Array[Int]) =
world.getTileEntity(x, y, z) match { world.getTileEntity(x, y, z) match {
case t: tileentity.traits.BundledRedstoneAware => for (color <- 0 until 16) { case t: tileentity.traits.BundledRedstoneAware => for (color <- 0 until 16) {
t.rednetInput(side, color, inputValues(color)) t.setRednetInput(side, color, inputValues(color))
} }
case _ => case _ =>
} }

View File

@ -205,7 +205,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
override def updateRedstoneInput(side: EnumFacing) { override def updateRedstoneInput(side: EnumFacing) {
super.updateRedstoneInput(side) super.updateRedstoneInput(side)
val signal = math.max(0, math.min(15, EnumFacing.values.map(input).max)) val signal = getInput.max min 15
if (invertSignal) chargeSpeed = (15 - signal) / 15.0 if (invertSignal) chargeSpeed = (15 - signal) / 15.0
else chargeSpeed = signal / 15.0 else chargeSpeed = signal / 15.0

View File

@ -20,6 +20,7 @@ import net.minecraft.util.math.RayTraceResult
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly import net.minecraftforge.fml.relauncher.SideOnly
import scala.collection.convert.WrapAsJava._
class Print(val canToggle: Option[() => Boolean], val scheduleUpdate: Option[Int => Unit], val onStateChange: Option[() => Unit]) extends traits.TileEntity with traits.RedstoneAware with traits.RotatableTile { class Print(val canToggle: Option[() => Boolean], val scheduleUpdate: Option[Int => Unit], val onStateChange: Option[() => Unit]) extends traits.TileEntity with traits.RedstoneAware with traits.RotatableTile {
def this() = this(None, None, None) def this() = this(None, None, None)
@ -113,6 +114,14 @@ class Print(val canToggle: Option[() => Boolean], val scheduleUpdate: Option[Int
false false
} }
private def buildValueSet(value: Int): util.Map[AnyRef, AnyRef] = {
val map: util.Map[AnyRef, AnyRef] = new util.HashMap[AnyRef, AnyRef]()
EnumFacing.values.foreach {
side => map.put(new java.lang.Integer(side.ordinal), new java.lang.Integer(value))
}
map
}
def toggleState(): Unit = { def toggleState(): Unit = {
if (canToggle.fold(true)(_.apply())) { if (canToggle.fold(true)(_.apply())) {
state = !state state = !state
@ -142,7 +151,7 @@ class Print(val canToggle: Option[() => Boolean], val scheduleUpdate: Option[Int
def updateRedstone(): Unit = { def updateRedstone(): Unit = {
if (data.emitRedstone) { if (data.emitRedstone) {
EnumFacing.values().foreach(output(_, if (data.emitRedstone(state)) data.redstoneLevel else 0)) setOutput(buildValueSet(if (data.emitRedstone(state)) data.redstoneLevel else 0))
} }
} }

View File

@ -265,7 +265,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
override def markChanged(slot: Int): Unit = { override def markChanged(slot: Int): Unit = {
hasChanged.synchronized(hasChanged(slot) = true) hasChanged.synchronized(hasChanged(slot) = true)
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -313,7 +313,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
override def markDirty() { override def markDirty() {
super.markDirty() super.markDirty()
if (isServer) { if (isServer) {
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
ServerPacketSender.sendRackInventory(this) ServerPacketSender.sendRackInventory(this)
} }
else { else {
@ -368,7 +368,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
ServerPacketSender.sendRackMountableData(this, slot) ServerPacketSender.sendRackMountableData(this, slot)
world.notifyNeighborsOfStateChange(getPos, getBlockType) world.notifyNeighborsOfStateChange(getPos, getBlockType)
// These are working state dependent, so recompute them. // These are working state dependent, so recompute them.
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
} }
// Power mountables without requiring them to be connected to the outside. // Power mountables without requiring them to be connected to the outside.

View File

@ -190,9 +190,9 @@ class RobotProxy(val robot: Robot) extends traits.Computer with traits.PowerInfo
override protected[tileentity] val _bundledOutput = robot._bundledOutput override protected[tileentity] val _bundledOutput = robot._bundledOutput
override def isOutputEnabled = robot.isOutputEnabled override def isOutputEnabled: Boolean = robot.isOutputEnabled
override def isOutputEnabled_=(value: Boolean) = robot.isOutputEnabled_=(value) override def setOutputEnabled(value: Boolean): Unit = robot.setOutputEnabled(value)
override def checkRedstoneInputChanged() = robot.checkRedstoneInputChanged() override def checkRedstoneInputChanged() = robot.checkRedstoneInputChanged()

View File

@ -6,6 +6,7 @@ import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
import mrtjp.projectred.api.IBundledTile import mrtjp.projectred.api.IBundledTile
import net.minecraftforge.fml.common.Optional import net.minecraftforge.fml.common.Optional
import java.util
/* TODO RedLogic /* TODO RedLogic
import mods.immibis.redlogic.api.wiring.IBundledEmitter import mods.immibis.redlogic.api.wiring.IBundledEmitter
@ -36,8 +37,8 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledTile /* with IBund
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def isOutputEnabled_=(value: Boolean) = { override def setOutputEnabled(value: Boolean): Unit = {
if (value != isOutputEnabled) { if (value != _isOutputEnabled) {
if (!value) { if (!value) {
for (i <- _bundledOutput.indices) { for (i <- _bundledOutput.indices) {
for (j <- _bundledOutput(i).indices) { for (j <- _bundledOutput(i).indices) {
@ -46,40 +47,71 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledTile /* with IBund
} }
} }
} }
super.isOutputEnabled_=(value) super.setOutputEnabled(value)
} }
def bundledInput(side: EnumFacing) = def getBundledInput: Array[Array[Int]] = {
(_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max) (0 until 6).map(side => (0 until 16).map(color => _bundledInput(side)(color) max _rednetInput(side)(color) max 0).toArray).toArray
}
def bundledInput(side: EnumFacing, newBundledInput: Array[Int]): Unit = { private def checkSide(side: EnumFacing): Int = {
val index = side.ordinal
if (index >= 6) throw new IndexOutOfBoundsException(s"Bad side $side")
index
}
private def checkColor(color: Int): Int = {
if (color < 0 || color >= 16) throw new IndexOutOfBoundsException(s"Bad color $color")
color
}
def getBundledInput(side: EnumFacing): Array[Int] = {
val sideIndex = checkSide(side)
val bundled = _bundledInput(sideIndex)
val rednet = _rednetInput(sideIndex)
(bundled, rednet).zipped.map((a, b) => a max b max 0)
}
def getBundledInput(side: EnumFacing, color: Int): Int = {
val sideIndex = checkSide(side)
val colorIndex = checkColor(color)
val bundled = _bundledInput(sideIndex)(colorIndex)
val rednet = _rednetInput(sideIndex)(colorIndex)
bundled max rednet max 0
}
def setBundledInput(side: EnumFacing, color: Int, newValue: Int): Unit = {
updateInput(_bundledInput, side, color, newValue)
}
def setBundledInput(side: EnumFacing, newBundledInput: Array[Int]): Unit = {
for (color <- 0 until 16) { for (color <- 0 until 16) {
updateInput(_bundledInput, side, color, if (newBundledInput == null) 0 else newBundledInput(color)) val value = if (newBundledInput == null || color >= newBundledInput.length) 0 else newBundledInput(color)
setBundledInput(side, color, value)
} }
} }
def rednetInput(side: EnumFacing, color: Int, value: Int): Unit = updateInput(_rednetInput, side, color, value) def setRednetInput(side: EnumFacing, color: Int, value: Int): Unit = updateInput(_rednetInput, side, color, value)
def updateInput(inputs: Array[Array[Int]], side: EnumFacing, color: Int, newValue: Int): Unit = { def updateInput(inputs: Array[Array[Int]], side: EnumFacing, color: Int, newValue: Int): Unit = {
val oldValue = inputs(side.ordinal())(color) val sideIndex = checkSide(side)
val colorIndex = checkColor(color)
val oldValue = inputs(sideIndex)(colorIndex)
if (oldValue != newValue) { if (oldValue != newValue) {
inputs(sideIndex)(colorIndex) = newValue
if (oldValue != -1) { if (oldValue != -1) {
onRedstoneInputChanged(RedstoneChangedEventArgs(side, oldValue, newValue, color)) onRedstoneInputChanged(RedstoneChangedEventArgs(side, oldValue, newValue, colorIndex))
} }
inputs(side.ordinal())(color) = newValue
} }
} }
def bundledInput(side: EnumFacing, color: Int) = def getBundledOutput: Array[Array[Int]] = _bundledInput
math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
def bundledOutput(side: EnumFacing) = _bundledOutput(toLocal(side).ordinal()) def getBundledOutput(side: EnumFacing): Array[Int] = _bundledOutput(checkSide(toLocal(side)))
def bundledOutput(side: EnumFacing, color: Int): Int = bundledOutput(side)(color) def getBundledOutput(side: EnumFacing, color: Int): Int = getBundledOutput(side)(checkColor(color))
def bundledOutput(side: EnumFacing, color: Int, value: Int): Unit = if (value != bundledOutput(side, color)) {
_bundledOutput(toLocal(side).ordinal())(color) = value
def notifyChangedSide(side: EnumFacing): Unit = {
/* TODO MFR /* TODO MFR
if (Mods.MineFactoryReloaded.isAvailable) { if (Mods.MineFactoryReloaded.isAvailable) {
val blockPos = BlockPosition(x, y, z).offset(side) val blockPos = BlockPosition(x, y, z).offset(side)
@ -93,11 +125,50 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledTile /* with IBund
onRedstoneOutputChanged(side) onRedstoneOutputChanged(side)
} }
def setBundledOutput(side: EnumFacing, color: Int, value: Int): Boolean = if (value != getBundledOutput(side, color)) {
_bundledOutput(checkSide(toLocal(side)))(checkColor(color)) = value
notifyChangedSide(side)
true
} else false
def setBundledOutput(side: EnumFacing, values: util.Map[_, _]): Boolean = {
val sideIndex = toLocal(side).ordinal
var changed: Boolean = false
(0 until 16).foreach(color => {
// due to a bug in our jnlua layer, I cannot loop the map
valueToInt(getObjectFuzzy(values, color)) match {
case Some(newValue: Int) =>
if (newValue != getBundledOutput(side, color)) {
_bundledOutput(sideIndex)(color) = newValue
changed = true
}
case _ =>
}
})
if (changed) {
notifyChangedSide(side)
}
changed
}
def setBundledOutput(values: util.Map[_, _]): Boolean = {
var changed: Boolean = false
EnumFacing.values.foreach(side => {
val sideIndex = toLocal(side).ordinal
// due to a bug in our jnlua layer, I cannot loop the map
getObjectFuzzy(values, sideIndex) match {
case Some(child: util.Map[_, _]) if setBundledOutput(side, child) => changed = true
case _ =>
}
})
changed
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def updateRedstoneInput(side: EnumFacing) { override def updateRedstoneInput(side: EnumFacing) {
super.updateRedstoneInput(side) super.updateRedstoneInput(side)
bundledInput(side, BundledRedstone.computeBundledInput(position, side)) setBundledInput(side, BundledRedstone.computeBundledInput(position, side))
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -162,7 +233,7 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledTile /* with IBund
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
/* TODO RedLogic /* TODO RedLogic
@Optional.Method(modid = Mods.IDs.RedLogic) @Optional.Method(modid = Mods.IDs.RedLogic)
def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = bundledOutput(EnumFacing.getOrientation(toDirection)).map(value => math.min(math.max(value, 0), 255).toByte) def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = getBundledOutput(EnumFacing.getOrientation(toDirection)).map(value => math.min(math.max(value, 0), 255).toByte)
@Optional.Method(modid = Mods.IDs.RedLogic) @Optional.Method(modid = Mods.IDs.RedLogic)
def onBundledInputChanged() = checkRedstoneInputChanged() def onBundledInputChanged() = checkRedstoneInputChanged()
@ -170,9 +241,8 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledTile /* with IBund
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Optional.Method(modid = Mods.IDs.ProjectRedTransmission) @Optional.Method(modid = Mods.IDs.ProjectRedTransmission)
override def canConnectBundled(side: Int): Boolean = isOutputEnabled override def canConnectBundled(side: Int): Boolean = _isOutputEnabled
@Optional.Method(modid = Mods.IDs.ProjectRedTransmission) @Optional.Method(modid = Mods.IDs.ProjectRedTransmission)
override def getBundledSignal(side: Int): Array[Byte] = bundledOutput(EnumFacing.getFront(side)).map(value => math.min(math.max(value, 0), 255).toByte) override def getBundledSignal(side: Int): Array[Byte] = getBundledOutput(EnumFacing.getFront(side)).map(value => math.min(math.max(value, 0), 255).toByte)
} }

View File

@ -188,7 +188,7 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
super.markDirty() super.markDirty()
if (isServer) { if (isServer) {
machine.onHostChanged() machine.onHostChanged()
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
} }
} }

View File

@ -1,5 +1,6 @@
package li.cil.oc.common.tileentity.traits package li.cil.oc.common.tileentity.traits
import java.util
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.common.EventHandler import li.cil.oc.common.EventHandler
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
@ -27,18 +28,18 @@ case class RedstoneChangedEventArgs (side: EnumFacing, oldValue: Int, newValue:
new Optional.Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = Mods.IDs.RedLogic) new Optional.Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = Mods.IDs.RedLogic)
)) ))
trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmitter with IRedstoneUpdatable TODO RedLogic */ { trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmitter with IRedstoneUpdatable TODO RedLogic */ {
protected[tileentity] val _input = Array.fill(6)(-1) protected[tileentity] val _input: Array[Int] = Array.fill(6)(-1)
protected[tileentity] val _output = Array.fill(6)(0) protected[tileentity] val _output: Array[Int] = Array.fill(6)(0)
protected var _isOutputEnabled = false protected var _isOutputEnabled: Boolean = false
protected var shouldUpdateInput = true def isOutputEnabled: Boolean = _isOutputEnabled
def isOutputEnabled = _isOutputEnabled protected var shouldUpdateInput: Boolean = true
def isOutputEnabled_=(value: Boolean) = { def setOutputEnabled(value: Boolean): Unit = {
if (value != isOutputEnabled) { if (value != _isOutputEnabled) {
_isOutputEnabled = value _isOutputEnabled = value
if (!value) { if (!value) {
for (i <- _output.indices) { for (i <- _output.indices) {
@ -47,12 +48,34 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
} }
onRedstoneOutputEnabledChanged() onRedstoneOutputEnabledChanged()
} }
this
} }
def input(side: EnumFacing) = _input(side.ordinal()) max 0 protected def getObjectFuzzy(map: util.Map[_, _], key: Int): Option[AnyRef] = {
val refMap: util.Map[AnyRef, AnyRef] = map.asInstanceOf[util.Map[AnyRef, AnyRef]]
if (refMap.containsKey(key))
Option(refMap.get(key))
else if (refMap.containsKey(new Integer(key)))
Option(refMap.get(new Integer(key)))
else if (refMap.containsKey(new Integer(key) * 1.0))
Option(refMap.get(new Integer(key) * 1.0))
else if (refMap.containsKey(key * 1.0))
Option(refMap.get(key * 1.0))
else
None
}
def input(side: EnumFacing, newInput: Int): Unit = { protected def valueToInt(value: AnyRef): Option[Int] = {
value match {
case Some(num: Number) => Option(num.intValue)
case _ => None
}
}
def getInput: Array[Int] = _input.map(math.max(_, 0))
def getInput(side: EnumFacing): Int = _input(side.ordinal) max 0
def setInput(side: EnumFacing, newInput: Int): Unit = {
val oldInput = _input(side.ordinal()) val oldInput = _input(side.ordinal())
_input(side.ordinal()) = newInput _input(side.ordinal()) = newInput
if (oldInput >= 0 && newInput != oldInput) { if (oldInput >= 0 && newInput != oldInput) {
@ -60,14 +83,37 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
} }
} }
def maxInput = EnumFacing.values.map(input).max def setInput(values: Array[Int]): Unit = {
for (side <- EnumFacing.values) {
val value = if (side.ordinal <= values.length) values(side.ordinal) else 0
setInput(side, value)
}
}
def output(side: EnumFacing) = _output(toLocal(side).ordinal()) def maxInput: Int = _input.map(math.max(_, 0)).max
def output(side: EnumFacing, value: Int): Unit = if (value != output(side)) { def getOutput: Array[Int] = EnumFacing.values.map{ side: EnumFacing => _output(toLocal(side).ordinal) }
def getOutput(side: EnumFacing) = _output(toLocal(side).ordinal())
def setOutput(side: EnumFacing, value: Int): Boolean = {
if (value == getOutput(side)) return false
_output(toLocal(side).ordinal()) = value _output(toLocal(side).ordinal()) = value
onRedstoneOutputChanged(side) onRedstoneOutputChanged(side)
true
}
def setOutput(values: util.Map[_, _]): Boolean = {
var changed: Boolean = false
EnumFacing.values.foreach(side => {
val sideIndex = toLocal(side).ordinal
// due to a bug in our jnlua layer, I cannot loop the map
valueToInt(getObjectFuzzy(values, sideIndex)) match {
case Some(num: Int) if setOutput(side, num) => changed = true
case _ =>
}
})
changed
} }
def checkRedstoneInputChanged() { def checkRedstoneInputChanged() {
@ -97,9 +143,7 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
} }
} }
def updateRedstoneInput(side: EnumFacing) { def updateRedstoneInput(side: EnumFacing): Unit = setInput(side, BundledRedstone.computeInput(position, side))
input(side, BundledRedstone.computeInput(position, side))
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -122,13 +166,13 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
override def readFromNBTForClient(nbt: NBTTagCompound) { override def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt) super.readFromNBTForClient(nbt)
isOutputEnabled = nbt.getBoolean("isOutputEnabled") _isOutputEnabled = nbt.getBoolean("isOutputEnabled")
nbt.getIntArray("output").copyToArray(_output) nbt.getIntArray("output").copyToArray(_output)
} }
override def writeToNBTForClient(nbt: NBTTagCompound) { override def writeToNBTForClient(nbt: NBTTagCompound) {
super.writeToNBTForClient(nbt) super.writeToNBTForClient(nbt)
nbt.setBoolean("isOutputEnabled", isOutputEnabled) nbt.setBoolean("isOutputEnabled", _isOutputEnabled)
nbt.setIntArray("output", _output) nbt.setIntArray("output", _output)
} }
@ -156,7 +200,7 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
/* TODO RedLogic /* TODO RedLogic
@Optional.Method(modid = Mods.IDs.RedLogic) @Optional.Method(modid = Mods.IDs.RedLogic)
override def connects(wire: IWire, blockFace: Int, fromDirection: Int) = isOutputEnabled override def connects(wire: IWire, blockFace: Int, fromDirection: Int) = _isOutputEnabled
@Optional.Method(modid = Mods.IDs.RedLogic) @Optional.Method(modid = Mods.IDs.RedLogic)
override def connectsAroundCorner(wire: IWire, blockFace: Int, fromDirection: Int) = false override def connectsAroundCorner(wire: IWire, blockFace: Int, fromDirection: Int) = false

View File

@ -28,11 +28,11 @@ class BundledRedstoneDevice(val tileEntity: BundledRedstoneAware) extends IBundl
override def getBundledColor(side: ForgeDirection): MinecraftColor = MinecraftColor.ANY override def getBundledColor(side: ForgeDirection): MinecraftColor = MinecraftColor.ANY
override def getBundledOutput(side: ForgeDirection): Array[Byte] = tileEntity.bundledOutput(side).map(_.toByte) override def getBundledOutput(side: ForgeDirection): Array[Byte] = tileEntity.getBundledOutput(side).map(_.toByte)
override def getBundledPower(side: ForgeDirection): Array[Byte] = tileEntity.bundledInput(side).map(_.toByte) override def getBundledPower(side: ForgeDirection): Array[Byte] = tileEntity.getBundledInput(side).map(_.toByte)
override def setBundledPower(side: ForgeDirection, power: Array[Byte]): Unit = tileEntity.bundledInput(side, power.map(_ & 0xFF)) override def setBundledPower(side: ForgeDirection, power: Array[Byte]): Unit = tileEntity.setBundledInput(side, power.map(_ & 0xFF))
override def onBundledUpdate(): Unit = tileEntity.checkRedstoneInputChanged() override def onBundledUpdate(): Unit = tileEntity.checkRedstoneInputChanged()
} }

View File

@ -25,9 +25,9 @@ class RedstoneDevice(val tileEntity: RedstoneAware) extends IRedstoneDevice {
override def getRedstoneConnectionCache: IConnectionCache[_ <: IRedstoneDevice] = cache override def getRedstoneConnectionCache: IConnectionCache[_ <: IRedstoneDevice] = cache
override def getRedstonePower(side: ForgeDirection): Byte = tileEntity.output(side).toByte override def getRedstonePower(side: ForgeDirection): Byte = tileEntity.getOutput(side).toByte
override def setRedstonePower(side: ForgeDirection, power: Byte): Unit = tileEntity.input(side, power & 0xFF) override def setRedstonePower(side: ForgeDirection, power: Byte): Unit = tileEntity.setInput(side, power & 0xFF)
override def onRedstoneUpdate(): Unit = tileEntity.checkRedstoneInputChanged() override def onRedstoneUpdate(): Unit = tileEntity.checkRedstoneInputChanged()
} }

View File

@ -20,9 +20,9 @@ object BundledRedstoneProvider extends IBundledRedstoneProvider with RedstonePro
world.getTileEntity(blockPos) match { world.getTileEntity(blockPos) match {
case tile: BundledRedstoneAware => case tile: BundledRedstoneAware =>
var result = 0 var result = 0
val colours = tile.bundledOutput(enumFacing) val colors = tile.getBundledOutput(enumFacing)
for (colour <- 0 to 15) { for (color <- 0 to 15) {
if (colours(colour) > 0) result |= 1 << colour if (colors(color) > 0) result |= 1 << color
} }
result result
case _ => -1 case _ => -1

View File

@ -58,7 +58,7 @@ object ProviderEnderIO extends RedstoneProvider with ISignalProvider {
override def getNetworkInputs(world: World, pos: BlockPos, side: EnumFacing): util.Set[Signal] = { override def getNetworkInputs(world: World, pos: BlockPos, side: EnumFacing): util.Set[Signal] = {
world.getTileEntity(pos) match { world.getTileEntity(pos) match {
case tile: BundledRedstoneAware => case tile: BundledRedstoneAware =>
tile.bundledOutput(side).zipWithIndex.map { tile.getBundledOutput(side).zipWithIndex.map {
case (strength, i) => new Signal(pos, side.getOpposite, strength, DyeColor.fromIndex(15 - i)) case (strength, i) => new Signal(pos, side.getOpposite, strength, DyeColor.fromIndex(15 - i))
}.toSet[Signal] }.toSet[Signal]
case _ => null case _ => null

View File

@ -64,7 +64,7 @@ class PartPrint extends Multipart with INormallyOccludingPart with IRedstonePart
override def getStrongSignal(side: EnumFacing): Int = getWeakSignal(side) override def getStrongSignal(side: EnumFacing): Int = getWeakSignal(side)
override def getWeakSignal(side: EnumFacing): Int = wrapped.output(side) override def getWeakSignal(side: EnumFacing): Int = wrapped.getOutput(side)
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// IOccludingPart // IOccludingPart

View File

@ -479,7 +479,7 @@ object PacketSender {
pb.writeTileEntity(t) pb.writeTileEntity(t)
pb.writeBoolean(t.isOutputEnabled) pb.writeBoolean(t.isOutputEnabled)
for (d <- EnumFacing.values) { for (d <- EnumFacing.values) {
pb.writeByte(t.output(d)) pb.writeByte(t.getOutput(d))
} }
pb.sendToPlayersNearTileEntity(t) pb.sendToPlayersNearTileEntity(t)

View File

@ -11,6 +11,7 @@ import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context import li.cil.oc.api.machine.Context
import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.BundledRedstoneAware
import net.minecraft.util.EnumFacing
import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsJava._
@ -26,56 +27,103 @@ trait RedstoneBundled extends RedstoneVanilla {
override def getDeviceInfo: util.Map[String, String] = deviceInfo override def getDeviceInfo: util.Map[String, String] = deviceInfo
private val COLOR_RANGE = 0 until 16
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def redstone: EnvironmentHost with BundledRedstoneAware override def redstone: EnvironmentHost with BundledRedstoneAware
@Callback(direct = true, doc = """function(side:number[, color:number]):number or table -- Get the bundled redstone input on the specified side and with the specified color.""") private def getBundleKey(args: Arguments): (Option[EnumFacing], Option[Int]) = {
def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { args.count match {
val side = checkSide(args, 0) case 2 => (Option(checkSide(args, 0)), Option(checkColor(args, 1)))
if (args.optAny(1, null) == null) case 1 => (Option(checkSide(args, 0)), None)
result(redstone.bundledInput(side).zipWithIndex.map(_.swap).toMap) case 0 => (None, None)
else case _ => throw new Exception("too many arguments, expected 0, 1, or 2")
result(redstone.bundledInput(side, checkColor(args, 1))) }
} }
@Callback(direct = true, doc = """function(side:number[, color:number]):number or table -- Get the bundled redstone output on the specified side and with the specified color.""") private def tableToColorValues(table: util.Map[_, _]): Array[Int] = {
def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { COLOR_RANGE.collect {
val side = checkSide(args, 0) case color: Int if table.containsKey(color) => {
if (args.optAny(1, null) == null) table.get(color) match {
result(redstone.bundledOutput(side).zipWithIndex.map(_.swap).toMap) case value: Integer => value.toInt
else }
result(redstone.bundledOutput(side, checkColor(args, 1)))
}
@Callback(doc = """function(side:number, color:number, value:number):number -- Set the bundled redstone output on the specified side and with the specified color.""")
def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0)
if (args.isTable(1)) {
val table = args.checkTable(1)
(0 to 15).map(color => (color, table.get(color))).foreach {
case (color, number: Number) => redstone.bundledOutput(side, color, number.intValue())
case _ =>
} }
}.toArray
}
private def colorsToMap(ar: Array[Int]): Map[Int, Int] = {
COLOR_RANGE.map{
case color if color < ar.length => color -> ar(color)
}.toMap
}
private def sidesToMap(ar: Array[Array[Int]]): Map[Int, Map[Int, Int]] = {
SIDE_RANGE.map {
case side if side.ordinal < ar.length && ar(side.ordinal).length > 0 => side.ordinal -> colorsToMap(ar(side.ordinal))
}.toMap
}
private def getBundleAssignment(args: Arguments): (Any, Any, Any) = {
args.count match {
case 3 => (checkSide(args, 0), checkColor(args, 1), args.checkInteger(2))
case 2 => (checkSide(args, 0), args.checkTable(1), null)
case 1 => (args.checkTable(0), null, null)
case _ => throw new Exception("invalid number of arguments, expected 1, 2, or 3")
}
}
@Callback(direct = true, doc = "function([side:number[, color:number]]):number or table -- Fewer params returns set of inputs")
def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = {
val (side, color) = getBundleKey(args)
if (color.isDefined) {
result(redstone.getBundledInput(side.get, color.get))
} else if (side.isDefined) {
result(colorsToMap(redstone.getBundledInput(side.get)))
} else {
result(sidesToMap(redstone.getBundledInput))
}
}
@Callback(direct = true, doc = "function([side:number[, color:number]]):number or table -- Fewer params returns set of outputs")
def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
val (side, color) = getBundleKey(args)
if (color.isDefined) {
result(redstone.getBundledOutput(side.get, color.get))
} else if (side.isDefined) {
result(colorsToMap(redstone.getBundledOutput(side.get)))
} else {
result(sidesToMap(redstone.getBundledOutput))
}
}
@Callback(doc = "function([side:number[, color:number,]] value:number or table):number or table -- Fewer params to assign set of outputs. Returns previous values")
def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
var ret: AnyRef = null
if (getBundleAssignment(args) match {
case (side: EnumFacing, color: Int, value: Int) =>
ret = new java.lang.Integer(redstone.getBundledOutput(side, color))
redstone.setBundledOutput(side, color, value)
case (side: EnumFacing, value: util.Map[_, _], _) =>
ret = redstone.getBundledOutput(side)
redstone.setBundledOutput(side, value)
case (value: util.Map[_, _], _, _) =>
ret = redstone.getBundledOutput
redstone.setBundledOutput(value)
}) {
if (Settings.get.redstoneDelay > 0) if (Settings.get.redstoneDelay > 0)
context.pause(Settings.get.redstoneDelay) context.pause(Settings.get.redstoneDelay)
result(true)
}
else {
val color = checkColor(args, 1)
val value = args.checkInteger(2)
redstone.bundledOutput(side, color, value)
if (Settings.get.redstoneDelay > 0)
context.pause(Settings.get.redstoneDelay)
result(redstone.bundledOutput(side, color))
} }
result(ret)
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
private def checkColor(args: Arguments, index: Int): Int = { private def checkColor(args: Arguments, index: Int): Int = {
val color = args.checkInteger(index) val color = args.checkInteger(index)
if (color < 0 || color > 15) if (!COLOR_RANGE.contains(color))
throw new IllegalArgumentException("invalid color") throw new IllegalArgumentException("invalid color")
color color
} }

View File

@ -36,31 +36,43 @@ trait RedstoneVanilla extends RedstoneSignaller with DeviceInfo {
override def getDeviceInfo: util.Map[String, String] = deviceInfo override def getDeviceInfo: util.Map[String, String] = deviceInfo
protected val SIDE_RANGE: Array[EnumFacing] = EnumFacing.values
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback(direct = true, doc = "function([side:number]):number or table -- Get the redstone input (all sides, or optionally on the specified side)")
@Callback(direct = true, doc = """function(side:number):number -- Get the redstone input on the specified side.""")
def getInput(context: Context, args: Arguments): Array[AnyRef] = { def getInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) getOptionalSide(args) match {
result(redstone.input(side)) case Some(side: Int) => result(redstone.getInput(side))
case _ => result(valuesToMap(redstone.getInput))
}
} }
@Callback(direct = true, doc = """function(side:number):number -- Get the redstone output on the specified side.""") @Callback(direct = true, doc = "function([side:number]):number or table -- Get the redstone output (all sides, or optionally on the specified side)")
def getOutput(context: Context, args: Arguments): Array[AnyRef] = { def getOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) getOptionalSide(args) match {
result(redstone.output(side)) case Some(side: Int) => result(redstone.getOutput(side))
case _ => result(valuesToMap(redstone.getOutput))
}
} }
@Callback(doc = """function(side:number, value:number):number -- Set the redstone output on the specified side.""") @Callback(doc = "function([side:number, ]value:number or table):number or table -- Set the redstone output (all sides, or optionally on the specified side). Returns previous values")
def setOutput(context: Context, args: Arguments): Array[AnyRef] = { def setOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) var ret: AnyRef = null
val value = args.checkInteger(1) if (getAssignment(args) match {
redstone.output(side, value) case (side: EnumFacing, value: Int) =>
if (Settings.get.redstoneDelay > 0) ret = new java.lang.Integer(redstone.getOutput(side))
context.pause(Settings.get.redstoneDelay) redstone.setOutput(side, value)
result(redstone.output(side)) case (value: util.Map[_, _], _) =>
ret = valuesToMap(redstone.getOutput)
redstone.setOutput(value)
}) {
if (Settings.get.redstoneDelay > 0)
context.pause(Settings.get.redstoneDelay)
}
result(ret)
} }
@Callback(direct = true, doc = """function(side:number):number -- Get the comparator input on the specified side.""") @Callback(direct = true, doc = "function(side:number):number -- Get the comparator input on the specified side.")
def getComparatorInput(context: Context, args: Arguments): Array[AnyRef] = { def getComparatorInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
val blockPos = BlockPosition(redstone).offset(side) val blockPos = BlockPosition(redstone).offset(side)
@ -87,10 +99,27 @@ trait RedstoneVanilla extends RedstoneSignaller with DeviceInfo {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
protected def checkSide(args: Arguments, index: Int) = { private def getOptionalSide(args: Arguments): Option[Int] = {
if (args.count == 1)
Option(checkSide(args, 0).ordinal)
else
None
}
private def getAssignment(args: Arguments): (Any, Any) = {
args.count match {
case 2 => (checkSide(args, 0), args.checkInteger(1))
case 1 => (args.checkTable(0), null)
case _ => throw new Exception("invalid number of arguments, expected 1 or 2")
}
}
protected def checkSide(args: Arguments, index: Int): EnumFacing = {
val side = args.checkInteger(index) val side = args.checkInteger(index)
if (side < 0 || side > 5) if (side < 0 || side > 5)
throw new IllegalArgumentException("invalid side") throw new IllegalArgumentException("invalid side")
redstone.toGlobal(EnumFacing.getFront(side)) redstone.toGlobal(EnumFacing.getFront(side))
} }
private def valuesToMap(ar: Array[Int]): Map[Int, Int] = SIDE_RANGE.map(_.ordinal).map{ case side if side < ar.length => side -> ar(side) }.toMap
} }