1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-04-18 08:43:13 +00:00

Move API factories to the common package

We don't actually use this functionality in other projects (e.g.
emulators). In fact the method to add new APIs only exists in the mod
itself!

We still need some mechanism to remove mounts when the computer is
shutdown. We add a new ApiLifecycle interface (with startup and
shutdown hooks), and use those in the ComputerSystem impl.
This commit is contained in:
Jonathan Coates 2024-07-29 19:46:25 +01:00
parent cbe075b001
commit dc3d8ea198
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
11 changed files with 68 additions and 56 deletions

View File

@ -5,6 +5,7 @@
package dan200.computercraft.api.lua;
import dan200.computercraft.api.peripheral.IComputerAccess;
import org.jetbrains.annotations.ApiStatus;
import javax.annotation.Nullable;
@ -12,6 +13,7 @@ import javax.annotation.Nullable;
* An interface passed to {@link ILuaAPIFactory} in order to provide additional information
* about a computer.
*/
@ApiStatus.NonExtendable
public interface IComputerSystem extends IComputerAccess {
/**
* Get the label for this computer.

View File

@ -4,13 +4,15 @@
package dan200.computercraft.api.lua;
import dan200.computercraft.api.ComputerCraftAPI;
import javax.annotation.Nullable;
/**
* Construct an {@link ILuaAPI} for a specific computer.
* Construct an {@link ILuaAPI} for a computer.
*
* @see ILuaAPI
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
*/
@FunctionalInterface
public interface ILuaAPIFactory {

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.core.computer;
package dan200.computercraft.shared.computer.core;
import dan200.computercraft.api.lua.IComputerSystem;
import dan200.computercraft.api.lua.ILuaAPIFactory;
@ -10,6 +10,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.ComputerAccess;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.ApiLifecycle;
import javax.annotation.Nullable;
import java.util.Map;
@ -18,9 +19,8 @@ import java.util.Map;
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs.
*
* @see ILuaAPIFactory
* @see ApiWrapper
*/
public class ComputerSystem extends ComputerAccess implements IComputerSystem {
class ComputerSystem extends ComputerAccess implements IComputerSystem, ApiLifecycle {
private final IAPIEnvironment environment;
ComputerSystem(IAPIEnvironment environment) {
@ -28,6 +28,11 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem {
this.environment = environment;
}
@Override
public void shutdown() {
unmountAll();
}
@Override
public String getAttachmentName() {
return "computer";

View File

@ -13,6 +13,7 @@ import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerEnvironment;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.metrics.MetricsObserver;
import dan200.computercraft.impl.ApiFactories;
import dan200.computercraft.shared.computer.apis.CommandAPI;
import dan200.computercraft.shared.computer.menu.ComputerMenu;
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
@ -63,6 +64,13 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
computer = new Computer(context.computerContext(), this, terminal, computerID);
computer.setLabel(label);
// Load in the externally registered APIs.
for (var factory : ApiFactories.getAll()) {
var system = new ComputerSystem(computer.getAPIEnvironment());
var api = factory.create(system);
if (api != null) computer.addApi(api, system);
}
if (family == ComputerFamily.COMMAND) addAPI(new CommandAPI(this));
}

View File

@ -17,7 +17,6 @@ import dan200.computercraft.core.lua.ILuaMachine;
import dan200.computercraft.core.methods.MethodSupplier;
import dan200.computercraft.core.methods.PeripheralMethod;
import dan200.computercraft.impl.AbstractComputerCraftAPI;
import dan200.computercraft.impl.ApiFactories;
import dan200.computercraft.impl.GenericSources;
import dan200.computercraft.shared.CommonHooks;
import dan200.computercraft.shared.computer.metrics.GlobalMetrics;
@ -74,7 +73,6 @@ public final class ServerContext {
.computerThreads(ConfigSpec.computerThreads.get())
.mainThreadScheduler(mainThread)
.luaFactory(luaMachine)
.apiFactories(ApiFactories.getAll())
.genericMethods(GenericSources.getAllMethods())
.build();
idAssigner = new IDAssigner(storageDir.resolve("ids.json"));

View File

@ -4,7 +4,6 @@
package dan200.computercraft.core;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.core.asm.GenericMethod;
import dan200.computercraft.core.asm.LuaMethodSupplier;
import dan200.computercraft.core.asm.PeripheralMethodSupplier;
@ -35,21 +34,19 @@ public final class ComputerContext {
private final ComputerScheduler computerScheduler;
private final MainThreadScheduler mainThreadScheduler;
private final ILuaMachine.Factory luaFactory;
private final List<ILuaAPIFactory> apiFactories;
private final MethodSupplier<LuaMethod> luaMethods;
private final MethodSupplier<PeripheralMethod> peripheralMethods;
ComputerContext(
private ComputerContext(
GlobalEnvironment globalEnvironment, ComputerScheduler computerScheduler,
MainThreadScheduler mainThreadScheduler, ILuaMachine.Factory luaFactory,
List<ILuaAPIFactory> apiFactories, MethodSupplier<LuaMethod> luaMethods,
MethodSupplier<LuaMethod> luaMethods,
MethodSupplier<PeripheralMethod> peripheralMethods
) {
this.globalEnvironment = globalEnvironment;
this.computerScheduler = computerScheduler;
this.mainThreadScheduler = mainThreadScheduler;
this.luaFactory = luaFactory;
this.apiFactories = apiFactories;
this.luaMethods = luaMethods;
this.peripheralMethods = peripheralMethods;
}
@ -91,15 +88,6 @@ public final class ComputerContext {
return luaFactory;
}
/**
* Additional APIs to inject into each computer.
*
* @return All available API factories.
*/
public List<ILuaAPIFactory> apiFactories() {
return apiFactories;
}
/**
* Get the {@link MethodSupplier} used to find methods on Lua values.
*
@ -166,7 +154,6 @@ public final class ComputerContext {
private @Nullable ComputerScheduler computerScheduler = null;
private @Nullable MainThreadScheduler mainThreadScheduler;
private @Nullable ILuaMachine.Factory luaFactory;
private @Nullable List<ILuaAPIFactory> apiFactories;
private @Nullable List<GenericMethod> genericMethods;
Builder(GlobalEnvironment environment) {
@ -227,20 +214,6 @@ public final class ComputerContext {
return this;
}
/**
* Set the additional {@linkplain ILuaAPIFactory APIs} to add to each computer.
*
* @param apis A list of API factories.
* @return {@code this}, for chaining
* @see ComputerContext#apiFactories()
*/
public Builder apiFactories(Collection<ILuaAPIFactory> apis) {
Objects.requireNonNull(apis);
if (apiFactories != null) throw new IllegalStateException("Main-thread scheduler already specified");
apiFactories = List.copyOf(apis);
return this;
}
/**
* Set the set of {@link GenericMethod}s used by the {@linkplain MethodSupplier method suppliers}.
*
@ -267,7 +240,6 @@ public final class ComputerContext {
computerScheduler == null ? new ComputerThread(1) : computerScheduler,
mainThreadScheduler == null ? new NoWorkMainThreadScheduler() : mainThreadScheduler,
luaFactory == null ? CobaltLuaMachine::new : luaFactory,
apiFactories == null ? List.of() : apiFactories,
LuaMethodSupplier.create(genericMethods == null ? List.of() : genericMethods),
PeripheralMethodSupplier.create(genericMethods == null ? List.of() : genericMethods)
);

View File

@ -21,7 +21,7 @@ public abstract class ComputerAccess implements IComputerAccess {
private static final Logger LOG = LoggerFactory.getLogger(ComputerAccess.class);
private final IAPIEnvironment environment;
private final Set<String> mounts = new HashSet<>();
private final Set<String> mounts = new HashSet<>(0);
protected ComputerAccess(IAPIEnvironment environment) {
this.environment = environment;

View File

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.core.computer;
import dan200.computercraft.api.lua.ILuaAPI;
/**
* Hooks for managing the lifecycle of an API. This allows adding additional logic to an API's {@link ILuaAPI#startup()}
* and {@link ILuaAPI#shutdown()} methods.
*
* @see ILuaAPI
* @see Computer#addApi(ILuaAPI, ApiLifecycle)
*/
public interface ApiLifecycle {
/**
* Called before the API's {@link ILuaAPI#startup()} method, may be used to set up resources.
*/
default void startup() {
}
/**
* Called after the API's {@link ILuaAPI#shutdown()} method, may be used to tear down resources.
*/
default void shutdown() {
}
}

View File

@ -9,18 +9,14 @@ import dan200.computercraft.api.lua.ILuaAPI;
import javax.annotation.Nullable;
/**
* A wrapper for {@link ILuaAPI}s which optionally manages the lifecycle of a {@link ComputerSystem}.
* A wrapper for {@link ILuaAPI}s which provides an optional shutdown hook to clean up resources.
*
* @param api The original API.
* @param lifecycle The optional lifecycle hooks for this API.
*/
final class ApiWrapper {
private final ILuaAPI api;
private final @Nullable ComputerSystem system;
ApiWrapper(ILuaAPI api, @Nullable ComputerSystem system) {
this.api = api;
this.system = system;
}
record ApiWrapper(ILuaAPI api, @Nullable ApiLifecycle lifecycle) {
public void startup() {
if (lifecycle != null) lifecycle.startup();
api.startup();
}
@ -30,7 +26,7 @@ final class ApiWrapper {
public void shutdown() {
api.shutdown();
if (system != null) system.unmountAll();
if (lifecycle != null) lifecycle.shutdown();
}
public ILuaAPI api() {

View File

@ -184,6 +184,10 @@ public class Computer {
executor.addApi(api);
}
public void addApi(ILuaAPI api, ApiLifecycle lifecycleHooks) {
executor.addApi(api, lifecycleHooks);
}
long getUniqueTaskId() {
return lastTaskId.incrementAndGet();
}

View File

@ -162,13 +162,6 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
addApi(new PeripheralAPI(environment, context.peripheralMethods()));
addApi(new OSAPI(environment));
if (CoreConfig.httpEnabled) addApi(new HTTPAPI(environment));
// Load in the externally registered APIs.
for (var factory : context.apiFactories()) {
var system = new ComputerSystem(environment);
var api = factory.create(system);
if (api != null) apis.add(new ApiWrapper(api, system));
}
}
@Override
@ -190,6 +183,10 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
apis.add(new ApiWrapper(api, null));
}
void addApi(ILuaAPI api, ApiLifecycle lifecycleHooks) {
apis.add(new ApiWrapper(api, lifecycleHooks));
}
/**
* Schedule this computer to be started if not already on.
*/