1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-23 09:57:39 +00:00

Clean up how we enumerate Lua/peripheral methods

- Move several interfaces out of `d00.computercraft.core.asm` into a
   new `aethods` package. It may make sense to expose this to the
   public API in a future commit (possibly part of #1462).

 - Add a new MethodSupplier<T> interface, which provides methods to
   iterate over all methods exported by an object (either directly, or
   including those from ObjectSources).

   This interface's concrete implementation (asm.MethodSupplierImpl),
   uses Generators and IntCaches as before - we can now make that all
   package-private though, which is nice!

 - Make the LuaMethod and PeripheralMethod MethodSupplier local to the
   ComputerContext. This currently has no effect (the underlying
   Generator is still global), but eventually we'll make GenericMethods
   non-global, which unlocks the door for #1382.

 - Update everything to use this new interface. This is mostly pretty
   sensible, but is a little uglier on the MC side (especially in
   generic peripherals), as we need to access the global ServerContext.
This commit is contained in:
Jonathan Coates
2023-06-26 19:32:09 +01:00
parent a29a516a3f
commit 591a7eca23
33 changed files with 449 additions and 188 deletions

View File

@@ -14,6 +14,8 @@ import dan200.computercraft.core.computer.mainthread.MainThread;
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
import dan200.computercraft.core.lua.CobaltLuaMachine;
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.shared.CommonHooks;
@@ -134,6 +136,16 @@ public final class ServerContext {
return context;
}
/**
* Get the {@link MethodSupplier} used to find methods on peripherals.
*
* @return The {@link PeripheralMethod} method supplier.
* @see ComputerContext#peripheralMethods()
*/
public MethodSupplier<PeripheralMethod> peripheralMethods() {
return context.peripheralMethods();
}
/**
* Tick all components of this server context. This should <em>NOT</em> be called outside of {@link CommonHooks}.
*/

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.upload;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.core.apis.handles.BinaryReadableHandle;
import dan200.computercraft.core.apis.handles.ByteBufferChannel;
import dan200.computercraft.core.asm.ObjectSource;
import dan200.computercraft.core.methods.ObjectSource;
import java.nio.ByteBuffer;
import java.util.Collections;

View File

@@ -6,9 +6,12 @@ package dan200.computercraft.shared.peripheral.generic;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.PeripheralType;
import dan200.computercraft.core.asm.NamedMethod;
import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.methods.MethodSupplier;
import dan200.computercraft.core.methods.NamedMethod;
import dan200.computercraft.core.methods.PeripheralMethod;
import dan200.computercraft.shared.computer.core.ServerContext;
import net.minecraft.core.Direction;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.block.entity.BlockEntity;
import javax.annotation.Nullable;
@@ -25,37 +28,36 @@ import java.util.Set;
* See the platform-specific peripheral providers for the usage of this.
*/
final class GenericPeripheralBuilder {
private final MethodSupplier<PeripheralMethod> peripheralMethods;
private @Nullable String name;
private final Set<String> additionalTypes = new HashSet<>(0);
private final ArrayList<SaturatedMethod> methods = new ArrayList<>(0);
private final ArrayList<SaturatedMethod> methods = new ArrayList<>();
GenericPeripheralBuilder(MinecraftServer server) {
peripheralMethods = ServerContext.get(server).peripheralMethods();
}
@Nullable
IPeripheral toPeripheral(BlockEntity tile, Direction side) {
IPeripheral toPeripheral(BlockEntity blockEntity, Direction side) {
if (methods.isEmpty()) return null;
methods.trimToSize();
return new GenericPeripheral(tile, side, name, additionalTypes, methods);
return new GenericPeripheral(blockEntity, side, name, additionalTypes, methods);
}
boolean addMethods(Object target) {
var methods = PeripheralMethod.GENERATOR.getMethods(target.getClass());
if (methods.isEmpty()) return false;
var saturatedMethods = this.methods;
saturatedMethods.ensureCapacity(saturatedMethods.size() + methods.size());
for (var method : methods) {
saturatedMethods.add(new SaturatedMethod(target, method.name(), method.method()));
return peripheralMethods.forEachSelfMethod(target, (name, method, info) -> {
methods.add(new SaturatedMethod(target, name, method));
// If we have a peripheral type, use it. Always pick the smallest one, so it's consistent (assuming mods
// don't change).
var type = method.genericType();
var type = info == null ? null : info.genericType();
if (type != null && type.getPrimaryType() != null) {
var name = type.getPrimaryType();
if (this.name == null || this.name.compareTo(name) > 0) this.name = name;
var primaryType = type.getPrimaryType();
if (this.name == null || this.name.compareTo(primaryType) > 0) this.name = primaryType;
}
if (type != null) additionalTypes.addAll(type.getAdditionalTypes());
}
return true;
});
}
}

View File

@@ -9,7 +9,7 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.methods.PeripheralMethod;
/**
* A {@link PeripheralMethod} along with the method's target.

View File

@@ -16,10 +16,12 @@ import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.NotAttachedException;
import dan200.computercraft.api.peripheral.WorkMonitor;
import dan200.computercraft.core.apis.PeripheralAPI;
import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.methods.PeripheralMethod;
import dan200.computercraft.core.util.LuaUtil;
import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -284,7 +286,8 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
private void attachPeripheralImpl(IComputerAccess computer, ConcurrentMap<String, RemotePeripheralWrapper> peripherals, String periphName, IPeripheral peripheral) {
if (!peripherals.containsKey(periphName) && !periphName.equals(getLocalPeripheral().getConnectedName())) {
var wrapper = new RemotePeripheralWrapper(modem, peripheral, computer, periphName);
var methods = ServerContext.get(((ServerLevel) getLevel()).getServer()).peripheralMethods().getSelfMethods(peripheral);
var wrapper = new RemotePeripheralWrapper(modem, peripheral, computer, periphName, methods);
peripherals.put(periphName, wrapper);
wrapper.attach();
}
@@ -314,7 +317,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
private volatile boolean attached;
private final Set<String> mounts = new HashSet<>();
RemotePeripheralWrapper(WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name) {
RemotePeripheralWrapper(WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name, Map<String, PeripheralMethod> methods) {
this.element = element;
this.peripheral = peripheral;
this.computer = computer;
@@ -322,7 +325,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
type = Objects.requireNonNull(peripheral.getType(), "Peripheral type cannot be null");
additionalTypes = peripheral.getAdditionalTypes();
methodMap = PeripheralAPI.getMethods(peripheral);
methodMap = methods;
}
public void attach() {