mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-25 22:14:09 -04:00
Merge branch 'master' of github.com:MightyPirates/OpenComputers into MC1.7
This commit is contained in:
commit
b184c026dc
@ -12,12 +12,11 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public interface Converter {
|
public interface Converter {
|
||||||
/**
|
/**
|
||||||
* Converts a type to a Map that only contains valid values, i.e. values
|
* Converts a type to a Map.
|
||||||
* that can be directly pushed to an architecture, without further
|
|
||||||
* conversion steps.
|
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is primarily enforced to avoid cycles in conversion steps. If the
|
* The keys and values in the resulting map will be converted in turn.
|
||||||
* returned map contains any unsupported values, they will not be retained.
|
* If after those conversions the map still contains unsupported values,
|
||||||
|
* they will not be retained.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The conversion result should be placed into the the passed map, i.e. the
|
* The conversion result should be placed into the the passed map, i.e. the
|
||||||
* map will represent the original object. For example, if the value had a
|
* map will represent the original object. For example, if the value had a
|
||||||
|
@ -83,7 +83,7 @@ class UserdataAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
|
|||||||
|
|
||||||
lua.pushScalaFunction(lua => {
|
lua.pushScalaFunction(lua => {
|
||||||
val value = lua.toJavaObjectRaw(1).asInstanceOf[Value]
|
val value = lua.toJavaObjectRaw(1).asInstanceOf[Value]
|
||||||
lua.pushTable(Callbacks(value).map(entry => entry._1 -> entry._2.direct))
|
lua.pushValue(Callbacks(value).map(entry => entry._1 -> entry._2.direct))
|
||||||
1
|
1
|
||||||
})
|
})
|
||||||
lua.setField(-2, "methods")
|
lua.setField(-2, "methods")
|
||||||
|
@ -8,7 +8,8 @@ import li.cil.oc.{OpenComputers, api}
|
|||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import scala.collection.convert.WrapAsScala._
|
import scala.collection.convert.WrapAsScala._
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable
|
||||||
|
import scala.math.ScalaNumber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class keeps track of registered drivers and provides installation logic
|
* This class keeps track of registered drivers and provides installation logic
|
||||||
@ -25,11 +26,11 @@ import scala.collection.mutable.ArrayBuffer
|
|||||||
* the computer, but may also provide context-free functions.
|
* the computer, but may also provide context-free functions.
|
||||||
*/
|
*/
|
||||||
private[oc] object Registry extends api.detail.DriverAPI {
|
private[oc] object Registry extends api.detail.DriverAPI {
|
||||||
val blocks = ArrayBuffer.empty[api.driver.Block]
|
val blocks = mutable.ArrayBuffer.empty[api.driver.Block]
|
||||||
|
|
||||||
val items = ArrayBuffer.empty[api.driver.Item]
|
val items = mutable.ArrayBuffer.empty[api.driver.Item]
|
||||||
|
|
||||||
val converters = ArrayBuffer.empty[api.driver.Converter]
|
val converters = mutable.ArrayBuffer.empty[api.driver.Converter]
|
||||||
|
|
||||||
/** Used to keep track of whether we're past the init phase. */
|
/** Used to keep track of whether we're past the init phase. */
|
||||||
var locked = false
|
var locked = false
|
||||||
@ -59,48 +60,95 @@ private[oc] object Registry extends api.detail.DriverAPI {
|
|||||||
if (stack != null) items.find(_.worksWith(stack)).orNull
|
if (stack != null) items.find(_.worksWith(stack)).orNull
|
||||||
else null
|
else null
|
||||||
|
|
||||||
def convert(value: Array[AnyRef]) = if (value != null) value.map(convertRecursively) else null
|
def convert(value: Array[AnyRef]) = if (value != null) value.map(arg => convertRecursively(arg, new util.IdentityHashMap())) else null
|
||||||
|
|
||||||
def convertRecursively(value: AnyRef): AnyRef = value match {
|
def convertRecursively(value: Any, memo: util.IdentityHashMap[AnyRef, AnyRef], force: Boolean = false): AnyRef = {
|
||||||
case null | Unit | None => null
|
val valueRef = value match {
|
||||||
case arg: java.lang.Boolean => arg
|
case number: ScalaNumber => number.underlying
|
||||||
case arg: java.lang.Byte => arg
|
case reference: AnyRef => reference
|
||||||
case arg: java.lang.Character => arg
|
case null => null
|
||||||
case arg: java.lang.Short => arg
|
case primitive => primitive.asInstanceOf[AnyRef]
|
||||||
case arg: java.lang.Integer => arg
|
|
||||||
case arg: java.lang.Long => arg
|
|
||||||
case arg: java.lang.Float => arg
|
|
||||||
case arg: java.lang.Double => arg
|
|
||||||
case arg: java.lang.String => arg
|
|
||||||
|
|
||||||
case arg: Array[Boolean] => arg
|
|
||||||
case arg: Array[Byte] => arg
|
|
||||||
case arg: Array[Character] => arg
|
|
||||||
case arg: Array[Short] => arg
|
|
||||||
case arg: Array[Integer] => arg
|
|
||||||
case arg: Array[Long] => arg
|
|
||||||
case arg: Array[Float] => arg
|
|
||||||
case arg: Array[Double] => arg
|
|
||||||
case arg: Array[String] => arg
|
|
||||||
|
|
||||||
case arg: Value => arg
|
|
||||||
|
|
||||||
case arg: Array[_] => arg.map {
|
|
||||||
case (value: AnyRef) => convertRecursively(value)
|
|
||||||
}
|
}
|
||||||
case arg: Map[_, _] => arg.collect {
|
if (!force && memo.containsKey(valueRef)) {
|
||||||
case (key: AnyRef, value: AnyRef) => convertRecursively(key) -> convertRecursively(value)
|
memo.get(valueRef)
|
||||||
}
|
|
||||||
case arg: java.util.Map[_, _] => arg.collect {
|
|
||||||
case (key: AnyRef, value: AnyRef) => convertRecursively(key) -> convertRecursively(value)
|
|
||||||
}
|
}
|
||||||
|
else valueRef match {
|
||||||
|
case null | Unit | None => null
|
||||||
|
|
||||||
case arg =>
|
case arg: java.lang.Boolean => arg
|
||||||
val result = new util.HashMap[AnyRef, AnyRef]()
|
case arg: java.lang.Byte => arg
|
||||||
converters.foreach(converter => try converter.convert(arg, result) catch {
|
case arg: java.lang.Character => arg
|
||||||
case t: Throwable => OpenComputers.log.log(Level.WARNING, "Type converter threw an exception.", t)
|
case arg: java.lang.Short => arg
|
||||||
})
|
case arg: java.lang.Integer => arg
|
||||||
if (result.isEmpty) null
|
case arg: java.lang.Long => arg
|
||||||
else result
|
case arg: java.lang.Float => arg
|
||||||
|
case arg: java.lang.Double => arg
|
||||||
|
case arg: java.lang.String => arg
|
||||||
|
|
||||||
|
case arg: Array[Boolean] => arg
|
||||||
|
case arg: Array[Byte] => arg
|
||||||
|
case arg: Array[Character] => arg
|
||||||
|
case arg: Array[Short] => arg
|
||||||
|
case arg: Array[Integer] => arg
|
||||||
|
case arg: Array[Long] => arg
|
||||||
|
case arg: Array[Float] => arg
|
||||||
|
case arg: Array[Double] => arg
|
||||||
|
case arg: Array[String] => arg
|
||||||
|
|
||||||
|
case arg: Value => arg
|
||||||
|
|
||||||
|
case arg: Array[_] => convertList(arg, arg.zipWithIndex.iterator, memo)
|
||||||
|
case arg: Product => convertList(arg, arg.productIterator.zipWithIndex, memo)
|
||||||
|
case arg: Seq[_] => convertList(arg, arg.zipWithIndex.iterator, memo)
|
||||||
|
|
||||||
|
case arg: Map[_, _] => convertMap(arg, arg, memo)
|
||||||
|
case arg: mutable.Map[_, _] => convertMap(arg, arg.toMap, memo)
|
||||||
|
case arg: java.util.Map[_, _] => convertMap(arg, arg.toMap, memo)
|
||||||
|
|
||||||
|
case arg =>
|
||||||
|
val converted = new util.HashMap[AnyRef, AnyRef]()
|
||||||
|
memo += arg -> converted
|
||||||
|
converters.foreach(converter => try converter.convert(arg, converted) catch {
|
||||||
|
case t: Throwable => OpenComputers.log.log(Level.WARNING, "Type converter threw an exception.", t)
|
||||||
|
})
|
||||||
|
if (converted.isEmpty) {
|
||||||
|
memo += arg -> null
|
||||||
|
null
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// This is a little nasty but necessary because we need to keep the
|
||||||
|
// 'converted' value up-to-date for any reference created to it in
|
||||||
|
// the following convertRecursively call. For example:
|
||||||
|
// - Converter C is called for A with map M.
|
||||||
|
// - C puts A into M again.
|
||||||
|
// - convertRecursively(M) encounters A in the memoization map, uses M.
|
||||||
|
// That M is then 'wrong', as in not fully converted. Hence the clear
|
||||||
|
// plus copy action afterwards.
|
||||||
|
memo += converted -> converted // Makes convertMap re-use the map.
|
||||||
|
convertRecursively(converted, memo, force = true)
|
||||||
|
memo -= converted
|
||||||
|
converted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def convertList(obj: AnyRef, list: Iterator[(Any, Int)], memo: util.IdentityHashMap[AnyRef, AnyRef]) = {
|
||||||
|
val converted = new Array[AnyRef](list.size)
|
||||||
|
memo += obj -> converted
|
||||||
|
for ((value, index) <- list) {
|
||||||
|
converted(index) = convertRecursively(value, memo)
|
||||||
|
}
|
||||||
|
converted
|
||||||
|
}
|
||||||
|
|
||||||
|
def convertMap(obj: AnyRef, map: Map[_, _], memo: util.IdentityHashMap[AnyRef, AnyRef]) = {
|
||||||
|
val converted = memo.getOrElseUpdate(obj, mutable.Map.empty[AnyRef, AnyRef]) match {
|
||||||
|
case map: mutable.Map[AnyRef, AnyRef]@unchecked => map
|
||||||
|
case map: java.util.Map[AnyRef, AnyRef]@unchecked => mapAsScalaMap(map)
|
||||||
|
}
|
||||||
|
map.collect {
|
||||||
|
case (key: AnyRef, value: AnyRef) => converted += convertRecursively(key, memo) -> convertRecursively(value, memo)
|
||||||
|
}
|
||||||
|
memo.get(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package li.cil.oc.util
|
package li.cil.oc.util
|
||||||
|
|
||||||
import com.naef.jnlua.{LuaType, JavaFunction, LuaState}
|
import com.naef.jnlua.{LuaType, JavaFunction, LuaState}
|
||||||
|
import java.util
|
||||||
import li.cil.oc.api.machine.Value
|
import li.cil.oc.api.machine.Value
|
||||||
import li.cil.oc.OpenComputers
|
import li.cil.oc.OpenComputers
|
||||||
import scala.collection.convert.WrapAsScala._
|
import scala.collection.convert.WrapAsScala._
|
||||||
@ -18,43 +19,49 @@ object ExtendedLuaState {
|
|||||||
override def invoke(state: LuaState) = f(state)
|
override def invoke(state: LuaState) = f(state)
|
||||||
})
|
})
|
||||||
|
|
||||||
def pushValue(value: Any) {
|
def pushValue(value: Any, memo: util.IdentityHashMap[Any, Int] = new util.IdentityHashMap()) {
|
||||||
(value match {
|
if (memo.containsKey(value)) {
|
||||||
case number: ScalaNumber => number.underlying
|
lua.pushValue(memo.get(value))
|
||||||
case reference: AnyRef => reference
|
}
|
||||||
case null => null
|
else {
|
||||||
case primitive => primitive.asInstanceOf[AnyRef]
|
(value match {
|
||||||
}) match {
|
case number: ScalaNumber => number.underlying
|
||||||
case null | Unit | _: BoxedUnit => lua.pushNil()
|
case reference: AnyRef => reference
|
||||||
case value: java.lang.Boolean => lua.pushBoolean(value.booleanValue)
|
case null => null
|
||||||
case value: java.lang.Byte => lua.pushNumber(value.byteValue)
|
case primitive => primitive.asInstanceOf[AnyRef]
|
||||||
case value: java.lang.Character => lua.pushString(String.valueOf(value))
|
}) match {
|
||||||
case value: java.lang.Short => lua.pushNumber(value.shortValue)
|
case null | Unit | _: BoxedUnit => lua.pushNil()
|
||||||
case value: java.lang.Integer => lua.pushNumber(value.intValue)
|
case value: java.lang.Boolean => lua.pushBoolean(value.booleanValue)
|
||||||
case value: java.lang.Long => lua.pushNumber(value.longValue)
|
case value: java.lang.Byte => lua.pushNumber(value.byteValue)
|
||||||
case value: java.lang.Float => lua.pushNumber(value.floatValue)
|
case value: java.lang.Character => lua.pushString(String.valueOf(value))
|
||||||
case value: java.lang.Double => lua.pushNumber(value.doubleValue)
|
case value: java.lang.Short => lua.pushNumber(value.shortValue)
|
||||||
case value: java.lang.String => lua.pushString(value)
|
case value: java.lang.Integer => lua.pushNumber(value.intValue)
|
||||||
case value: Array[Byte] => lua.pushByteArray(value)
|
case value: java.lang.Long => lua.pushNumber(value.longValue)
|
||||||
case value: Array[_] => pushList(value.zipWithIndex.iterator)
|
case value: java.lang.Float => lua.pushNumber(value.floatValue)
|
||||||
case value: Value => lua.pushJavaObjectRaw(value)
|
case value: java.lang.Double => lua.pushNumber(value.doubleValue)
|
||||||
case value: Product => pushList(value.productIterator.zipWithIndex)
|
case value: java.lang.String => lua.pushString(value)
|
||||||
case value: Seq[_] => pushList(value.zipWithIndex.iterator)
|
case value: Array[Byte] => lua.pushByteArray(value)
|
||||||
case value: java.util.Map[_, _] => pushTable(value.toMap)
|
case value: Array[_] => pushList(value, value.zipWithIndex.iterator, memo)
|
||||||
case value: Map[_, _] => pushTable(value)
|
case value: Value => lua.pushJavaObjectRaw(value)
|
||||||
case value: mutable.Map[_, _] => pushTable(value.toMap)
|
case value: Product => pushList(value, value.productIterator.zipWithIndex, memo)
|
||||||
case _ =>
|
case value: Seq[_] => pushList(value, value.zipWithIndex.iterator, memo)
|
||||||
OpenComputers.log.warning("Tried to push an unsupported value of type to Lua: " + value.getClass.getName + ".")
|
case value: java.util.Map[_, _] => pushTable(value, value.toMap, memo)
|
||||||
lua.pushNil()
|
case value: Map[_, _] => pushTable(value, value, memo)
|
||||||
|
case value: mutable.Map[_, _] => pushTable(value, value.toMap, memo)
|
||||||
|
case _ =>
|
||||||
|
OpenComputers.log.warning("Tried to push an unsupported value of type to Lua: " + value.getClass.getName + ".")
|
||||||
|
lua.pushNil()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def pushList(list: Iterator[(Any, Int)]) {
|
def pushList(obj: AnyRef, list: Iterator[(Any, Int)], memo: util.IdentityHashMap[Any, Int]) {
|
||||||
lua.newTable()
|
lua.newTable()
|
||||||
|
memo += obj -> lua.getTop
|
||||||
var count = 0
|
var count = 0
|
||||||
list.foreach {
|
list.foreach {
|
||||||
case (value, index) =>
|
case (value, index) =>
|
||||||
pushValue(value)
|
pushValue(value, memo)
|
||||||
lua.rawSet(-2, index + 1)
|
lua.rawSet(-2, index + 1)
|
||||||
count = count + 1
|
count = count + 1
|
||||||
}
|
}
|
||||||
@ -63,12 +70,13 @@ object ExtendedLuaState {
|
|||||||
lua.rawSet(-3)
|
lua.rawSet(-3)
|
||||||
}
|
}
|
||||||
|
|
||||||
def pushTable(map: Map[_, _]) {
|
def pushTable(obj: AnyRef, map: Map[_, _], memo: util.IdentityHashMap[Any, Int]) {
|
||||||
lua.newTable(0, map.size)
|
lua.newTable(0, map.size)
|
||||||
|
memo += obj -> lua.getTop
|
||||||
for ((key: AnyRef, value: AnyRef) <- map) {
|
for ((key: AnyRef, value: AnyRef) <- map) {
|
||||||
if (key != null && key != Unit && !key.isInstanceOf[BoxedUnit]) {
|
if (key != null && key != Unit && !key.isInstanceOf[BoxedUnit]) {
|
||||||
pushValue(key)
|
pushValue(key, memo)
|
||||||
pushValue(value)
|
pushValue(value, memo)
|
||||||
lua.setTable(-3)
|
lua.setTable(-3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user