mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 18:55:03 -04:00
cleaned up RIM reflection into a helper singleton; cleaned up and extended RIM component a bit; extended arguments class with type testing methods; documented arguments class; linearly increasing screen buffer size per tier (copy would fail for advanced screens...)
This commit is contained in:
parent
43d9365c17
commit
2a2785e077
@ -5,6 +5,10 @@ package li.cil.oc.api.network;
|
|||||||
* <p/>
|
* <p/>
|
||||||
* It allows checking for the presence of arguments in a uniform manner, taking
|
* It allows checking for the presence of arguments in a uniform manner, taking
|
||||||
* care of proper type checking based on what can be passed along by Lua.
|
* care of proper type checking based on what can be passed along by Lua.
|
||||||
|
* <p/>
|
||||||
|
* Note that integer values fetched this way are actually double values that
|
||||||
|
* have been truncated. So if a Lua program passes <tt>1.9</tt> and you do a
|
||||||
|
* <tt>checkInteger</tt> you'll get a <tt>1</tt>.
|
||||||
*/
|
*/
|
||||||
public interface Arguments extends Iterable<Object> {
|
public interface Arguments extends Iterable<Object> {
|
||||||
/**
|
/**
|
||||||
@ -28,16 +32,125 @@ public interface Arguments extends Iterable<Object> {
|
|||||||
*
|
*
|
||||||
* @param index the index from which to get the argument.
|
* @param index the index from which to get the argument.
|
||||||
* @return the raw value at that index.
|
* @return the raw value at that index.
|
||||||
|
* @throws IllegalArgumentException if there is no argument at that index.
|
||||||
*/
|
*/
|
||||||
Object checkAny(int index);
|
Object checkAny(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to get a boolean value at the specified index.
|
||||||
|
* <p/>
|
||||||
|
* Throws an error if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index from which to get the argument.
|
||||||
|
* @return the boolean value at the specified index.
|
||||||
|
* @throws IllegalArgumentException if there is no argument at that index,
|
||||||
|
* or if the argument is not a boolean.
|
||||||
|
*/
|
||||||
boolean checkBoolean(int index);
|
boolean checkBoolean(int index);
|
||||||
|
|
||||||
double checkDouble(int index);
|
/**
|
||||||
|
* Try to get an integer value at the specified index.
|
||||||
|
* <p/>
|
||||||
|
* Throws an error if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index from which to get the argument.
|
||||||
|
* @return the integer value at the specified index.
|
||||||
|
* @throws IllegalArgumentException if there is no argument at that index,
|
||||||
|
* or if the argument is not a number.
|
||||||
|
*/
|
||||||
int checkInteger(int index);
|
int checkInteger(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to get a double value at the specified index.
|
||||||
|
* <p/>
|
||||||
|
* Throws an error if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index from which to get the argument.
|
||||||
|
* @return the double value at the specified index.
|
||||||
|
* @throws IllegalArgumentException if there is no argument at that index,
|
||||||
|
* or if the argument is not a number.
|
||||||
|
*/
|
||||||
|
double checkDouble(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to get a string value at the specified index.
|
||||||
|
* <p/>
|
||||||
|
* Throws an error if there are too few arguments.
|
||||||
|
* <p/>
|
||||||
|
* This will actually check for a byte array and convert it to a string
|
||||||
|
* using UTF-8 encoding.
|
||||||
|
*
|
||||||
|
* @param index the index from which to get the argument.
|
||||||
|
* @return the boolean value at the specified index.
|
||||||
|
* @throws IllegalArgumentException if there is no argument at that index,
|
||||||
|
* or if the argument is not a string.
|
||||||
|
*/
|
||||||
String checkString(int index);
|
String checkString(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to get a byte array at the specified index.
|
||||||
|
* <p/>
|
||||||
|
* Throws an error if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index from which to get the argument.
|
||||||
|
* @return the byte array at the specified index.
|
||||||
|
* @throws IllegalArgumentException if there is no argument at that index,
|
||||||
|
* or if the argument is not a byte array.
|
||||||
|
*/
|
||||||
byte[] checkByteArray(int index);
|
byte[] checkByteArray(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the argument at the specified index is a boolean value.
|
||||||
|
* <p/>
|
||||||
|
* This will return true if there is <em>no</em> argument at the specified
|
||||||
|
* index, i.e. if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index to check.
|
||||||
|
* @return true if the argument is a boolean; false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isBoolean(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the argument at the specified index is an integer value.
|
||||||
|
* <p/>
|
||||||
|
* This will return true if there is <em>no</em> argument at the specified
|
||||||
|
* index, i.e. if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index to check.
|
||||||
|
* @return true if the argument is an integer; false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isInteger(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the argument at the specified index is a double value.
|
||||||
|
* <p/>
|
||||||
|
* This will return true if there is <em>no</em> argument at the specified
|
||||||
|
* index, i.e. if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index to check.
|
||||||
|
* @return true if the argument is a double; false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isDouble(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the argument at the specified index is a string value.
|
||||||
|
* <p/>
|
||||||
|
* This will return true if there is <em>no</em> argument at the specified
|
||||||
|
* index, i.e. if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index to check.
|
||||||
|
* @return true if the argument is a string; false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isString(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the argument at the specified index is a byte array.
|
||||||
|
* <p/>
|
||||||
|
* This will return true if there is <em>no</em> argument at the specified
|
||||||
|
* index, i.e. if there are too few arguments.
|
||||||
|
*
|
||||||
|
* @param index the index to check.
|
||||||
|
* @return true if the argument is a byte array; false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isByteArray(int index);
|
||||||
}
|
}
|
||||||
|
@ -74,12 +74,12 @@ object Screen {
|
|||||||
trait Environment extends tileentity.Environment with util.Persistable {
|
trait Environment extends tileentity.Environment with util.Persistable {
|
||||||
val node = api.Network.newNode(this, Visibility.Network).
|
val node = api.Network.newNode(this, Visibility.Network).
|
||||||
withComponent("screen").
|
withComponent("screen").
|
||||||
withConnector(Config.bufferScreen).
|
withConnector(Config.bufferScreen * (tier + 1)).
|
||||||
create()
|
create()
|
||||||
|
|
||||||
final val instance = new component.Screen(this, maxResolution)
|
final val instance = new component.Screen(this, Config.screenResolutionsByTier(tier))
|
||||||
|
|
||||||
protected def maxResolution: (Int, Int)
|
protected def tier: Int
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
@ -14,15 +14,15 @@ import scala.collection.mutable
|
|||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
|
|
||||||
class ScreenTier1 extends Screen {
|
class ScreenTier1 extends Screen {
|
||||||
protected def maxResolution = Config.screenResolutionsByTier(0)
|
protected def tier = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScreenTier2 extends Screen {
|
class ScreenTier2 extends Screen {
|
||||||
protected def maxResolution = Config.screenResolutionsByTier(1)
|
protected def tier = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScreenTier3 extends Screen {
|
class ScreenTier3 extends Screen {
|
||||||
protected def maxResolution = Config.screenResolutionsByTier(2)
|
protected def tier = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Screen extends Rotatable with ScreenEnvironment {
|
abstract class Screen extends Rotatable with ScreenEnvironment {
|
||||||
@ -165,7 +165,7 @@ abstract class Screen extends Rotatable with ScreenEnvironment {
|
|||||||
def tryMergeTowards(dx: Int, dy: Int) = {
|
def tryMergeTowards(dx: Int, dy: Int) = {
|
||||||
val (nx, ny, nz) = unproject(x + dx, y + dy, z)
|
val (nx, ny, nz) = unproject(x + dx, y + dy, z)
|
||||||
worldObj.getBlockTileEntity(nx, ny, nz) match {
|
worldObj.getBlockTileEntity(nx, ny, nz) match {
|
||||||
case s: Screen if s.maxResolution == maxResolution && s.pitch == pitch && s.yaw == yaw && !screens.contains(s) =>
|
case s: Screen if s.tier == tier && s.pitch == pitch && s.yaw == yaw && !screens.contains(s) =>
|
||||||
val (sx, sy, _) = project(s.origin)
|
val (sx, sy, _) = project(s.origin)
|
||||||
val canMergeAlongX = sy == y && s.height == height && s.width + width <= Config.maxScreenWidth
|
val canMergeAlongX = sy == y && s.height == height && s.width + width <= Config.maxScreenWidth
|
||||||
val canMergeAlongY = sx == x && s.width == width && s.height + height <= Config.maxScreenHeight
|
val canMergeAlongY = sx == x && s.width == width && s.height + height <= Config.maxScreenHeight
|
||||||
|
@ -1,49 +1,71 @@
|
|||||||
package li.cil.oc.server.component
|
package li.cil.oc.server.component
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException
|
|
||||||
import li.cil.oc.api
|
import li.cil.oc.api
|
||||||
import li.cil.oc.api.network._
|
import li.cil.oc.api.network._
|
||||||
|
import li.cil.oc.util.RedstoneInMotion
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
import scala.Some
|
|
||||||
import scala.language.existentials
|
|
||||||
|
|
||||||
class Carriage(controller: Object) extends ManagedComponent {
|
class Carriage(controller: AnyRef) extends ManagedComponent {
|
||||||
val node = api.Network.newNode(this, Visibility.Network).
|
val node = api.Network.newNode(this, Visibility.Network).
|
||||||
withComponent("carriage").
|
withComponent("carriage").
|
||||||
create()
|
create()
|
||||||
|
|
||||||
private val (directions, setup, move) = try {
|
private val names = Map(
|
||||||
val directions = Class.forName("JAKJ.RedstoneInMotion.Directions").getEnumConstants
|
"negy" -> 0, "posy" -> 1, "negz" -> 2, "posz" -> 3, "negx" -> 4, "posx" -> 5,
|
||||||
val clazz = Class.forName("JAKJ.RedstoneInMotion.CarriageControllerEntity")
|
"down" -> 0, "up" -> 1, "north" -> 2, "south" -> 3, "west" -> 4, "east" -> 5)
|
||||||
val methods = clazz.getDeclaredMethods
|
|
||||||
val setup = methods.find(_.getName == "SetupMotion").orNull
|
|
||||||
val move = methods.find(_.getName == "Move").orNull
|
|
||||||
(directions, setup, move)
|
|
||||||
} catch {
|
|
||||||
case _: Throwable => (null, null, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var shouldMove = false
|
private var anchored = false
|
||||||
private var direction = 0
|
private var direction = 0
|
||||||
private var simulating = false
|
private var simulating = false
|
||||||
private var anchored = false
|
|
||||||
|
private var shouldMove = false
|
||||||
private var moving = false
|
private var moving = false
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@LuaCallback("move")
|
@LuaCallback("move")
|
||||||
def move(context: Context, args: Arguments): Array[Object] = {
|
def move(context: Context, args: Arguments): Array[Object] = {
|
||||||
if (directions == null || setup == null || move == null)
|
direction = checkDirection(args)
|
||||||
|
simulating = if (args.count > 1) args.checkBoolean(1) else false
|
||||||
|
shouldMove = true
|
||||||
|
result(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("simulate")
|
||||||
|
def simulate(context: Context, args: Arguments): Array[Object] = {
|
||||||
|
direction = checkDirection(args)
|
||||||
|
simulating = true
|
||||||
|
shouldMove = true
|
||||||
|
result(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback(value = "getAnchored", direct = true)
|
||||||
|
def getAnchored(context: Context, args: Arguments): Array[Object] =
|
||||||
|
result(anchored)
|
||||||
|
|
||||||
|
@LuaCallback("setAnchored")
|
||||||
|
def setAnchored(context: Context, args: Arguments): Array[Object] = {
|
||||||
|
anchored = args.checkBoolean(0)
|
||||||
|
result(anchored)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def checkDirection(args: Arguments) = {
|
||||||
|
if (!RedstoneInMotion.available)
|
||||||
throw new Exception("Redstone in Motion not found")
|
throw new Exception("Redstone in Motion not found")
|
||||||
if (shouldMove || moving)
|
if (shouldMove || moving)
|
||||||
throw new Exception("already moving")
|
throw new Exception("already moving")
|
||||||
direction = args.checkInteger(0)
|
if (args.isString(0)) {
|
||||||
if (direction < 0 || direction > directions.length)
|
val name = args.checkString(0).toLowerCase
|
||||||
throw new ArrayIndexOutOfBoundsException("invalid direction")
|
if (!names.contains(name))
|
||||||
simulating = args.checkBoolean(1)
|
throw new IllegalArgumentException("invalid direction")
|
||||||
anchored = args.checkBoolean(2)
|
names(name)
|
||||||
shouldMove = true
|
}
|
||||||
result(true)
|
else {
|
||||||
|
val index = args.checkInteger(0)
|
||||||
|
if (index < 0 || index > 5)
|
||||||
|
throw new ArrayIndexOutOfBoundsException("invalid direction")
|
||||||
|
index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
@ -53,18 +75,19 @@ class Carriage(controller: Object) extends ManagedComponent {
|
|||||||
if (shouldMove) {
|
if (shouldMove) {
|
||||||
shouldMove = false
|
shouldMove = false
|
||||||
moving = true
|
moving = true
|
||||||
var error: Option[Throwable] = None
|
|
||||||
try {
|
try {
|
||||||
setup.invoke(controller, directions(direction), Boolean.box(simulating), Boolean.box(anchored))
|
RedstoneInMotion.move(controller, direction, simulating, anchored)
|
||||||
move.invoke(controller)
|
if (simulating || anchored) {
|
||||||
} catch {
|
// We won't get re-connected, so we won't send in onConnect. Do it here.
|
||||||
case e: InvocationTargetException => error = Some(e.getCause)
|
node.sendToReachable("computer.signal", "carriage_moved", Boolean.box(true))
|
||||||
case e: Throwable => error = Some(e)
|
}
|
||||||
}
|
}
|
||||||
moving = false
|
catch {
|
||||||
error match {
|
case e: Throwable =>
|
||||||
case Some(e) => node.sendToReachable("computer.signal", "carriage_moved", Unit, Option(e.getMessage).getOrElse(e.toString))
|
node.sendToReachable("computer.signal", "carriage_moved", Unit, Option(e.getMessage).getOrElse(e.toString))
|
||||||
case _ => if (simulating || anchored) node.sendToReachable("computer.signal", "carriage_moved", Boolean.box(true))
|
}
|
||||||
|
finally {
|
||||||
|
moving = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,10 +107,12 @@ class Carriage(controller: Object) extends ManagedComponent {
|
|||||||
override def save(nbt: NBTTagCompound) {
|
override def save(nbt: NBTTagCompound) {
|
||||||
super.save(nbt)
|
super.save(nbt)
|
||||||
nbt.setBoolean("moving", moving)
|
nbt.setBoolean("moving", moving)
|
||||||
|
nbt.setBoolean("anchored", anchored)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def load(nbt: NBTTagCompound) {
|
override def load(nbt: NBTTagCompound) {
|
||||||
super.load(nbt)
|
super.load(nbt)
|
||||||
moving = nbt.getBoolean("moving")
|
moving = nbt.getBoolean("moving")
|
||||||
|
anchored = nbt.getBoolean("anchored")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,28 +2,19 @@ package li.cil.oc.server.driver
|
|||||||
|
|
||||||
import li.cil.oc.api.driver
|
import li.cil.oc.api.driver
|
||||||
import li.cil.oc.server.component
|
import li.cil.oc.server.component
|
||||||
|
import li.cil.oc.util.RedstoneInMotion
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
|
||||||
object Carriage extends driver.Block {
|
object Carriage extends driver.Block {
|
||||||
private val (carriageControllerClass) = try {
|
|
||||||
Class.forName("JAKJ.RedstoneInMotion.CarriageControllerEntity")
|
|
||||||
} catch {
|
|
||||||
case _: Throwable => null
|
|
||||||
}
|
|
||||||
|
|
||||||
def worksWith(world: World, x: Int, y: Int, z: Int) =
|
def worksWith(world: World, x: Int, y: Int, z: Int) =
|
||||||
Option(world.getBlockTileEntity(x, y, z)) match {
|
Option(world.getBlockTileEntity(x, y, z)) match {
|
||||||
case Some(entity) if checkClass(entity) => true
|
case Some(entity) if RedstoneInMotion.isCarriageController(entity) => true
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
def createEnvironment(world: World, x: Int, y: Int, z: Int) =
|
def createEnvironment(world: World, x: Int, y: Int, z: Int) =
|
||||||
world.getBlockTileEntity(x, y, z) match {
|
world.getBlockTileEntity(x, y, z) match {
|
||||||
case controller if checkClass(controller) =>
|
case entity if RedstoneInMotion.isCarriageController(entity) => new component.Carriage(entity)
|
||||||
new component.Carriage(controller)
|
|
||||||
case _ => null
|
case _ => null
|
||||||
}
|
}
|
||||||
|
|
||||||
private def checkClass(value: Object) =
|
|
||||||
carriageControllerClass != null && carriageControllerClass.isAssignableFrom(value.getClass)
|
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ object Component {
|
|||||||
args(index)
|
args(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkBoolean(index: Int): Boolean = {
|
def checkBoolean(index: Int) = {
|
||||||
checkIndex(index, "boolean")
|
checkIndex(index, "boolean")
|
||||||
args(index) match {
|
args(index) match {
|
||||||
case value: java.lang.Boolean => value
|
case value: java.lang.Boolean => value
|
||||||
@ -154,7 +154,7 @@ object Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkDouble(index: Int): Double = {
|
def checkDouble(index: Int) = {
|
||||||
checkIndex(index, "number")
|
checkIndex(index, "number")
|
||||||
args(index) match {
|
args(index) match {
|
||||||
case value: java.lang.Double => value
|
case value: java.lang.Double => value
|
||||||
@ -162,7 +162,7 @@ object Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkInteger(index: Int): Int = {
|
def checkInteger(index: Int) = {
|
||||||
checkIndex(index, "number")
|
checkIndex(index, "number")
|
||||||
args(index) match {
|
args(index) match {
|
||||||
case value: java.lang.Double => value.intValue
|
case value: java.lang.Double => value.intValue
|
||||||
@ -170,10 +170,16 @@ object Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkString(index: Int) =
|
def checkString(index: Int) = {
|
||||||
new String(checkByteArray(index), "UTF-8")
|
checkIndex(index, "string")
|
||||||
|
args(index) match {
|
||||||
|
case value: java.lang.String => value
|
||||||
|
case value: Array[Byte] => new String(value, "UTF-8")
|
||||||
|
case value => throw typeError(index, value, "string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def checkByteArray(index: Int): Array[Byte] = {
|
def checkByteArray(index: Int) = {
|
||||||
checkIndex(index, "string")
|
checkIndex(index, "string")
|
||||||
args(index) match {
|
args(index) match {
|
||||||
case value: Array[Byte] => value
|
case value: Array[Byte] => value
|
||||||
@ -181,6 +187,37 @@ object Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def isBoolean(index: Int) =
|
||||||
|
index >= 0 && index < count && (args(index) match {
|
||||||
|
case value: java.lang.Boolean => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
|
def isDouble(index: Int) =
|
||||||
|
index >= 0 && index < count && (args(index) match {
|
||||||
|
case value: java.lang.Double => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
|
def isInteger(index: Int) =
|
||||||
|
index >= 0 && index < count && (args(index) match {
|
||||||
|
case value: java.lang.Integer => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
|
def isString(index: Int) =
|
||||||
|
index >= 0 && index < count && (args(index) match {
|
||||||
|
case value: java.lang.String => true
|
||||||
|
case value: Array[Byte] => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
|
def isByteArray(index: Int) =
|
||||||
|
index >= 0 && index < count && (args(index) match {
|
||||||
|
case value: Array[Byte] => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
private def checkIndex(index: Int, name: String) =
|
private def checkIndex(index: Int, name: String) =
|
||||||
if (index < 0) throw new IndexOutOfBoundsException()
|
if (index < 0) throw new IndexOutOfBoundsException()
|
||||||
else if (args.length <= index) throw new IllegalArgumentException(
|
else if (args.length <= index) throw new IllegalArgumentException(
|
||||||
|
36
li/cil/oc/util/RedstoneInMotion.scala
Normal file
36
li/cil/oc/util/RedstoneInMotion.scala
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package li.cil.oc.util
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import scala.language.existentials
|
||||||
|
|
||||||
|
object RedstoneInMotion {
|
||||||
|
private val (controller, setup, move, directions) = try {
|
||||||
|
val controller = Class.forName("JAKJ.RedstoneInMotion.CarriageControllerEntity")
|
||||||
|
val methods = controller.getDeclaredMethods
|
||||||
|
val setup = methods.find(_.getName == "SetupMotion").get
|
||||||
|
val move = methods.find(_.getName == "Move").get
|
||||||
|
val directions = Class.forName("JAKJ.RedstoneInMotion.Directions").getEnumConstants
|
||||||
|
(Option(controller), setup, move, directions)
|
||||||
|
} catch {
|
||||||
|
case _: Throwable => (None, null, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
def available = controller.isDefined
|
||||||
|
|
||||||
|
def isCarriageController(value: AnyRef) = controller match {
|
||||||
|
case Some(clazz) => clazz.isAssignableFrom(value.getClass)
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
def move(controller: AnyRef, direction: Int, simulating: Boolean, anchored: Boolean) {
|
||||||
|
if (!isCarriageController(controller))
|
||||||
|
throw new IllegalArgumentException("Not a carriage controller.")
|
||||||
|
|
||||||
|
try {
|
||||||
|
setup.invoke(controller, directions(direction), Boolean.box(simulating), Boolean.box(anchored))
|
||||||
|
move.invoke(controller)
|
||||||
|
} catch {
|
||||||
|
case e: InvocationTargetException => throw e.getCause
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user