blob: 3956c671641f4be2655c09722441e1ff4e5b2f85 [file] [log] [blame] [raw]
package li.cil.oc.server.component
import li.cil.oc.api.Network
import li.cil.oc.api.network._
import li.cil.oc.util.mods.RedstoneInMotion
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
class Carriage(controller: TileEntity) extends ManagedComponent {
val node = Network.newNode(this, Visibility.Network).
withComponent("carriage").
create()
private val names = Map(
"negy" -> 0, "posy" -> 1, "negz" -> 2, "posz" -> 3, "negx" -> 4, "posx" -> 5,
"down" -> 0, "up" -> 1, "north" -> 2, "south" -> 3, "west" -> 4, "east" -> 5)
private var anchored = false
private var direction = 0
private var simulating = false
private var shouldMove = false
private var moving = false
private var signalDelay = 10
// ----------------------------------------------------------------------- //
@Callback
def move(context: Context, args: Arguments): Array[AnyRef] = {
direction = checkDirection(args)
simulating = if (args.count > 1) args.checkBoolean(1) else false
shouldMove = true
context.pause(0.1)
result(true)
}
@Callback
def simulate(context: Context, args: Arguments): Array[AnyRef] = {
// IMPORTANT: we have to do the simulation asynchronously, too, because
// that may also try to persist the computer that called us, and it must
// not be running when we do that.
direction = checkDirection(args)
simulating = true
shouldMove = true
context.pause(0.1)
result(true)
}
@Callback
def getAnchored(context: Context, args: Arguments): Array[AnyRef] =
result(anchored)
@Callback
def setAnchored(context: Context, args: Arguments): Array[AnyRef] = {
anchored = args.checkBoolean(0)
result(anchored)
}
private def checkDirection(args: Arguments) = {
if (!RedstoneInMotion.available)
throw new Exception("Redstone in Motion not found")
if (shouldMove || moving)
throw new Exception("already moving")
if (args.isString(0)) {
val name = args.checkString(0).toLowerCase
if (!names.contains(name))
throw new IllegalArgumentException("invalid direction")
names(name)
}
else {
val index = args.checkInteger(0)
if (index < 0 || index > 5)
throw new ArrayIndexOutOfBoundsException("invalid direction")
index
}
}
// ----------------------------------------------------------------------- //
override val canUpdate = true
override def update() {
if (node != null && node.network != null && moving) {
signalDelay = signalDelay - 1
if (signalDelay <= 0) {
moving = false
node.sendToReachable("computer.signal", "carriage_moved", Boolean.box(true))
}
}
super.update()
if (shouldMove) {
shouldMove = false
moving = true
try {
val (ok, reason) = RedstoneInMotion.move(controller, direction, simulating, anchored)
if (!ok || simulating || anchored) {
// We won't get re-connected, so we won't send in onConnect. Do it here.
node.sendToReachable("computer.signal", Seq("carriage_moved", Boolean.box(ok)) ++ reason: _*)
}
}
catch {
case e: Throwable =>
node.sendToReachable("computer.signal", "carriage_moved", Boolean.box(false), Option(e.getMessage).getOrElse(e.toString))
}
finally {
moving = false
}
}
}
// ----------------------------------------------------------------------- //
override def save(nbt: NBTTagCompound) = {
super.save(nbt)
nbt.setBoolean("moving", moving)
nbt.setBoolean("anchored", anchored)
}
override def load(nbt: NBTTagCompound) {
super.load(nbt)
moving = nbt.getBoolean("moving")
anchored = nbt.getBoolean("anchored")
}
}