mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-05-06 17:34:15 +00:00
Allow ILuaAPIs to be exposed as a module
- cc.require now uses the internal _LOADED table to get the list of built-in globals. This fixes several globals not showing up on the list (e.g. utf8), and allows us to inject more modules from the Java side. - ILuaAPI now has a getModuleName() function. This is used to inject the API into the aforementioned _LOADED table, allowing it to be "require"d.
This commit is contained in:
parent
f26e443e81
commit
8db5c6bc3a
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Lua object which is stored as a global variable on computer startup. This must either provide
|
* Represents a Lua object which is stored as a global variable on computer startup. This must either provide
|
||||||
* {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}.
|
* {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}.
|
||||||
@ -15,12 +17,31 @@ package dan200.computercraft.api.lua;
|
|||||||
*/
|
*/
|
||||||
public interface ILuaAPI {
|
public interface ILuaAPI {
|
||||||
/**
|
/**
|
||||||
* Get the globals this API will be assigned to. This will override any other global, so you should
|
* Get the globals this API will be assigned to.
|
||||||
|
* <p>
|
||||||
|
* This will override any other global, so you should be careful to pick a unique name. Alternatively, you may
|
||||||
|
* return the empty array here, and instead override {@link #getModuleName()}.
|
||||||
*
|
*
|
||||||
* @return A list of globals this API will be assigned to.
|
* @return A list of globals this API will be assigned to.
|
||||||
*/
|
*/
|
||||||
String[] getNames();
|
String[] getNames();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the module name this API should be available as.
|
||||||
|
* <p>
|
||||||
|
* Rather than (or as well as) making this API available as a global, APIs can be exposed as {@code require}able
|
||||||
|
* modules. This is generally more idiomatic, as it avoids polluting the global environment.
|
||||||
|
* <p>
|
||||||
|
* Modules defined here take precedence over user-defined modules, and so like with {@link #getNames()}, you should
|
||||||
|
* be careful to pick a unique name. It is recommended that module names should be camel case, and live under a
|
||||||
|
* namespace associated with your mod. For instance, {@code "mod_id.a_custom_api"}.
|
||||||
|
*
|
||||||
|
* @return The module name of this API, or {@code null} if this API should not be loadable as a module.
|
||||||
|
*/
|
||||||
|
default @Nullable String getModuleName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the computer is turned on.
|
* Called when the computer is turned on.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -25,7 +25,6 @@ import org.squiddev.cobalt.lib.Bit32Lib;
|
|||||||
import org.squiddev.cobalt.lib.CoreLibraries;
|
import org.squiddev.cobalt.lib.CoreLibraries;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -49,7 +48,7 @@ public class CobaltLuaMachine implements ILuaMachine {
|
|||||||
|
|
||||||
private @Nullable String eventFilter = null;
|
private @Nullable String eventFilter = null;
|
||||||
|
|
||||||
public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws MachineException, IOException {
|
public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws MachineException {
|
||||||
timeout = environment.timeout();
|
timeout = environment.timeout();
|
||||||
context = environment.context();
|
context = environment.context();
|
||||||
luaMethods = environment.luaMethods();
|
luaMethods = environment.luaMethods();
|
||||||
@ -81,7 +80,7 @@ public class CobaltLuaMachine implements ILuaMachine {
|
|||||||
globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings));
|
globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings));
|
||||||
|
|
||||||
// Add default APIs
|
// Add default APIs
|
||||||
for (var api : environment.apis()) addAPI(globals, api);
|
for (var api : environment.apis()) addAPI(state, globals, api);
|
||||||
|
|
||||||
// And load the BIOS
|
// And load the BIOS
|
||||||
var value = LoadState.load(state, bios, "@bios.lua", globals);
|
var value = LoadState.load(state, bios, "@bios.lua", globals);
|
||||||
@ -93,7 +92,7 @@ public class CobaltLuaMachine implements ILuaMachine {
|
|||||||
timeout.addListener(timeoutListener);
|
timeout.addListener(timeoutListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAPI(LuaTable globals, ILuaAPI api) {
|
private void addAPI(LuaState state, LuaTable globals, ILuaAPI api) throws LuaError {
|
||||||
// Add the methods of an API to the global table
|
// Add the methods of an API to the global table
|
||||||
var table = wrapLuaObject(api);
|
var table = wrapLuaObject(api);
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
@ -103,6 +102,9 @@ public class CobaltLuaMachine implements ILuaMachine {
|
|||||||
|
|
||||||
var names = api.getNames();
|
var names = api.getNames();
|
||||||
for (var name : names) globals.rawset(name, table);
|
for (var name : names) globals.rawset(name, table);
|
||||||
|
|
||||||
|
var moduleName = api.getModuleName();
|
||||||
|
if (moduleName != null) state.registry().getSubTable(Constants.LOADED).rawset(moduleName, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTimeout() {
|
private void updateTimeout() {
|
||||||
|
@ -124,13 +124,22 @@ local function make_package(env, dir)
|
|||||||
local package = {}
|
local package = {}
|
||||||
package.loaded = {
|
package.loaded = {
|
||||||
_G = _G,
|
_G = _G,
|
||||||
bit32 = bit32,
|
|
||||||
coroutine = coroutine,
|
|
||||||
math = math,
|
|
||||||
package = package,
|
package = package,
|
||||||
string = string,
|
|
||||||
table = table,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Copy everything from the global package table to this instance.
|
||||||
|
--
|
||||||
|
-- This table is an internal implementation detail - it is NOT intended to
|
||||||
|
-- be extended by user code.
|
||||||
|
local registry = debug.getregistry()
|
||||||
|
if registry and type(registry._LOADED) == "table" then
|
||||||
|
for k, v in next, registry._LOADED do
|
||||||
|
if type(k) == "string" then
|
||||||
|
package.loaded[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
|
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
|
||||||
if turtle then
|
if turtle then
|
||||||
package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"
|
package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"
|
||||||
|
@ -89,6 +89,16 @@ public class MethodTest {
|
|||||||
x -> x.addApi(new ReturnFunction()), 50);
|
x -> x.addApi(new ReturnFunction()), 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModule() {
|
||||||
|
ComputerBootstrap.run(
|
||||||
|
"""
|
||||||
|
assert(require "test.module".func() == 123)
|
||||||
|
""",
|
||||||
|
x -> x.addApi(new IsModule()), 50);
|
||||||
|
}
|
||||||
|
|
||||||
public static class MainThread implements ILuaAPI, IPeripheral {
|
public static class MainThread implements ILuaAPI, IPeripheral {
|
||||||
public final String thread = Thread.currentThread().getName();
|
public final String thread = Thread.currentThread().getName();
|
||||||
|
|
||||||
@ -206,7 +216,7 @@ public class MethodTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodResult callMethod(ILuaContext context, int method, IArguments arguments) throws LuaException {
|
public MethodResult callMethod(ILuaContext context, int method, IArguments arguments) {
|
||||||
return MethodResult.of();
|
return MethodResult.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,4 +237,21 @@ public class MethodTest {
|
|||||||
return new String[]{ "func" };
|
return new String[]{ "func" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class IsModule implements ILuaAPI {
|
||||||
|
@Override
|
||||||
|
public String[] getNames() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getModuleName() {
|
||||||
|
return "test.module";
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaFunction
|
||||||
|
public final int func() {
|
||||||
|
return 123;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
|||||||
import dan200.computercraft.core.filesystem.MemoryMount;
|
import dan200.computercraft.core.filesystem.MemoryMount;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.test.core.computer.BasicEnvironment;
|
import dan200.computercraft.test.core.computer.BasicEnvironment;
|
||||||
|
import org.intellij.lang.annotations.Language;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -31,7 +32,7 @@ public class ComputerBootstrap {
|
|||||||
private static final int TPS = 20;
|
private static final int TPS = 20;
|
||||||
public static final int MAX_TIME = 10;
|
public static final int MAX_TIME = 10;
|
||||||
|
|
||||||
public static void run(String program, Consumer<Computer> setup, int maxTimes) {
|
public static void run(@Language("lua") String program, Consumer<Computer> setup, int maxTimes) {
|
||||||
var mount = new MemoryMount()
|
var mount = new MemoryMount()
|
||||||
.addFile("test.lua", program)
|
.addFile("test.lua", program)
|
||||||
.addFile("startup.lua", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()");
|
.addFile("startup.lua", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()");
|
||||||
@ -39,7 +40,7 @@ public class ComputerBootstrap {
|
|||||||
run(mount, setup, maxTimes);
|
run(mount, setup, maxTimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void run(String program, int maxTimes) {
|
public static void run(@Language("lua") String program, int maxTimes) {
|
||||||
run(program, x -> {
|
run(program, x -> {
|
||||||
}, maxTimes);
|
}, maxTimes);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user