mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 19:25:20 -04:00
Merge branch 'master' of https://github.com/MightyPirates/OpenComputers into MC1.7
Conflicts: src/main/java/li/cil/oc/common/asm/SimpleComponentTickHandler.java
This commit is contained in:
commit
a401858a80
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.api;
|
||||
|
||||
import cpw.mods.fml.common.Optional;
|
||||
import dan200.computer.api.IMount;
|
||||
import dan200.computer.api.IWritableMount;
|
||||
import li.cil.oc.api.detail.FileSystemAPI;
|
||||
@ -112,6 +113,7 @@ public final class FileSystem {
|
||||
* @param mount the mount to wrap with a file system.
|
||||
* @return a file system wrapping the specified mount.
|
||||
*/
|
||||
@Optional.Method(modid = "ComputerCraft")
|
||||
public static li.cil.oc.api.fs.FileSystem fromComputerCraft(final IMount mount) {
|
||||
if (instance != null) return instance.fromComputerCraft(mount);
|
||||
return null;
|
||||
@ -123,6 +125,7 @@ public final class FileSystem {
|
||||
* @param mount the mount to wrap with a file system.
|
||||
* @return a file system wrapping the specified mount.
|
||||
*/
|
||||
@Optional.Method(modid = "ComputerCraft")
|
||||
public static li.cil.oc.api.fs.FileSystem fromComputerCraft(final IWritableMount mount) {
|
||||
if (instance != null) return instance.fromComputerCraft(mount);
|
||||
return null;
|
||||
|
85
src/main/java/li/cil/oc/api/README.md
Normal file
85
src/main/java/li/cil/oc/api/README.md
Normal file
@ -0,0 +1,85 @@
|
||||
The API can be used to either interact with existing implementations in OpenComputers or to implement your own extensions for OpenComputers.
|
||||
|
||||
Extending OpenComputers
|
||||
========================
|
||||
|
||||
Making a tile entity available as a component / peripheral
|
||||
--------------------------------------------------
|
||||
If you simply wish to expose a couple of methods that can be called from a computer if your tile entity's block is 'connected' to the computer, you can use the `SimpleComponent` interface. This interface serves as a marker for OpenComputers to know it has to inject code that converts your tile entity into a component using its class transformer. It is an interface instead of an annotation to allow stripping it, removing any dependencies on OpenComputers. Here is an example implementation:
|
||||
```java
|
||||
@Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers")
|
||||
public class TileEntityMyFancyThing extends TileEntity
|
||||
implements SimpleComponent
|
||||
{
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return "fancy_thing";
|
||||
}
|
||||
|
||||
@Callback
|
||||
@Optional.Method(modid = "OpenComputers")
|
||||
public Object[] greet(Context context, Arguments args) {
|
||||
return new Object[]{String.format("Hello, %s!", args.checkString(0))};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `getComponentName` determines with which name the tile entity will be available to computers. The `Callback` annotation tells OpenComputers to make the annotated method available to the computer. See the documentation on the `Callback` annotation for more information, in particular how it can be used to manipulate the call behavior (synchronized to the main thread vs. in the thread driving the calling computer).
|
||||
|
||||
So to call the greeter method, in Lua you'd do this:
|
||||
```lua
|
||||
print(component.fancy_thing.greet("Steve")) -- prints "Hello, Steve!"
|
||||
````
|
||||
|
||||
More control
|
||||
------------
|
||||
If you really need more control over how how your tile entity interacts with OpenComputer's internal network, you will have to implement the `Environment` interface on your tile entity. There's a basic implementation in the prefab package, named `TileEntityEnvironment`. Doing so will give you access to the `Node` that connects to the component network, and you must take care of the construction of the node itself (using the factory method in `api.Network`). This allows you to make the node a `Connector` node, which will allow you to draw internal power from OpenComputers or feed energy into it. You will also be able to send messages over the component network, see the `send...` methods in the `Node` interface. See the documentation on those interfaces to get a better idea on how they work together.
|
||||
|
||||
Making a thrid-party block available as component / peripheral
|
||||
--------------------------------------------------------------
|
||||
Blocks from other mods, i.e. blocks where you have no control over the tile entity implementation, can be accessed using the Adapter block as long as there is a driver available that supports the block. If there are multiple drivers they are automatically merged. Please see the [OpenComponents][] project for examples, and consider contributing any block drivers you write to it. Thank you.
|
||||
|
||||
Making items available as components
|
||||
------------------------------------
|
||||
To make items usable as components in computers, such as cards or hard drives, you have to provide a driver for that item. This means you have to implement the `driver.Item` interface on a class and register an instance of it via the `api.Driver` registry. You can base your item drivers on the `DriverItem` prefab. Please see the example project on Github for a working example, and read the documentation of the driver interface for more information.
|
||||
|
||||
FileSystem API
|
||||
==============
|
||||
If you'd like to make some files/scripts you ship with your mod available to a computer, you can do so by wrapping those files using an OpenComputers file system. Use the factory methods in `api.FileSystem` to wrap the location your files are stored at in a file system, use the `asManagedEnvironment` methods to wrap it in a node that can be attached to the component network. For example, in an environment of a tile entity or created by an item driver you could do this in the `onConnect` method whenever a computer is connected (i.e. `node.host() instanceof Context`). Code-wise it may look something like this:
|
||||
```java
|
||||
public class TileEntityWithFileSystem extends TileEntityEnvironment {
|
||||
private final Node fileSystem;
|
||||
|
||||
public TileEntityWithFileSystem() {
|
||||
node = Network.newNode(this, Visibility.Network).create();
|
||||
fileSystem = FileSystem.asManagedEnvironment(FileSystem.fromClass(getClass, "yourmodid/lua"), "my_files");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect(final Node node) {
|
||||
if (node.host() instanceof Context) {
|
||||
// Attach our file system to new computers we get connected to.
|
||||
// Note that this is also called for all already present computers
|
||||
// when we're added to an already existing network, so we don't
|
||||
// have to loop through the existing nodes manually.
|
||||
node.connect(fileSystem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(final Node node) {
|
||||
if (node.host() instanceof Context) {
|
||||
// Remove our file systems when we get disconnected from a
|
||||
// computer.
|
||||
node.disconnect(fileSystem);
|
||||
} else if (node == this.node) {
|
||||
// Remove the file system if we are disconnected, because in that
|
||||
// case this method is only called once.
|
||||
fileSystem.node.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
[OpenComponents]: https://github.com/MightyPirates/OpenComponents
|
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.api.detail;
|
||||
|
||||
import cpw.mods.fml.common.Optional;
|
||||
import dan200.computer.api.IMount;
|
||||
import dan200.computer.api.IWritableMount;
|
||||
import li.cil.oc.api.fs.FileSystem;
|
||||
@ -13,8 +14,10 @@ public interface FileSystemAPI {
|
||||
|
||||
FileSystem fromMemory(long capacity);
|
||||
|
||||
@Optional.Method(modid = "ComputerCraft")
|
||||
FileSystem fromComputerCraft(IMount mount);
|
||||
|
||||
@Optional.Method(modid = "ComputerCraft")
|
||||
FileSystem fromComputerCraft(IWritableMount mount);
|
||||
|
||||
ManagedEnvironment asManagedEnvironment(FileSystem fs, Label label);
|
||||
|
@ -66,6 +66,16 @@ public interface Environment {
|
||||
* At this point the node's network is never <tt>null</tt> and you can use
|
||||
* it to query it for other nodes. Use this to perform initialization logic,
|
||||
* such as building lists of nodes of a certain type in the network.
|
||||
* <p/>
|
||||
* For example, if node C is added to a network with nodes A and B, these
|
||||
* calls are made:
|
||||
* <ul>
|
||||
* <li>A.onConnect(A)</li>
|
||||
* <li>A.onConnect(B)</li>
|
||||
* <li>A.onConnect(C)</li>
|
||||
* <li>B.onConnect(A)</li>
|
||||
* <li>C.onConnect(A)</li>
|
||||
* </ul>
|
||||
*/
|
||||
void onConnect(Node node);
|
||||
|
||||
@ -73,11 +83,20 @@ public interface Environment {
|
||||
* This is called when a node is removed from the network.
|
||||
* <p/>
|
||||
* This is also called for the node itself, when it has been removed from
|
||||
* its network.
|
||||
* its network. Note that this is called on the node that is being removed
|
||||
* <em>only once</em> with the node itself as the parameter.
|
||||
* <p/>
|
||||
* At this point the node's network is no longer available (<tt>null</tt>).
|
||||
* Use this to perform clean-up logic such as removing references to the
|
||||
* removed node.
|
||||
* <p/>
|
||||
* For example, if node C is removed from a network with nodes A, B and C,
|
||||
* these calls are made:
|
||||
* <ul>
|
||||
* <li>A.onDisconnect(A)</li>
|
||||
* <li>B.onDisconnect(A)</li>
|
||||
* <li>C.onDisconnect(A)</li>
|
||||
* </ul>
|
||||
*/
|
||||
void onDisconnect(Node node);
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
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.
|
||||
* This interface can be used with an {@link li.cil.oc.api.network.Environment}
|
||||
* and is intended to be used for environments wrapping a ComputerCraft
|
||||
* peripheral. Tt could be used for other purposes as well, though. 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 Environment {
|
||||
public interface ManagedPeripheral {
|
||||
/**
|
||||
* Get the list of methods provided by this environment, in
|
||||
* <em>addition</em> to methods marked as callbacks.
|
||||
|
@ -40,7 +40,13 @@ package li.cil.oc.api.network;
|
||||
* public class TileEntityMyFancyThing extends TileEntity
|
||||
* implements SimpleComponent
|
||||
* {
|
||||
* {@literal @}Override
|
||||
* public String getComponentName() {
|
||||
* return "fancy_thing";
|
||||
* }
|
||||
*
|
||||
* {@literal @}Callback
|
||||
* {@literal @}Optional.Method(modid = "OpenComputers")
|
||||
* public Object[] greet(Context context, Arguments args) {
|
||||
* return new Object[]{String.format("Hello, %s!", args.checkString(0))};
|
||||
* }
|
||||
@ -55,10 +61,16 @@ package li.cil.oc.api.network;
|
||||
* public class TileEntityMyFancyThing extends TileEntity
|
||||
* implements SimpleComponent, ManagedPeripheral
|
||||
* {
|
||||
* {@literal @}Override
|
||||
* public String getComponentName() {
|
||||
* return "fancy_thing";
|
||||
* }
|
||||
*
|
||||
* public String[] methods() {
|
||||
* return new String[] {"greet"};
|
||||
* }
|
||||
*
|
||||
* {@literal @}Optional.Method(modid = "OpenComputers")
|
||||
* public Object[] invoke(String method, Context context, Arguments args) {
|
||||
* if ("greet".equals(method)) {
|
||||
* return new Object[]{String.format("Hello, %s!", args.checkString(0))};
|
||||
|
@ -37,5 +37,5 @@
|
||||
@cpw.mods.fml.common.API(
|
||||
owner = "OpenComputers|Core",
|
||||
provides = "OpenComputersAPI",
|
||||
apiVersion = "1.2.0")
|
||||
apiVersion = "1.3.0")
|
||||
package li.cil.oc.api;
|
@ -1,184 +0,0 @@
|
||||
package li.cil.oc.api.prefab;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import dan200.computer.api.*;
|
||||
import li.cil.oc.api.FileSystem;
|
||||
import li.cil.oc.api.Network;
|
||||
import li.cil.oc.api.network.Arguments;
|
||||
import li.cil.oc.api.network.Context;
|
||||
import li.cil.oc.api.network.Node;
|
||||
import li.cil.oc.api.network.Visibility;
|
||||
|
||||
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());
|
||||
node = 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 = _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.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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
protected final Map<String, li.cil.oc.api.network.ManagedEnvironment> fileSystems = new HashMap<String, li.cil.oc.api.network.ManagedEnvironment>();
|
||||
|
||||
public FakeComputerAccess(final ManagedPeripheral 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(FileSystem.fromComputerCraft(mount)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mountWritable(final String desiredLocation, final IWritableMount mount) {
|
||||
if (fileSystems.containsKey(desiredLocation)) {
|
||||
return null;
|
||||
}
|
||||
return mount(desiredLocation, FileSystem.asManagedEnvironment(FileSystem.fromComputerCraft(mount)));
|
||||
}
|
||||
|
||||
private String mount(final String path, final li.cil.oc.api.network.ManagedEnvironment fileSystem) {
|
||||
fileSystems.put(path, fileSystem);
|
||||
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.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,9 @@ public final class SimpleComponentTickHandler {
|
||||
|
||||
public static final SimpleComponentTickHandler Instance = new SimpleComponentTickHandler();
|
||||
|
||||
private SimpleComponentTickHandler() {
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onTick(TickEvent.ServerTickEvent e) {
|
||||
synchronized (pendingOperations) {
|
||||
|
@ -13,13 +13,13 @@ opencomputers {
|
||||
# performance. Note that this needs OpenGL 1.4 to work, otherwise text
|
||||
# will always just instantly disappear when moving away from the screen
|
||||
# displaying it.
|
||||
screenTextFadeStartDistance: 8.0
|
||||
screenTextFadeStartDistance: 15.0
|
||||
|
||||
# The maximum distance at which to render text on screens. Rendering text
|
||||
# can be pretty expensive, so if you have a lot of screens you'll want to
|
||||
# avoid huge numbers here. Note that this setting is client-sided, and
|
||||
# only has an impact on render performance on clients.
|
||||
maxScreenTextRenderDistance: 10.0
|
||||
maxScreenTextRenderDistance: 20.0
|
||||
|
||||
# Whether to apply linear filtering for text displayed on screens when the
|
||||
# screen has to be scaled down - i.e. the text is rendered at a resolution
|
||||
@ -56,7 +56,7 @@ opencomputers {
|
||||
# programs blocking other computers by locking down the executor threads.
|
||||
# Note that changing this won't have any effect on computers that are
|
||||
# already running - they'll have to be rebooted for this to take effect.
|
||||
timeout: 1.0
|
||||
timeout: 5.0
|
||||
|
||||
# Whether to allow loading precompiled bytecode via Lua's `load` function,
|
||||
# or related functions (`loadfile`, `dofile`). Enable this only if you
|
||||
|
@ -74,6 +74,8 @@ trait AbstractBusAware extends TileEntity with network.Environment { self: IBusD
|
||||
|
||||
abstract override def onDisconnect(node: network.Node) {
|
||||
super.onDisconnect(node)
|
||||
isAbstractBusAvailable = false
|
||||
if (node == this.node) {
|
||||
isAbstractBusAvailable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import li.cil.oc.util.ThreadPoolFactory
|
||||
import li.cil.oc.{OpenComputers, Settings}
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import scala.Array
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
|
||||
class InternetCard extends ManagedComponent {
|
||||
@ -216,20 +214,16 @@ class InternetCard extends ManagedComponent {
|
||||
|
||||
override def onConnect(node: Node) {
|
||||
super.onConnect(node)
|
||||
if (owner.isEmpty && node.host.isInstanceOf[Context]) {
|
||||
if (owner.isEmpty && node.host.isInstanceOf[Context] && node.isNeighborOf(this.node)) {
|
||||
owner = Some(node.host.asInstanceOf[Context])
|
||||
}
|
||||
if (node == this.node) {
|
||||
romInternet.foreach(rom => node.neighbors.head.connect(rom.node))
|
||||
romInternet.foreach(rom => node.connect(rom.node))
|
||||
}
|
||||
}
|
||||
|
||||
override def onDisconnect(node: Node) {
|
||||
super.onDisconnect(node)
|
||||
if (owner.isDefined && node.host.isInstanceOf[Context] && (node.host.asInstanceOf[Context] == owner.get)) {
|
||||
if (owner.isDefined && (node == this.node || node.host.isInstanceOf[Context] && (node.host.asInstanceOf[Context] == owner.get))) {
|
||||
owner = None
|
||||
}
|
||||
if (node == this.node) {
|
||||
for ((_, socket) <- connections) {
|
||||
socket.close()
|
||||
}
|
||||
|
@ -119,8 +119,8 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent {
|
||||
inventory = None
|
||||
case _ =>
|
||||
}
|
||||
remainingTicks = 0
|
||||
}
|
||||
remainingTicks = 0
|
||||
}
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.server.fs
|
||||
|
||||
import cpw.mods.fml.common.Optional
|
||||
import dan200.computer.api.{IWritableMount, IMount}
|
||||
import java.io
|
||||
import java.net.URL
|
||||
@ -64,8 +65,10 @@ object FileSystem extends api.detail.FileSystemAPI {
|
||||
|
||||
def fromMemory(capacity: Long): api.fs.FileSystem = new RamFileSystem(capacity)
|
||||
|
||||
@Optional.Method(modid = "ComputerCraft")
|
||||
def fromComputerCraft(mount: IMount) = new ComputerCraftFileSystem(mount)
|
||||
|
||||
@Optional.Method(modid = "ComputerCraft")
|
||||
def fromComputerCraft(mount: IWritableMount) = new ComputerCraftWritableFileSystem(mount)
|
||||
|
||||
def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label) =
|
||||
|
Loading…
x
Reference in New Issue
Block a user