mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 18:55:03 -04:00
Added ComputerCraft support back to 1.12.
This commit is contained in:
parent
c6cdd99d0e
commit
4c8799f38a
@ -67,6 +67,7 @@ repositories {
|
||||
maven { url "http://maven.ic2.player.to/" }
|
||||
maven { url "http://tehnut.info/maven" }
|
||||
maven { url "http://maven.thiakil.com" }
|
||||
maven { url "http://cc.crzd.me/maven/" }
|
||||
ivy {
|
||||
name 'ExtraCells'
|
||||
artifactPattern "http://addons-origin.cursecdn.com/files/${config.extracells.cf}/[module]-[revision].[ext]"
|
||||
@ -89,6 +90,7 @@ dependencies {
|
||||
}
|
||||
deobfCompile "net.industrial-craft:industrialcraft-2:${config.ic2.version}"
|
||||
deobfCompile "mcp.mobius.waila:Hwyla:${config.hwyla.version}:api"
|
||||
deobfCompile "dan200.computercraft:ComputerCraft:${config.cc.version}"
|
||||
|
||||
provided ("appeng:appliedenergistics2:${config.ae2.version}:api") {
|
||||
transitive = false
|
||||
|
@ -7,6 +7,7 @@ mod.group=li.cil.oc
|
||||
mod.version=1.7.1
|
||||
|
||||
ae2.version=rv5-stable-2
|
||||
cc.version=1.80pr1-build0
|
||||
extracells.cf=2500/596
|
||||
extracells.version=api-1.12.2-2.5.3a25
|
||||
forestry.version=5.5.0.157
|
||||
|
@ -1,5 +1,7 @@
|
||||
package li.cil.oc.common.block
|
||||
|
||||
import java.util
|
||||
|
||||
import li.cil.oc.common.GuiType
|
||||
import li.cil.oc.common.block.property.PropertyRotatable
|
||||
import li.cil.oc.common.tileentity
|
||||
@ -7,6 +9,7 @@ import li.cil.oc.integration.Mods
|
||||
import li.cil.oc.util.Tooltip
|
||||
import net.minecraft.block.state.BlockStateContainer
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.client.util.ITooltipFlag
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.util.EnumFacing
|
||||
@ -23,6 +26,15 @@ class DiskDrive extends SimpleBlock with traits.GUI {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def tooltipTail(metadata: Int, stack: ItemStack, world: World, tooltip: util.List[String], flag: ITooltipFlag) {
|
||||
super.tooltipTail(metadata, stack, world, tooltip, flag)
|
||||
if (Mods.ComputerCraft.isModAvailable) {
|
||||
tooltip.addAll(Tooltip.get(getClass.getSimpleName + ".CC"))
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def guiType = GuiType.DiskDrive
|
||||
|
||||
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.DiskDrive()
|
||||
|
@ -1,5 +1,7 @@
|
||||
package li.cil.oc.common.tileentity
|
||||
|
||||
import com.google.common.base.Charsets
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess
|
||||
import li.cil.oc.api.detail.ItemInfo
|
||||
import li.cil.oc.api.network.Component
|
||||
import li.cil.oc.server.PacketSender
|
||||
@ -23,6 +25,7 @@ import li.cil.oc.common.InventorySlots
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.common.item
|
||||
import li.cil.oc.common.item.Delegator
|
||||
import li.cil.oc.integration.Mods
|
||||
import li.cil.oc.integration.opencomputers.DriverLinkedCard
|
||||
import li.cil.oc.server.network.QuantumNetwork
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
@ -108,6 +111,19 @@ class Relay extends traits.Hub with traits.ComponentInventory with traits.PowerA
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def queueMessage(source: String, destination: String, port: Int, answerPort: Int, args: Array[AnyRef]) {
|
||||
for (computer <- computers.map(_.asInstanceOf[IComputerAccess])) {
|
||||
val address = s"cc${computer.getID}_${computer.getAttachmentName}"
|
||||
if (source != address && Option(destination).forall(_ == address) && openPorts(computer).contains(port))
|
||||
computer.queueEvent("modem_message", Array(Seq(computer.getAttachmentName, Int.box(port), Int.box(answerPort)) ++ args.map {
|
||||
case x: Array[Byte] => new String(x, Charsets.UTF_8)
|
||||
case x => x
|
||||
}: _*))
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def receivePacket(packet: Packet, source: WirelessEndpoint): Unit = {
|
||||
if (isWirelessEnabled) {
|
||||
tryEnqueuePacket(None, packet)
|
||||
@ -120,6 +136,18 @@ class Relay extends traits.Hub with traits.ComponentInventory with traits.PowerA
|
||||
}
|
||||
}
|
||||
|
||||
val computers = mutable.Buffer.empty[AnyRef]
|
||||
|
||||
override def tryEnqueuePacket(sourceSide: Option[EnumFacing], packet: Packet): Boolean = {
|
||||
if (Mods.ComputerCraft.isModAvailable) {
|
||||
packet.data.headOption match {
|
||||
case Some(answerPort: java.lang.Double) => queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1))
|
||||
case _ => queueMessage(packet.source, packet.destination, packet.port, -1, packet.data)
|
||||
}
|
||||
}
|
||||
super.tryEnqueuePacket(sourceSide, packet)
|
||||
}
|
||||
|
||||
override protected def relayPacket(sourceSide: Option[EnumFacing], packet: Packet): Unit = {
|
||||
super.relayPacket(sourceSide, packet)
|
||||
|
||||
|
@ -19,6 +19,7 @@ object Mods {
|
||||
|
||||
def All: ArrayBuffer[ModBase] = knownMods.clone()
|
||||
val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2)
|
||||
val ComputerCraft = new SimpleMod(IDs.ComputerCraft)
|
||||
val ExtraCells = new SimpleMod(IDs.ExtraCells, version = "@[2.5.2,)")
|
||||
val Forestry = new SimpleMod(IDs.Forestry, version = "@[5.2,)")
|
||||
val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2)
|
||||
@ -45,6 +46,8 @@ object Mods {
|
||||
integration.minecraft.ModMinecraft,
|
||||
integration.waila.ModWaila,
|
||||
|
||||
integration.computercraft.ModComputerCraft,
|
||||
|
||||
// We go late to ensure all other mod integration is done, e.g. to
|
||||
// allow properly checking if wireless redstone is present.
|
||||
integration.opencomputers.ModOpenComputers
|
||||
@ -72,6 +75,7 @@ object Mods {
|
||||
|
||||
object IDs {
|
||||
final val AppliedEnergistics2 = "appliedenergistics2"
|
||||
final val ComputerCraft = "computercraft"
|
||||
final val ExtraCells = "extracells"
|
||||
final val Forestry = "forestry"
|
||||
final val Forge = "forge"
|
||||
|
@ -0,0 +1,34 @@
|
||||
package li.cil.oc.integration.computercraft;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import li.cil.oc.api.machine.Arguments;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class CallableHelper {
|
||||
private final List<String> _methods;
|
||||
|
||||
public CallableHelper(final String[] methods) {
|
||||
_methods = Arrays.asList(methods);
|
||||
}
|
||||
|
||||
public int methodIndex(final String method) throws NoSuchMethodException {
|
||||
final int index = _methods.indexOf(method);
|
||||
if (index < 0) {
|
||||
throw new NoSuchMethodException();
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public Object[] convertArguments(final Arguments args) throws UnsupportedEncodingException {
|
||||
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");
|
||||
}
|
||||
}
|
||||
return argArray;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package li.cil.oc.integration.computercraft
|
||||
|
||||
import dan200.computercraft.api.filesystem.IMount
|
||||
import li.cil.oc.server.fs.InputStreamFileSystem
|
||||
|
||||
class ComputerCraftFileSystem(val mount: IMount) extends InputStreamFileSystem {
|
||||
override def spaceTotal = 0
|
||||
|
||||
override def spaceUsed = 0
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def exists(path: String) = mount.exists(path)
|
||||
|
||||
override def isDirectory(path: String) = mount.isDirectory(path)
|
||||
|
||||
override def lastModified(path: String) = 0L
|
||||
|
||||
override def list(path: String) = {
|
||||
val result = new java.util.ArrayList[String]
|
||||
mount.list(path, result)
|
||||
result.toArray.map(_.asInstanceOf[String])
|
||||
}
|
||||
|
||||
override def size(path: String) = mount.getSize(path)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def openInputChannel(path: String) = try {
|
||||
Some(new InputStreamChannel(mount.openForRead(path)))
|
||||
} catch {
|
||||
case _: Throwable => None
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package li.cil.oc.integration.computercraft
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
import dan200.computercraft.api.filesystem.IWritableMount
|
||||
import li.cil.oc.api.fs.Mode
|
||||
import li.cil.oc.server.fs.OutputStreamFileSystem
|
||||
|
||||
class ComputerCraftWritableFileSystem(override val mount: IWritableMount)
|
||||
extends ComputerCraftFileSystem(mount)
|
||||
with OutputStreamFileSystem {
|
||||
|
||||
override def delete(path: String) = try {
|
||||
mount.delete(path)
|
||||
true
|
||||
} catch {
|
||||
case _: Throwable => false
|
||||
}
|
||||
|
||||
override def makeDirectory(path: String) = try {
|
||||
mount.makeDirectory(path)
|
||||
true
|
||||
} catch {
|
||||
case _: Throwable => false
|
||||
}
|
||||
|
||||
override protected def openOutputHandle(id: Int, path: String, mode: Mode): Option[OutputHandle] = try {
|
||||
Some(new ComputerCraftOutputHandle(mount, mode match {
|
||||
case Mode.Append => mount.openForAppend(path)
|
||||
case Mode.Write => mount.openForWrite(path)
|
||||
case _ => throw new IllegalArgumentException()
|
||||
}, this, id, path))
|
||||
} catch {
|
||||
case _: Throwable => None
|
||||
}
|
||||
|
||||
protected class ComputerCraftOutputHandle(val mount: IWritableMount, val stream: OutputStream, owner: OutputStreamFileSystem, handle: Int, path: String) extends OutputHandle(owner, handle, path) {
|
||||
override def length() = mount.getSize(path)
|
||||
|
||||
override def position() = throw new IOException("bad file descriptor")
|
||||
|
||||
override def write(value: Array[Byte]) = stream.write(value)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package li.cil.oc.integration.computercraft;
|
||||
|
||||
import dan200.computercraft.api.lua.ILuaObject;
|
||||
import li.cil.oc.api.driver.Converter;
|
||||
import li.cil.oc.api.machine.Arguments;
|
||||
import li.cil.oc.api.machine.Context;
|
||||
import li.cil.oc.api.network.ManagedPeripheral;
|
||||
import li.cil.oc.api.prefab.AbstractValue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class ConverterLuaObject implements Converter {
|
||||
@Override
|
||||
public void convert(final Object value, final Map<Object, Object> output) {
|
||||
if (value instanceof ILuaObject) {
|
||||
output.put("value", new LuaObjectValue((ILuaObject) value));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class LuaObjectValue extends AbstractValue implements ManagedPeripheral {
|
||||
private final ILuaObject value;
|
||||
|
||||
protected final CallableHelper helper;
|
||||
|
||||
// For loading when values were saved in a computer state.
|
||||
public LuaObjectValue() {
|
||||
value = null;
|
||||
helper = null;
|
||||
}
|
||||
|
||||
public LuaObjectValue(final ILuaObject value) {
|
||||
this.value = value;
|
||||
helper = new CallableHelper(value.getMethodNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] methods() {
|
||||
if (value != null)
|
||||
return value.getMethodNames();
|
||||
return new String[0]; // Loaded userdata, missing context.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] invoke(final String method, final Context context, final Arguments args) throws Exception {
|
||||
if (value != null) {
|
||||
final int index = helper.methodIndex(method);
|
||||
final Object[] argArray = helper.convertArguments(args);
|
||||
return value.callMethod(DriverPeripheral.Environment.UnsupportedLuaContext.instance(), index, argArray);
|
||||
}
|
||||
return new Object[]{null, "ComputerCraft userdata cannot be persisted"};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package li.cil.oc.integration.computercraft
|
||||
|
||||
import dan200.computercraft.api.filesystem.IMount
|
||||
import dan200.computercraft.api.filesystem.IWritableMount
|
||||
import dan200.computercraft.api.media.IMedia
|
||||
import li.cil.oc
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.fs.FileSystem
|
||||
import li.cil.oc.api.fs.Label
|
||||
import li.cil.oc.api.network.EnvironmentHost
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.integration.opencomputers.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
|
||||
object DriverComputerCraftMedia extends Item {
|
||||
override def worksWith(stack: ItemStack) = stack.getItem.isInstanceOf[IMedia]
|
||||
|
||||
override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = if (!host.world.isRemote) {
|
||||
val address = addressFromTag(dataTag(stack))
|
||||
val mount = fromComputerCraft(stack.getItem.asInstanceOf[IMedia].createDataMount(stack, host.world))
|
||||
Option(oc.api.FileSystem.asManagedEnvironment(mount, new ComputerCraftLabel(stack), host, Settings.resourceDomain + ":floppy_access")) match {
|
||||
case Some(environment) =>
|
||||
environment.node.asInstanceOf[oc.server.network.Node].address = address
|
||||
environment
|
||||
case _ => null
|
||||
}
|
||||
} else null
|
||||
|
||||
def fromComputerCraft(mount: AnyRef): FileSystem = DriverComputerCraftMedia.createFileSystem(mount).orNull
|
||||
|
||||
override def slot(stack: ItemStack) = Slot.Floppy
|
||||
|
||||
def createFileSystem(mount: AnyRef) = Option(mount) collect {
|
||||
case rw: IWritableMount => new ComputerCraftWritableFileSystem(rw)
|
||||
case ro: IMount => new ComputerCraftFileSystem(ro)
|
||||
}
|
||||
|
||||
private def addressFromTag(tag: NBTTagCompound) =
|
||||
if (tag.hasKey("node") && tag.getCompoundTag("node").hasKey("address")) {
|
||||
tag.getCompoundTag("node").getString("address")
|
||||
}
|
||||
else java.util.UUID.randomUUID().toString
|
||||
|
||||
class ComputerCraftLabel(val stack: ItemStack) extends Label {
|
||||
val media = stack.getItem.asInstanceOf[IMedia]
|
||||
|
||||
override def getLabel = media.getLabel(stack)
|
||||
|
||||
override def setLabel(value: String) {
|
||||
media.setLabel(stack, value)
|
||||
}
|
||||
|
||||
override def load(nbt: NBTTagCompound) {}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
package li.cil.oc.integration.computercraft;
|
||||
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||
import dan200.computercraft.api.lua.ILuaContext;
|
||||
import dan200.computercraft.api.lua.ILuaTask;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import li.cil.oc.OpenComputers;
|
||||
import li.cil.oc.Settings;
|
||||
import li.cil.oc.api.FileSystem;
|
||||
import li.cil.oc.api.Network;
|
||||
import li.cil.oc.api.driver.NamedBlock;
|
||||
import li.cil.oc.api.machine.Arguments;
|
||||
import li.cil.oc.api.machine.Context;
|
||||
import li.cil.oc.api.network.BlacklistedPeripheral;
|
||||
import li.cil.oc.api.network.ManagedEnvironment;
|
||||
import li.cil.oc.api.network.Node;
|
||||
import li.cil.oc.api.network.Visibility;
|
||||
import li.cil.oc.util.Reflection;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class DriverPeripheral implements li.cil.oc.api.driver.DriverBlock {
|
||||
private static Set<Class<?>> blacklist;
|
||||
|
||||
private boolean isBlacklisted(final Object o) {
|
||||
// Check for our interface first, as that has priority.
|
||||
if (o instanceof BlacklistedPeripheral) {
|
||||
return ((BlacklistedPeripheral) o).isPeripheralBlacklisted();
|
||||
}
|
||||
|
||||
// Delayed initialization of the resolved classes to allow registering
|
||||
// additional entries via IMC.
|
||||
if (blacklist == null) {
|
||||
blacklist = new HashSet<Class<?>>();
|
||||
for (String name : Settings.get().peripheralBlacklist()) {
|
||||
final Class<?> clazz = Reflection.getClass(name);
|
||||
if (clazz != null) {
|
||||
blacklist.add(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Class<?> clazz : blacklist) {
|
||||
if (clazz.isInstance(o))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private IPeripheral findPeripheral(final World world, final BlockPos pos, final EnumFacing side) {
|
||||
try {
|
||||
final IPeripheral p = dan200.computercraft.ComputerCraft.getPeripheralAt(world, pos, side);
|
||||
if (!isBlacklisted(p)) {
|
||||
return p;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
OpenComputers.log().warn(String.format("Error accessing ComputerCraft peripheral @ (%d, %d, %d).", pos.getX(), pos.getY(), pos.getZ()), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean worksWith(final World world, final BlockPos pos, final EnumFacing side) {
|
||||
final TileEntity tileEntity = world.getTileEntity(pos);
|
||||
return tileEntity != null
|
||||
// This ensures we don't get duplicate components, in case the
|
||||
// tile entity is natively compatible with OpenComputers.
|
||||
&& !li.cil.oc.api.network.Environment.class.isAssignableFrom(tileEntity.getClass())
|
||||
// The black list is used to avoid peripherals that are known
|
||||
// to be incompatible with OpenComputers when used directly.
|
||||
&& !isBlacklisted(tileEntity)
|
||||
// Actual check if it's a peripheral.
|
||||
&& findPeripheral(world, pos, side) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedEnvironment createEnvironment(final World world, final BlockPos pos, final EnumFacing side) {
|
||||
return new Environment(findPeripheral(world, pos, side));
|
||||
}
|
||||
|
||||
public static class Environment extends li.cil.oc.api.prefab.AbstractManagedEnvironment implements li.cil.oc.api.network.ManagedPeripheral, NamedBlock {
|
||||
protected final IPeripheral peripheral;
|
||||
|
||||
protected final CallableHelper helper;
|
||||
|
||||
protected final Map<String, FakeComputerAccess> accesses = new HashMap<String, FakeComputerAccess>();
|
||||
|
||||
public Environment(final IPeripheral peripheral) {
|
||||
this.peripheral = peripheral;
|
||||
helper = new CallableHelper(peripheral.getMethodNames());
|
||||
setNode(Network.newNode(this, Visibility.Network).create());
|
||||
}
|
||||
|
||||
@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 = helper.methodIndex(method);
|
||||
final Object[] argArray = helper.convertArguments(args);
|
||||
final FakeComputerAccess access;
|
||||
if (accesses.containsKey(context.node().address())) {
|
||||
access = accesses.get(context.node().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);
|
||||
access.close();
|
||||
}
|
||||
accesses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String preferredName() {
|
||||
return peripheral.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return -1; // Lower than 'real' OC components
|
||||
}
|
||||
|
||||
/**
|
||||
* Map interaction with the computer to our format as good as we can.
|
||||
*/
|
||||
public static class FakeComputerAccess implements IComputerAccess {
|
||||
protected final Environment owner;
|
||||
protected final Context context;
|
||||
protected final Map<String, ManagedEnvironment> fileSystems = new HashMap<String, ManagedEnvironment>();
|
||||
|
||||
public FakeComputerAccess(final Environment owner, final Context context) {
|
||||
this.owner = owner;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (li.cil.oc.api.network.ManagedEnvironment fileSystem : fileSystems.values()) {
|
||||
fileSystem.node().remove();
|
||||
}
|
||||
fileSystems.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mount(final String desiredLocation, final IMount mount) {
|
||||
if (fileSystems.containsKey(desiredLocation)) {
|
||||
return null;
|
||||
}
|
||||
return mount(desiredLocation, FileSystem.asManagedEnvironment(DriverComputerCraftMedia.fromComputerCraft(mount)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mount(String desiredLocation, IMount mount, String driveName) {
|
||||
if (fileSystems.containsKey(desiredLocation)) {
|
||||
return null;
|
||||
}
|
||||
return mount(desiredLocation, FileSystem.asManagedEnvironment(DriverComputerCraftMedia.fromComputerCraft(mount), driveName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mountWritable(final String desiredLocation, final IWritableMount mount) {
|
||||
if (fileSystems.containsKey(desiredLocation)) {
|
||||
return null;
|
||||
}
|
||||
return mount(desiredLocation, FileSystem.asManagedEnvironment(DriverComputerCraftMedia.fromComputerCraft(mount)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mountWritable(String desiredLocation, IWritableMount mount, String driveName) {
|
||||
if (fileSystems.containsKey(desiredLocation)) {
|
||||
return null;
|
||||
}
|
||||
return mount(desiredLocation, FileSystem.asManagedEnvironment(DriverComputerCraftMedia.fromComputerCraft(mount), driveName));
|
||||
}
|
||||
|
||||
private String mount(final String path, final li.cil.oc.api.network.ManagedEnvironment fileSystem) {
|
||||
fileSystems.put(path, fileSystem); //TODO This is per peripheral/Environment. It would be far better with per computer
|
||||
context.node().connect(fileSystem.node());
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmount(final String location) {
|
||||
final li.cil.oc.api.network.ManagedEnvironment fileSystem = fileSystems.remove(location);
|
||||
if (fileSystem != null) {
|
||||
fileSystem.node().remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getID() {
|
||||
return context.node().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.
|
||||
*/
|
||||
public final static class UnsupportedLuaContext implements ILuaContext {
|
||||
protected static final UnsupportedLuaContext Instance = new UnsupportedLuaContext();
|
||||
|
||||
private UnsupportedLuaContext() {
|
||||
}
|
||||
|
||||
public static UnsupportedLuaContext instance() {
|
||||
return Instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long issueMainThreadTask(ILuaTask task) throws LuaException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] executeMainThreadTask(ILuaTask task) throws LuaException, InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] pullEvent(final String filter) throws LuaException, InterruptedException {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package li.cil.oc.integration.computercraft
|
||||
|
||||
import li.cil.oc.api.Driver
|
||||
import li.cil.oc.integration.ModProxy
|
||||
import li.cil.oc.integration.Mods
|
||||
|
||||
object ModComputerCraft extends ModProxy {
|
||||
override def getMod = Mods.ComputerCraft
|
||||
|
||||
override def initialize() {
|
||||
PeripheralProvider.init()
|
||||
|
||||
Driver.add(DriverComputerCraftMedia)
|
||||
Driver.add(new DriverPeripheral())
|
||||
|
||||
Driver.add(new ConverterLuaObject)
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package li.cil.oc.integration.computercraft
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI
|
||||
import dan200.computercraft.api.peripheral.IPeripheral
|
||||
import dan200.computercraft.api.peripheral.IPeripheralProvider
|
||||
import li.cil.oc.common.tileentity.Relay
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
|
||||
object PeripheralProvider extends IPeripheralProvider {
|
||||
def init() {
|
||||
ComputerCraftAPI.registerPeripheralProvider(this)
|
||||
}
|
||||
|
||||
override def getPeripheral(world: World, blockPos: BlockPos, enumFacing: EnumFacing): IPeripheral = world.getTileEntity(blockPos) match {
|
||||
case relay: Relay => new RelayPeripheral(relay)
|
||||
case _ => null
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package li.cil.oc.integration.computercraft
|
||||
|
||||
import dan200.computercraft.api.lua.ILuaContext
|
||||
import dan200.computercraft.api.lua.LuaException
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess
|
||||
import dan200.computercraft.api.peripheral.IPeripheral
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network.Component
|
||||
import li.cil.oc.common.tileentity.Relay
|
||||
import li.cil.oc.util.ResultWrapper._
|
||||
import net.minecraft.util.EnumFacing
|
||||
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
|
||||
class RelayPeripheral(val relay: Relay) extends IPeripheral {
|
||||
private val methods = Map[String, (IComputerAccess, ILuaContext, Array[AnyRef]) => Array[AnyRef]](
|
||||
// Generic modem methods.
|
||||
"open" -> ((computer, context, arguments) => {
|
||||
val port = checkPort(arguments, 0)
|
||||
if (relay.openPorts(computer).size >= 128)
|
||||
throw new IllegalArgumentException("too many open channels")
|
||||
result(relay.openPorts(computer).add(port))
|
||||
}),
|
||||
"isOpen" -> ((computer, context, arguments) => {
|
||||
val port = checkPort(arguments, 0)
|
||||
result(relay.openPorts(computer).contains(port))
|
||||
}),
|
||||
"close" -> ((computer, context, arguments) => {
|
||||
val port = checkPort(arguments, 0)
|
||||
result(relay.openPorts(computer).remove(port))
|
||||
}),
|
||||
"closeAll" -> ((computer, context, arguments) => {
|
||||
relay.openPorts(computer).clear()
|
||||
null
|
||||
}),
|
||||
"transmit" -> ((computer, context, arguments) => {
|
||||
val sendPort = checkPort(arguments, 0)
|
||||
val answerPort = checkPort(arguments, 1)
|
||||
val data = arguments.drop(2) ++ Seq(Int.box(answerPort))
|
||||
val packet = api.Network.newPacket(s"cc${computer.getID}_${computer.getAttachmentName}", null, sendPort, data.toArray)
|
||||
result(relay.tryEnqueuePacket(None, packet))
|
||||
}),
|
||||
"isWireless" -> ((computer, context, arguments) => {
|
||||
// Let's pretend we're always wired, to allow accessing OC components
|
||||
// as remote peripherals when using an Access Point, too...
|
||||
result(false)
|
||||
}),
|
||||
|
||||
// Undocumented modem messages.
|
||||
"callRemote" -> ((computer, context, arguments) => {
|
||||
val address = checkString(arguments, 0)
|
||||
visibleComponents.find(_.address == address) match {
|
||||
case Some(component) =>
|
||||
val method = checkString(arguments, 1)
|
||||
val fakeContext = new CCContext(computer, context)
|
||||
component.invoke(method, fakeContext, arguments.drop(2): _*)
|
||||
case _ => null
|
||||
}
|
||||
}),
|
||||
"getMethodsRemote" -> ((computer, context, arguments) => {
|
||||
val address = checkString(arguments, 0)
|
||||
visibleComponents.find(_.address == address) match {
|
||||
case Some(component) => result(mapAsJavaMap(component.methods.zipWithIndex.map(t => (t._2 + 1, t._1)).toMap))
|
||||
case _ => null
|
||||
}
|
||||
}),
|
||||
"getNamesRemote" -> ((computer, context, arguments) => {
|
||||
result(mapAsJavaMap(visibleComponents.map(_.address).zipWithIndex.map(t => (t._2 + 1, t._1)).toMap))
|
||||
}),
|
||||
"getTypeRemote" -> ((computer, context, arguments) => {
|
||||
val address = checkString(arguments, 0)
|
||||
visibleComponents.find(_.address == address) match {
|
||||
case Some(component) => result(component.name)
|
||||
case _ => null
|
||||
}
|
||||
}),
|
||||
"isPresentRemote" -> ((computer, context, arguments) => {
|
||||
val address = checkString(arguments, 0)
|
||||
result(visibleComponents.exists(_.address == address))
|
||||
}),
|
||||
|
||||
// OC specific.
|
||||
"isAccessPoint" -> ((computer, context, arguments) => {
|
||||
result(relay.isWirelessEnabled)
|
||||
}),
|
||||
"isTunnel" -> ((computer, context, arguments) => {
|
||||
result(relay.isLinkedEnabled)
|
||||
}),
|
||||
"maxPacketSize" -> ((computer, context, arguments) => {
|
||||
result(Settings.get.maxNetworkPacketSize)
|
||||
})
|
||||
)
|
||||
|
||||
private val methodNames = methods.keys.toArray.sorted
|
||||
|
||||
override def getType = "modem"
|
||||
|
||||
override def attach(computer: IComputerAccess) {
|
||||
relay.computers += computer
|
||||
relay.openPorts += computer -> mutable.Set.empty
|
||||
}
|
||||
|
||||
override def detach(computer: IComputerAccess) {
|
||||
relay.computers -= computer
|
||||
relay.openPorts -= computer
|
||||
}
|
||||
|
||||
override def getMethodNames = methodNames
|
||||
|
||||
override def callMethod(computer: IComputerAccess, context: ILuaContext, method: Int, arguments: Array[AnyRef]) =
|
||||
try methods(methodNames(method))(computer, context, arguments) catch {
|
||||
case e: LuaException => throw e
|
||||
case t: Throwable =>
|
||||
t.printStackTrace()
|
||||
throw new LuaException(t.getMessage)
|
||||
}
|
||||
|
||||
override def equals(other: IPeripheral) = other match {
|
||||
case peripheral: RelayPeripheral => peripheral.relay == relay
|
||||
case _ => false
|
||||
}
|
||||
|
||||
private def checkPort(args: Array[AnyRef], index: Int) = {
|
||||
if (args.length <= index || !args(index).isInstanceOf[Number])
|
||||
throw new IllegalArgumentException(s"bad argument #${index + 1} (number expected)")
|
||||
val port = args(index).asInstanceOf[Double].toInt
|
||||
if (port < 0 || port > 0xFFFF)
|
||||
throw new IllegalArgumentException(s"bad argument #${index + 1} (number in [1, 65535] expected)")
|
||||
port
|
||||
}
|
||||
|
||||
private def checkString(args: Array[AnyRef], index: Int) = {
|
||||
if (args.length <= index || !args(index).isInstanceOf[String])
|
||||
throw new IllegalArgumentException(s"bad argument #${index + 1} (string expected)")
|
||||
args(index).asInstanceOf[String]
|
||||
}
|
||||
|
||||
private def visibleComponents = {
|
||||
EnumFacing.values().flatMap(side => {
|
||||
val node = relay.sidedNode(side)
|
||||
node.reachableNodes.collect {
|
||||
case component: Component if component.canBeSeenFrom(node) => component
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
class CCContext(val computer: IComputerAccess, val context: ILuaContext) extends Context {
|
||||
override def node() = relay.node
|
||||
|
||||
override def isPaused = false
|
||||
|
||||
override def stop() = false
|
||||
|
||||
override def canInteract(player: String) = true
|
||||
|
||||
override def signal(name: String, args: AnyRef*) = {
|
||||
computer.queueEvent(name, args.toArray)
|
||||
true
|
||||
}
|
||||
|
||||
override def pause(seconds: Double) = false
|
||||
|
||||
override def isRunning = true
|
||||
|
||||
override def start() = false
|
||||
|
||||
override def consumeCallBudget(callCost: Double): Unit = {}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user