diff --git a/build.gradle b/build.gradle index 3a992c35b..a260bd0d2 100644 --- a/build.gradle +++ b/build.gradle @@ -127,9 +127,6 @@ accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") - compileOnly 'com.google.auto.service:auto-service:1.0-rc7' - annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' - shade 'org.squiddev:Cobalt:0.5.2-SNAPSHOT' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' @@ -140,7 +137,7 @@ accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8' - cctJavadoc 'cc.tweaked:cct-javadoc:1.3.0' + cctJavadoc 'cc.tweaked:cct-javadoc:1.4.0' } // Compile tasks diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 70eab1e72..a51773124 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -8,7 +8,6 @@ import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRule; -import dan200.computercraft.core.asm.GenericSource; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; @@ -17,7 +16,6 @@ import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.turtle.upgrades.*; -import dan200.computercraft.shared.util.ServiceUtil; import net.minecraftforge.fml.common.Mod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -117,6 +115,5 @@ public ComputerCraft() { Config.setup(); Registry.setup(); - GenericSource.setup( () -> ServiceUtil.loadServicesForge( GenericSource.class ) ); } } diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 116b3135b..351fd3b91 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -8,6 +8,7 @@ import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.network.IPacketNetwork; @@ -18,9 +19,11 @@ import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.core.apis.ApiFactories; +import dan200.computercraft.core.asm.GenericMethod; import dan200.computercraft.core.filesystem.FileMount; import dan200.computercraft.core.filesystem.ResourceMount; import dan200.computercraft.shared.*; +import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.wired.WiredNode; @@ -31,6 +34,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.server.ServerLifecycleHooks; @@ -108,6 +112,18 @@ public void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ) Peripherals.register( provider ); } + @Override + public void registerGenericSource( @Nonnull GenericSource source ) + { + GenericMethod.register( source ); + } + + @Override + public void registerGenericCapability( @Nonnull Capability capability ) + { + GenericPeripheralProvider.addCapability( capability ); + } + @Override public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ) { diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 2c4223725..e7f05ab33 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -7,6 +7,7 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; @@ -23,6 +24,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; @@ -116,7 +118,7 @@ public static IMount createResourceMount( @Nonnull String domain, @Nonnull Strin } /** - * Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations. + * rers a peripheral provider to convert blocks into {@link IPeripheral} implementations. * * @param provider The peripheral provider to register. * @see IPeripheral @@ -127,6 +129,28 @@ public static void registerPeripheralProvider( @Nonnull IPeripheralProvider prov getInstance().registerPeripheralProvider( provider ); } + /** + * Registers a method source for generic peripherals. + * + * @param source The method source to register. + * @see GenericSource + */ + public static void registerGenericSource( @Nonnull GenericSource source ) + { + getInstance().registerGenericSource( source ); + } + + /** + * Registers a capability that can be used by generic peripherals. + * + * @param capability The capability to register. + * @see GenericSource + */ + public static void registerGenericCapability( @Nonnull Capability capability ) + { + getInstance().registerGenericCapability( capability ); + } + /** * Registers a new turtle turtle for use in ComputerCraft. After calling this, * users should be able to craft Turtles with your new turtle. It is recommended to call @@ -258,6 +282,10 @@ public interface IComputerCraftAPI void registerPeripheralProvider( @Nonnull IPeripheralProvider provider ); + void registerGenericSource( @Nonnull GenericSource source ); + + void registerGenericCapability( @Nonnull Capability capability ); + void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade ); void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ); diff --git a/src/main/java/dan200/computercraft/api/lua/GenericSource.java b/src/main/java/dan200/computercraft/api/lua/GenericSource.java new file mode 100644 index 000000000..f5a3178a3 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/GenericSource.java @@ -0,0 +1,60 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.core.asm.LuaMethod; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; + +/** + * A generic source of {@link LuaMethod} functions. + * + * Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but + * instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject + * methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a + * {@link Capability}). + * + * Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider} + * or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name + * determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable + * design has been established. + * + * For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s: + * + *
{@code
+ * public class InventoryMethods implements GenericSource {
+ *     @LuaFunction( mainThread = true )
+ *     public static int size(IItemHandler inventory) {
+ *         return inventory.getSlots();
+ *     }
+ *
+ *     // ...
+ * }
+ * }
+ * + * @see ComputerCraftAPI#registerGenericSource(GenericSource) + * @see ComputerCraftAPI#registerGenericCapability(Capability) New capabilities (those not built into Forge) must be + * explicitly given to the generic peripheral system, as there is no way to enumerate all capabilities. + */ +public interface GenericSource +{ + /** + * A unique identifier for this generic source. + * + * This is currently unused, but may be used in the future to allow disabling specific sources. It is recommended + * to return an identifier using your mod's ID. + * + * @return This source's identifier. + */ + @Nonnull + ResourceLocation id(); +} diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java index c559c4112..c630b140f 100644 --- a/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -11,10 +11,7 @@ import com.google.common.primitives.Primitives; import com.google.common.reflect.TypeToken; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.IArguments; -import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.LuaFunction; -import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.lua.*; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; @@ -111,7 +108,7 @@ private List> build( Class klass ) addMethod( methods, method, annotation, instance ); } - for( GenericSource.GenericMethod method : GenericSource.GenericMethod.all() ) + for( GenericMethod method : GenericMethod.all() ) { if( !method.target.isAssignableFrom( klass ) ) continue; diff --git a/src/main/java/dan200/computercraft/core/asm/GenericMethod.java b/src/main/java/dan200/computercraft/core/asm/GenericMethod.java new file mode 100644 index 000000000..ebd589112 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/GenericMethod.java @@ -0,0 +1,85 @@ +package dan200.computercraft.core.asm; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.GenericSource; +import dan200.computercraft.api.lua.LuaFunction; + +import javax.annotation.Nonnull; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * A generic method is a method belonging to a {@link GenericSource} with a known target. + */ +public class GenericMethod +{ + final Method method; + final LuaFunction annotation; + final Class target; + + private static final List sources = new ArrayList<>(); + private static List cache; + + GenericMethod( Method method, LuaFunction annotation, Class target ) + { + this.method = method; + this.annotation = annotation; + this.target = target; + } + + /** + * Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}. + * + * @return All available generic methods. + */ + static List all() + { + if( cache != null ) return cache; + return cache = sources.stream() + .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) + .map( method -> + { + LuaFunction annotation = method.getAnnotation( LuaFunction.class ); + if( annotation == null ) return null; + + if( !Modifier.isStatic( method.getModifiers() ) ) + { + ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() ); + return null; + } + + Type[] types = method.getGenericParameterTypes(); + if( types.length == 0 ) + { + ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() ); + return null; + } + + Class target = Reflect.getRawType( method, types[0], false ); + if( target == null ) return null; + + return new GenericMethod( method, annotation, target ); + } ) + .filter( Objects::nonNull ) + .collect( Collectors.toList() ); + } + + + public static synchronized void register( @Nonnull GenericSource source ) + { + Objects.requireNonNull( source, "Source cannot be null" ); + + if( cache != null ) + { + ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); + } + + sources.add( source ); + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/GenericSource.java b/src/main/java/dan200/computercraft/core/asm/GenericSource.java deleted file mode 100644 index ff28ea6e1..000000000 --- a/src/main/java/dan200/computercraft/core/asm/GenericSource.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.core.asm; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.LuaFunction; -import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; -import dan200.computercraft.shared.util.ServiceUtil; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own. - * - * Unlike conventional Lua objects, the annotated methods should be {@code static}, with their target as the first - * parameter. - * - * This is used by the generic peripheral system ({@link GenericPeripheralProvider}) to provide methods for arbitrary - * tile entities. Eventually this'll be be exposed in the public API. Until it is stabilised, it will remain in this - * package - do not use it in external mods! - */ -public interface GenericSource -{ - /** - * A unique identifier for this generic source. This may be used in the future to allow disabling specific sources. - * - * @return This source's identifier. - */ - @Nonnull - ResourceLocation id(); - - /** - * Register a stream of generic sources. - * - * @param sources The source of generic methods. - * @see ServiceUtil For ways to load this. Sadly {@link java.util.ServiceLoader} is broken under Forge, but we don't - * want to add a hard-dep on Forge within core either. - */ - static void setup( Supplier> sources ) - { - GenericMethod.sources = sources; - } - - /** - * A generic method is a method belonging to a {@link GenericSource} with a known target. - */ - class GenericMethod - { - final Method method; - final LuaFunction annotation; - final Class target; - - static Supplier> sources; - private static List cache; - - GenericMethod( Method method, LuaFunction annotation, Class target ) - { - this.method = method; - this.annotation = annotation; - this.target = target; - } - - /** - * Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}. - * - * @return All available generic methods. - */ - static List all() - { - if( cache != null ) return cache; - if( sources == null ) - { - ComputerCraft.log.warn( "Getting GenericMethods without a provider" ); - return cache = Collections.emptyList(); - } - - return cache = sources.get() - .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) - .map( method -> - { - LuaFunction annotation = method.getAnnotation( LuaFunction.class ); - if( annotation == null ) return null; - - if( !Modifier.isStatic( method.getModifiers() ) ) - { - ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() ); - return null; - } - - Type[] types = method.getGenericParameterTypes(); - if( types.length == 0 ) - { - ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() ); - return null; - } - - Class target = Reflect.getRawType( method, types[0], false ); - if( target == null ) return null; - - return new GenericMethod( method, annotation, target ); - } ) - .filter( Objects::nonNull ) - .collect( Collectors.toList() ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index dd9240465..a3a347fe5 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -245,7 +245,7 @@ private static void registerTurtleUpgrades() { // Upgrades ComputerCraft.TurtleUpgrades.wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ); - TurtleUpgrades.register( ComputerCraft.TurtleUpgrades.wirelessModemNormal ); + ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemNormal ); ComputerCraft.TurtleUpgrades.wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ); ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index 7f81033d0..8eab46f11 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -15,22 +15,22 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.NonNullConsumer; -import net.minecraftforge.energy.CapabilityEnergy; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.items.CapabilityItemHandler; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class GenericPeripheralProvider { - private static final Capability[] CAPABILITIES = new Capability[] { - CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, - CapabilityEnergy.ENERGY, - CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, - }; + private static final ArrayList> capabilities = new ArrayList<>(); + + public static synchronized void addCapability( Capability capability ) + { + Objects.requireNonNull( capability, "Capability cannot be null" ); + if( !capabilities.contains( capability ) ) capabilities.add( capability ); + } @Nullable public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer> invalidate ) @@ -43,7 +43,7 @@ public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos List> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() ); if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods ); - for( Capability capability : CAPABILITIES ) + for( Capability capability : capabilities ) { LazyOptional wrapper = tile.getCapability( capability ); wrapper.ifPresent( contents -> { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java index a7ae044af..4bf894a24 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java @@ -5,12 +5,11 @@ */ package dan200.computercraft.shared.peripheral.generic.methods; -import com.google.auto.service.AutoService; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.LuaFunction; -import dan200.computercraft.core.asm.GenericSource; import net.minecraft.util.ResourceLocation; import net.minecraftforge.energy.IEnergyStorage; -import net.minecraftforge.versions.forge.ForgeVersion; import javax.annotation.Nonnull; @@ -26,14 +25,13 @@ * * @cc.module energy_storage */ -@AutoService( GenericSource.class ) public class EnergyMethods implements GenericSource { @Nonnull @Override public ResourceLocation id() { - return new ResourceLocation( ForgeVersion.MOD_ID, "energy" ); + return new ResourceLocation( ComputerCraft.MOD_ID, "energy" ); } /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java index 9c994aa6e..3a66f809a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -5,12 +5,12 @@ */ package dan200.computercraft.shared.peripheral.generic.methods; -import com.google.auto.service.AutoService; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.core.asm.GenericSource; import dan200.computercraft.shared.peripheral.generic.data.FluidData; import net.minecraft.fluid.Fluid; import net.minecraft.util.ResourceLocation; @@ -20,7 +20,6 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.versions.forge.ForgeVersion; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -35,14 +34,13 @@ * * @cc.module fluid_storage */ -@AutoService( GenericSource.class ) public class FluidMethods implements GenericSource { @Nonnull @Override public ResourceLocation id() { - return new ResourceLocation( ForgeVersion.MOD_ID, "fluid" ); + return new ResourceLocation( ComputerCraft.MOD_ID, "fluid" ); } /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 8d044bf69..d247d7aee 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -5,12 +5,12 @@ */ package dan200.computercraft.shared.peripheral.generic.methods; -import com.google.auto.service.AutoService; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.core.asm.GenericSource; import dan200.computercraft.shared.peripheral.generic.data.ItemData; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; @@ -21,7 +21,6 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.wrapper.InvWrapper; -import net.minecraftforge.versions.forge.ForgeVersion; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -36,14 +35,13 @@ * * @cc.module inventory */ -@AutoService( GenericSource.class ) public class InventoryMethods implements GenericSource { @Nonnull @Override public ResourceLocation id() { - return new ResourceLocation( ForgeVersion.MOD_ID, "inventory" ); + return new ResourceLocation( ComputerCraft.MOD_ID, "inventory" ); } /** diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 38eb89930..f75f99f2a 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -24,6 +24,9 @@ import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.peripheral.generic.methods.EnergyMethods; +import dan200.computercraft.shared.peripheral.generic.methods.FluidMethods; +import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.util.NullStorage; import net.minecraft.inventory.container.Container; @@ -36,15 +39,19 @@ import net.minecraft.world.storage.loot.TableLootEntry; import net.minecraft.world.storage.loot.conditions.LootConditionManager; import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fml.DeferredWorkQueue; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; +import net.minecraftforge.items.CapabilityItemHandler; import java.util.Arrays; import java.util.HashSet; @@ -59,11 +66,15 @@ public static void init( FMLCommonSetupEvent event ) { NetworkHandler.setup(); - net.minecraftforge.fml.DeferredWorkQueue.runLater( () -> { + DeferredWorkQueue.runLater( () -> { registerProviders(); ArgumentSerializers.register(); registerLoot(); } ); + + ComputerCraftAPI.registerGenericSource( new InventoryMethods() ); + ComputerCraftAPI.registerGenericSource( new FluidMethods() ); + ComputerCraftAPI.registerGenericSource( new EnergyMethods() ); } public static void registerLoot() @@ -103,6 +114,12 @@ private static void registerProviders() // Register capabilities CapabilityManager.INSTANCE.register( IWiredElement.class, new NullStorage<>(), () -> null ); CapabilityManager.INSTANCE.register( IPeripheral.class, new NullStorage<>(), () -> null ); + + // Register generic capabilities. This can technically be done off-thread, but we need it to happen + // after Forge's common setup, so this is easiest. + ComputerCraftAPI.registerGenericCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ); + ComputerCraftAPI.registerGenericCapability( CapabilityEnergy.ENERGY ); + ComputerCraftAPI.registerGenericCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY ); } @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) diff --git a/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java b/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java deleted file mode 100644 index c21861dda..000000000 --- a/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.util; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.ComputerCraftAPI; -import net.minecraftforge.fml.ModList; -import org.objectweb.asm.Type; - -import java.util.List; -import java.util.ServiceLoader; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -public final class ServiceUtil -{ - private static final Type AUTO_SERVICE = Type.getType( "Lcom/google/auto/service/AutoService;" ); - - private ServiceUtil() - { - } - - public static Stream loadServices( Class target ) - { - return StreamSupport.stream( ServiceLoader.load( target, ServiceUtil.class.getClassLoader() ).spliterator(), false ); - } - - public static Stream loadServicesForge( Class target ) - { - Type type = Type.getType( target ); - ClassLoader loader = ComputerCraftAPI.class.getClassLoader(); - return ModList.get().getAllScanData().stream() - .flatMap( x -> x.getAnnotations().stream() ) - .filter( x -> x.getAnnotationType().equals( AUTO_SERVICE ) ) - .filter( x -> { - Object value = x.getAnnotationData().get( "value" ); - return value instanceof List && ((List) value).contains( type ); - } ) - .flatMap( x -> { - try - { - Class klass = loader.loadClass( x.getClassType().getClassName() ); - if( !target.isAssignableFrom( klass ) ) - { - ComputerCraft.log.error( "{} is not a subtype of {}", x.getClassType().getClassName(), target.getName() ); - return Stream.empty(); - } - - Class casted = klass.asSubclass( target ); - return Stream.of( casted.newInstance() ); - } - catch( ReflectiveOperationException e ) - { - ComputerCraft.log.error( "Cannot load {}", x.getClassType(), e ); - return Stream.empty(); - } - } ); - } -}