From a29a516a3f64fd1fdac33deecd24796c6d6b3577 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 26 Jun 2023 19:11:59 +0100 Subject: [PATCH] Small refactoring to generic peripherals - Remove SidedGenericPeripheral (we never used this!), adding the functionality to GenericPeripheral directly. This is just used on the Fabric side for now, but might make sense with Forge too. - Move GenericPeripheralBuilder into the common project - this is identical between the two projects! - GenericPeripheralBuilder now generates a list of methods internally, rather than being passed the methods. - Add a tiny bit of documentation. --- .../peripheral/generic/GenericPeripheral.java | 15 +++-- .../generic/GenericPeripheralBuilder.java | 61 +++++++++++++++++++ .../peripheral/generic/SaturatedMethod.java | 10 +-- .../generic/GenericPeripheralProvider.java | 53 ++-------------- .../generic/SidedGenericPeripheral.java | 25 -------- .../generic/methods/InventoryMethods.java | 3 +- .../generic/GenericPeripheralProvider.java | 59 +++--------------- 7 files changed, 95 insertions(+), 131 deletions(-) create mode 100644 projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralBuilder.java delete mode 100644 projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/SidedGenericPeripheral.java diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java index f181ae7c4..8874a12b9 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java @@ -12,19 +12,23 @@ import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.platform.RegistryWrappers; +import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntity; import javax.annotation.Nullable; import java.util.List; import java.util.Set; -class GenericPeripheral implements IDynamicPeripheral { +public final class GenericPeripheral implements IDynamicPeripheral { + private final BlockEntity tile; + private final Direction side; + private final String type; private final Set additionalTypes; - private final BlockEntity tile; private final List methods; - GenericPeripheral(BlockEntity tile, @Nullable String name, Set additionalTypes, List methods) { + GenericPeripheral(BlockEntity tile, Direction side, @Nullable String name, Set additionalTypes, List methods) { + this.side = side; var type = RegistryWrappers.BLOCK_ENTITY_TYPES.getKey(tile.getType()); this.tile = tile; this.type = name != null ? name : type.toString(); @@ -32,6 +36,10 @@ class GenericPeripheral implements IDynamicPeripheral { this.methods = methods; } + public Direction side() { + return side; + } + @Override public String[] getMethodNames() { var names = new String[methods.size()]; @@ -54,7 +62,6 @@ public Set getAdditionalTypes() { return additionalTypes; } - @Nullable @Override public Object getTarget() { return tile; diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralBuilder.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralBuilder.java new file mode 100644 index 000000000..1d2c61134 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralBuilder.java @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +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 net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * A builder for a {@link GenericPeripheral}. + *

+ * This handles building a list of {@linkplain SaturatedMethod methods} and computing the appropriate + * {@link PeripheralType} from the {@linkplain NamedMethod#genericType() methods' peripheral types}. + *

+ * See the platform-specific peripheral providers for the usage of this. + */ +final class GenericPeripheralBuilder { + private @Nullable String name; + private final Set additionalTypes = new HashSet<>(0); + private final ArrayList methods = new ArrayList<>(0); + + @Nullable + IPeripheral toPeripheral(BlockEntity tile, Direction side) { + if (methods.isEmpty()) return null; + + methods.trimToSize(); + return new GenericPeripheral(tile, 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())); + + // 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(); + if (type != null && type.getPrimaryType() != null) { + var name = type.getPrimaryType(); + if (this.name == null || this.name.compareTo(name) > 0) this.name = name; + } + if (type != null) additionalTypes.addAll(type.getAdditionalTypes()); + } + + return true; + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java index d43a30de0..8d0c92920 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java @@ -9,18 +9,20 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IComputerAccess; -import dan200.computercraft.core.asm.NamedMethod; import dan200.computercraft.core.asm.PeripheralMethod; +/** + * A {@link PeripheralMethod} along with the method's target. + */ final class SaturatedMethod { private final Object target; private final String name; private final PeripheralMethod method; - SaturatedMethod(Object target, NamedMethod method) { + SaturatedMethod(Object target, String name, PeripheralMethod method) { this.target = target; - name = method.name(); - this.method = method.method(); + this.name = name; + this.method = method; } MethodResult apply(ILuaContext context, IComputerAccess computer, IArguments args) throws LuaException { diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index de61e0d69..a9eefd5bb 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -5,8 +5,6 @@ package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.core.asm.NamedMethod; -import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -15,10 +13,7 @@ import net.minecraft.world.level.block.state.BlockState; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class GenericPeripheralProvider { interface Lookup { @@ -31,53 +26,17 @@ interface Lookup { ); @Nullable - public static IPeripheral getPeripheral(Level world, BlockPos pos, Direction side, @Nullable BlockEntity blockEntity) { + public static IPeripheral getPeripheral(Level level, BlockPos pos, Direction side, @Nullable BlockEntity blockEntity) { if (blockEntity == null) return null; - var saturated = new GenericPeripheralBuilder(); - - var tileMethods = PeripheralMethod.GENERATOR.getMethods(blockEntity.getClass()); - if (!tileMethods.isEmpty()) saturated.addMethods(blockEntity, tileMethods); + var builder = new GenericPeripheralBuilder(); + builder.addMethods(blockEntity); for (var lookup : lookups) { - var contents = lookup.find(world, pos, blockEntity.getBlockState(), blockEntity, side); - if (contents == null) continue; - - var methods = PeripheralMethod.GENERATOR.getMethods(contents.getClass()); - if (!methods.isEmpty()) saturated.addMethods(contents, methods); + var contents = lookup.find(level, pos, blockEntity.getBlockState(), blockEntity, side); + if (contents != null) builder.addMethods(contents); } - return saturated.toPeripheral(blockEntity); - } - - private static class GenericPeripheralBuilder { - private @Nullable String name; - private final Set additionalTypes = new HashSet<>(0); - private final ArrayList methods = new ArrayList<>(0); - - @Nullable - IPeripheral toPeripheral(BlockEntity tile) { - if (methods.isEmpty()) return null; - - methods.trimToSize(); - return new GenericPeripheral(tile, name, additionalTypes, methods); - } - - void addMethods(Object target, List> methods) { - var saturatedMethods = this.methods; - saturatedMethods.ensureCapacity(saturatedMethods.size() + methods.size()); - for (var method : methods) { - saturatedMethods.add(new SaturatedMethod(target, 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(); - if (type != null && type.getPrimaryType() != null) { - var name = type.getPrimaryType(); - if (this.name == null || this.name.compareTo(name) > 0) this.name = name; - } - if (type != null) additionalTypes.addAll(type.getAdditionalTypes()); - } - } + return builder.toPeripheral(blockEntity, side); } } diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/SidedGenericPeripheral.java b/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/SidedGenericPeripheral.java deleted file mode 100644 index b0aa1a351..000000000 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/SidedGenericPeripheral.java +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.shared.peripheral.generic; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntity; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.Set; - -public class SidedGenericPeripheral extends GenericPeripheral { - private final Direction direction; - - SidedGenericPeripheral(BlockEntity tile, Direction direction, @Nullable String name, Set additionalTypes, List methods) { - super(tile, name, additionalTypes, methods); - this.direction = direction; - } - - public Direction direction() { - return direction; - } -} diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 527e62dfe..dfbbdf5b7 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -12,7 +12,6 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.PeripheralType; -import dan200.computercraft.shared.peripheral.generic.SidedGenericPeripheral; import dan200.computercraft.shared.platform.FabricContainerTransfer; import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage; import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; @@ -157,7 +156,7 @@ public static int pullItems( @Nullable private static SlottedStorage extractHandler(IPeripheral peripheral) { var object = peripheral.getTarget(); - var direction = peripheral instanceof SidedGenericPeripheral sided ? sided.direction() : null; + var direction = peripheral instanceof dan200.computercraft.shared.peripheral.generic.GenericPeripheral sided ? sided.side() : null; if (object instanceof BlockEntity blockEntity) { if (blockEntity.isRemoved()) return null; diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index c9a59e366..d8c275101 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -5,18 +5,16 @@ package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.core.asm.NamedMethod; -import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.shared.util.CapabilityUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.NonNullConsumer; import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Objects; public class GenericPeripheralProvider { private static final ArrayList> capabilities = new ArrayList<>(); @@ -27,57 +25,20 @@ public static synchronized void addCapability(Capability capability) { } @Nullable - public static IPeripheral getPeripheral(Level world, BlockPos pos, Direction side, NonNullConsumer invalidate) { - var tile = world.getBlockEntity(pos); - if (tile == null) return null; + public static IPeripheral getPeripheral(Level level, BlockPos pos, Direction side, NonNullConsumer invalidate) { + var blockEntity = level.getBlockEntity(pos); + if (blockEntity == null) return null; - var saturated = new GenericPeripheralBuilder(); - - var tileMethods = PeripheralMethod.GENERATOR.getMethods(tile.getClass()); - if (!tileMethods.isEmpty()) saturated.addMethods(tile, tileMethods); + var builder = new GenericPeripheralBuilder(); + builder.addMethods(blockEntity); for (var capability : capabilities) { - var wrapper = CapabilityUtil.getCapability(tile, capability, side); + var wrapper = CapabilityUtil.getCapability(blockEntity, capability, side); wrapper.ifPresent(contents -> { - var capabilityMethods = PeripheralMethod.GENERATOR.getMethods(contents.getClass()); - if (capabilityMethods.isEmpty()) return; - - saturated.addMethods(contents, capabilityMethods); - CapabilityUtil.addListener(wrapper, invalidate); + if (builder.addMethods(contents)) CapabilityUtil.addListener(wrapper, invalidate); }); } - return saturated.toPeripheral(tile); - } - - private static class GenericPeripheralBuilder { - private @Nullable String name; - private final Set additionalTypes = new HashSet<>(0); - private final ArrayList methods = new ArrayList<>(0); - - @Nullable - IPeripheral toPeripheral(BlockEntity tile) { - if (methods.isEmpty()) return null; - - methods.trimToSize(); - return new GenericPeripheral(tile, name, additionalTypes, methods); - } - - void addMethods(Object target, List> methods) { - var saturatedMethods = this.methods; - saturatedMethods.ensureCapacity(saturatedMethods.size() + methods.size()); - for (var method : methods) { - saturatedMethods.add(new SaturatedMethod(target, 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(); - if (type != null && type.getPrimaryType() != null) { - var name = type.getPrimaryType(); - if (this.name == null || this.name.compareTo(name) > 0) this.name = name; - } - if (type != null) additionalTypes.addAll(type.getAdditionalTypes()); - } - } + return builder.toPeripheral(blockEntity, side); } }