Skip to content

Commit

Permalink
Move API factories to the common package
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
SquidDev committed Jul 29, 2024
1 parent cbe075b commit dc3d8ea
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
package dan200.computercraft.api.lua;

import dan200.computercraft.api.peripheral.IComputerAccess;
import org.jetbrains.annotations.ApiStatus;

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
//
// 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;
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;
Expand All @@ -18,16 +19,20 @@
* 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) {
super(environment);
this.environment = environment;
}

@Override
public void shutdown() {
unmountAll();
}

@Override
public String getAttachmentName() {
return "computer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
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;
Expand Down Expand Up @@ -63,6 +64,13 @@ public ServerComputer(
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));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
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;
Expand Down Expand Up @@ -74,7 +73,6 @@ private ServerContext(MinecraftServer server) {
.computerThreads(ConfigSpec.computerThreads.get())
.mainThreadScheduler(mainThread)
.luaFactory(luaMachine)
.apiFactories(ApiFactories.getAll())
.genericMethods(GenericSources.getAllMethods())
.build();
idAssigner = new IDAssigner(storageDir.resolve("ids.json"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -91,15 +88,6 @@ public ILuaMachine.Factory luaFactory() {
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.
*
Expand Down Expand Up @@ -166,7 +154,6 @@ public static class Builder {
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) {
Expand Down Expand Up @@ -227,20 +214,6 @@ public Builder luaFactory(ILuaMachine.Factory factory) {
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}.
*
Expand All @@ -267,7 +240,6 @@ public ComputerContext build() {
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)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,14 @@
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();
}

Expand All @@ -30,7 +26,7 @@ public void update() {

public void shutdown() {
api.shutdown();
if (system != null) system.unmountAll();
if (lifecycle != null) lifecycle.shutdown();
}

public ILuaAPI api() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ public void addApi(ILuaAPI api) {
executor.addApi(api);
}

public void addApi(ILuaAPI api, ApiLifecycle lifecycleHooks) {
executor.addApi(api, lifecycleHooks);
}

long getUniqueTaskId() {
return lastTaskId.incrementAndGet();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -190,6 +183,10 @@ void addApi(ILuaAPI api) {
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.
*/
Expand Down

0 comments on commit dc3d8ea

Please sign in to comment.