mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 11:15:12 -04:00
Merge branch 'master' of https://github.com/MightyPirates/OpenComputers into MC1.7
This commit is contained in:
commit
e39bb6ab6b
@ -81,6 +81,5 @@ public interface Component extends Node {
|
||||
* @return the list of results, or <tt>null</tt> if there is no result.
|
||||
* @throws NoSuchMethodException if there is no method with that name.
|
||||
*/
|
||||
Object[] invoke(String method, Context context, Object... arguments)
|
||||
throws NoSuchMethodException;
|
||||
Object[] invoke(String method, Context context, Object... arguments) throws Exception;
|
||||
}
|
||||
|
35
src/main/java/li/cil/oc/api/network/ManagedPeripheral.java
Normal file
35
src/main/java/li/cil/oc/api/network/ManagedPeripheral.java
Normal file
@ -0,0 +1,35 @@
|
||||
package li.cil.oc.api.network;
|
||||
|
||||
/**
|
||||
* This specialization of the managed environment is intended to be used for
|
||||
* environments wrapping a ComputerCraft peripheral, although it could be used
|
||||
* for other purposes as well. It allows providing method names in addition to
|
||||
* those defined via the {@link li.cil.oc.api.network.Callback} annotation, and
|
||||
* invoking said methods.
|
||||
*/
|
||||
public interface ManagedPeripheral extends ManagedEnvironment {
|
||||
/**
|
||||
* Get the list of methods provided by this environment, in
|
||||
* <em>addition</em> to methods marked as callbacks.
|
||||
* <p/>
|
||||
* Returning <tt>null</tt> has the same meaning as returning an empty array,
|
||||
* that being that there are no methods - in which case you don't need this
|
||||
* interface!
|
||||
*
|
||||
* @return the list of methods provided by the environment.
|
||||
*/
|
||||
String[] methods();
|
||||
|
||||
/**
|
||||
* Calls a method from the list provided by {@link #methods()}.
|
||||
* <p/>
|
||||
*
|
||||
* @param method the name of the method to call.
|
||||
* @param context the context from which the method is called.
|
||||
* @param args the arguments to pass to the method.
|
||||
* @return the result of calling the method. Same as for callbacks.
|
||||
* @throws java.lang.NoSuchMethodException if there is no method with the
|
||||
* specified name.
|
||||
*/
|
||||
Object[] invoke(String method, Context context, Arguments args) throws Exception;
|
||||
}
|
156
src/main/java/li/cil/oc/api/prefab/ManagedPeripheral.java
Normal file
156
src/main/java/li/cil/oc/api/prefab/ManagedPeripheral.java
Normal file
@ -0,0 +1,156 @@
|
||||
package li.cil.oc.api.prefab;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import dan200.computer.api.*;
|
||||
import li.cil.oc.api.network.Arguments;
|
||||
import li.cil.oc.api.network.Context;
|
||||
import li.cil.oc.api.network.Node;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of the <tt>ManagedPeripheral</tt> interface for simple
|
||||
* wrapping of ComputerCraft peripherals.
|
||||
*/
|
||||
public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.api.network.ManagedPeripheral {
|
||||
protected final IPeripheral peripheral;
|
||||
|
||||
protected final List<String> _methods;
|
||||
|
||||
protected final Map<String, FakeComputerAccess> accesses = new HashMap<String, FakeComputerAccess>();
|
||||
|
||||
public ManagedPeripheral(final IPeripheral peripheral) {
|
||||
this.peripheral = peripheral;
|
||||
_methods = Arrays.asList(peripheral.getMethodNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] methods() {
|
||||
return peripheral.getMethodNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] invoke(final String method, final Context context, final Arguments args) throws Exception {
|
||||
final int index = _methods.indexOf(method);
|
||||
if (index < 0) {
|
||||
throw new NoSuchMethodException();
|
||||
}
|
||||
final Object[] argArray = Iterables.toArray(args, Object.class);
|
||||
for (int i = 0; i < argArray.length; ++i) {
|
||||
if (argArray[i] instanceof byte[]) {
|
||||
argArray[i] = new String((byte[]) argArray[i], "UTF-8");
|
||||
}
|
||||
}
|
||||
final FakeComputerAccess access;
|
||||
if (accesses.containsKey(context.address())) {
|
||||
access = accesses.get(context.address());
|
||||
} else {
|
||||
// The calling contexts is not visible to us, meaning we never got
|
||||
// an onConnect for it. Create a temporary access.
|
||||
access = new FakeComputerAccess(this, context);
|
||||
}
|
||||
return peripheral.callMethod(access, UnsupportedLuaContext.instance(), index, argArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect(final Node node) {
|
||||
super.onConnect(node);
|
||||
if (node.host() instanceof Context) {
|
||||
final FakeComputerAccess access = new FakeComputerAccess(this, (Context) node.host());
|
||||
accesses.put(node.address(), access);
|
||||
peripheral.attach(access);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(final Node node) {
|
||||
super.onDisconnect(node);
|
||||
if (node.host() instanceof Context) {
|
||||
final FakeComputerAccess access = accesses.remove(node.address());
|
||||
if (access != null) {
|
||||
peripheral.detach(access);
|
||||
}
|
||||
} else if (node == this.node) {
|
||||
for (FakeComputerAccess access : accesses.values()) {
|
||||
peripheral.detach(access);
|
||||
}
|
||||
accesses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map interaction with the computer to our format as good as we can.
|
||||
*/
|
||||
private static class FakeComputerAccess implements IComputerAccess {
|
||||
protected final ManagedPeripheral owner;
|
||||
protected final Context context;
|
||||
|
||||
public FakeComputerAccess(final ManagedPeripheral owner, final Context context) {
|
||||
this.owner = owner;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mount(final String desiredLocation, final IMount mount) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mountWritable(final String desiredLocation, final IWritableMount mount) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmount(final String location) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getID() {
|
||||
return context.address().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent(final String event, final Object[] arguments) {
|
||||
context.signal(event, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachmentName() {
|
||||
return owner.node.address();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we abstract away anything language specific, we cannot support the
|
||||
* Lua context specific operations ComputerCraft provides.
|
||||
*/
|
||||
private final static class UnsupportedLuaContext implements ILuaContext {
|
||||
protected static final UnsupportedLuaContext Instance = new UnsupportedLuaContext();
|
||||
|
||||
private UnsupportedLuaContext() {
|
||||
}
|
||||
|
||||
public static UnsupportedLuaContext instance() {
|
||||
return Instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] pullEvent(final String filter) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] pullEventRaw(final String filter) throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] yield(final Object[] arguments) throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import li.cil.oc.api.network
|
||||
import li.cil.oc.api.network.{Node => ImmutableNode, _}
|
||||
import li.cil.oc.server.component.machine.Machine
|
||||
import li.cil.oc.server.driver.CompoundBlockEnvironment
|
||||
import li.cil.oc.server.network.Component.{PeripheralCallback, ComponentCallback}
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import scala.Some
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
@ -24,18 +25,26 @@ trait Component extends network.Component with Node {
|
||||
private lazy val hosts = host match {
|
||||
case multi: CompoundBlockEnvironment =>
|
||||
callbacks.map {
|
||||
case (method, callback) =>
|
||||
multi.environments.find {
|
||||
case (_, environment) => environment.getClass == callback.method.getDeclaringClass
|
||||
} match {
|
||||
case Some((_, environment)) => method -> Some(environment)
|
||||
case _ => method -> None
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
callbacks.map {
|
||||
case (method, callback) => method -> Some(host)
|
||||
case (method, callback) => callback match {
|
||||
case component: ComponentCallback =>
|
||||
multi.environments.find {
|
||||
case (_, environment) => environment.getClass == component.method.getDeclaringClass
|
||||
} match {
|
||||
case Some((_, environment)) => method -> Some(environment)
|
||||
case _ => method -> None
|
||||
}
|
||||
case peripheral: PeripheralCallback =>
|
||||
multi.environments.find {
|
||||
case (_, environment: ManagedPeripheral) => environment.methods.contains(peripheral.name)
|
||||
} match {
|
||||
case Some((_, environment)) => method -> Some(environment)
|
||||
case _ => method -> None
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ => callbacks.map {
|
||||
case (method, callback) => method -> Some(host)
|
||||
}
|
||||
}
|
||||
|
||||
private var _visibility = Visibility.None
|
||||
@ -130,6 +139,7 @@ object Component {
|
||||
|
||||
def callbacks(host: Environment) = host match {
|
||||
case multi: CompoundBlockEnvironment => analyze(host)
|
||||
case peripheral: ManagedPeripheral => analyze(host)
|
||||
case _ => cache.getOrElseUpdate(host.getClass, analyze(host))
|
||||
}
|
||||
|
||||
@ -137,8 +147,20 @@ object Component {
|
||||
val callbacks = mutable.Map.empty[String, Callback]
|
||||
val seeds = host match {
|
||||
case multi: CompoundBlockEnvironment => multi.environments.map {
|
||||
case (_, environment) => environment.getClass: Class[_]
|
||||
case (_, environment) =>
|
||||
environment match {
|
||||
case peripheral: ManagedPeripheral => for (name <- peripheral.methods() if !callbacks.contains(name)) {
|
||||
callbacks += name -> new PeripheralCallback(name)
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
environment.getClass: Class[_]
|
||||
}
|
||||
case peripheral: ManagedPeripheral =>
|
||||
for (name <- peripheral.methods() if !callbacks.contains(name)) {
|
||||
callbacks += name -> new PeripheralCallback(name)
|
||||
}
|
||||
Seq(host.getClass: Class[_])
|
||||
case _ => Seq(host.getClass: Class[_])
|
||||
}
|
||||
for (seed <- seeds) {
|
||||
@ -162,7 +184,7 @@ object Component {
|
||||
val a = m.getAnnotation[network.Callback](classOf[network.Callback])
|
||||
val name = if (a.value != null && a.value.trim != "") a.value else m.getName
|
||||
if (!callbacks.contains(name)) {
|
||||
callbacks += name -> new Callback(m, a.direct, a.limit)
|
||||
callbacks += name -> new ComponentCallback(m, a.direct, a.limit)
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -175,14 +197,26 @@ object Component {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
class Callback(val method: Method, val direct: Boolean, val limit: Int) {
|
||||
def apply(instance: AnyRef, context: Context, args: Arguments): Array[AnyRef] = try {
|
||||
abstract class Callback(val direct: Boolean, val limit: Int) {
|
||||
def apply(instance: Environment, context: Context, args: Arguments): Array[AnyRef]
|
||||
}
|
||||
|
||||
class ComponentCallback(val method: Method, direct: Boolean, limit: Int) extends Callback(direct, limit) {
|
||||
override def apply(instance: Environment, context: Context, args: Arguments) = try {
|
||||
method.invoke(instance, context, args).asInstanceOf[Array[AnyRef]]
|
||||
} catch {
|
||||
case e: InvocationTargetException => throw e.getCause
|
||||
}
|
||||
}
|
||||
|
||||
class PeripheralCallback(val name: String) extends Callback(true, 100) {
|
||||
override def apply(instance: Environment, context: Context, args: Arguments) =
|
||||
instance match {
|
||||
case peripheral: ManagedPeripheral => peripheral.invoke(name, context, args)
|
||||
case _ => throw new NoSuchMethodException()
|
||||
}
|
||||
}
|
||||
|
||||
class VarArgs(val args: Seq[AnyRef]) extends Arguments {
|
||||
def iterator() = args.iterator
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user