From 01fe949b3eb38eb793a4d5bec28c69f085c120bc Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 16 Feb 2025 19:49:47 +0000 Subject: [PATCH] Use Fabric's Item Lookup for registering media providers We'll switch to capabilities on the (Neo)Forge side for 1.21, when the capability system is less painful, and then fully deprecate in 1.21.4. --- .../impl/AbstractComputerCraftAPI.java | 6 ---- .../peripheral/diskdrive/DiskDriveBlock.java | 4 +-- .../peripheral/diskdrive/MediaStack.java | 4 +-- .../shared/platform/PlatformHelper.java | 10 ++++++ .../computercraft/TestPlatformHelper.java | 12 +++++++ .../computercraft/api/media/MediaLookup.java | 32 +++++++++++++++++++ .../impl/ComputerCraftAPIImpl.java | 7 ++++ .../shared/platform/PlatformHelperImpl.java | 8 +++++ .../impl/ComputerCraftAPIImpl.java | 6 ++++ .../computercraft/impl/MediaProviders.java | 0 .../shared/platform/PlatformHelperImpl.java | 7 ++++ 11 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 projects/fabric-api/src/main/java/dan200/computercraft/api/media/MediaLookup.java rename projects/{common => forge}/src/main/java/dan200/computercraft/impl/MediaProviders.java (100%) diff --git a/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java b/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java index adff3e6f8..eb5c07737 100644 --- a/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java +++ b/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java @@ -11,7 +11,6 @@ import dan200.computercraft.api.filesystem.Mount; import dan200.computercraft.api.filesystem.WritableMount; import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.ILuaAPIFactory; -import dan200.computercraft.api.media.MediaProvider; import dan200.computercraft.api.media.PrintoutContents; import dan200.computercraft.api.network.PacketNetwork; import dan200.computercraft.api.network.wired.WiredElement; @@ -93,11 +92,6 @@ public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIServic return BundledRedstone.getDefaultOutput(world, pos, side); } - @Override - public final void registerMediaProvider(MediaProvider provider) { - MediaProviders.register(provider); - } - @Override public final PacketNetwork getWirelessNetwork(MinecraftServer server) { return ServerContext.get(server).wirelessNetwork(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java index bc550ec2f..1a63c9a25 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveBlock.java @@ -4,9 +4,9 @@ package dan200.computercraft.shared.peripheral.diskdrive; -import dan200.computercraft.impl.MediaProviders; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.common.HorizontalContainerBlock; +import dan200.computercraft.shared.platform.PlatformHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.InteractionHand; @@ -50,7 +50,7 @@ public class DiskDriveBlock extends HorizontalContainerBlock { var disk = player.getItemInHand(hand); if (disk.isEmpty()) return InteractionResult.PASS; - if (!level.isClientSide && drive.getDiskStack().isEmpty() && MediaProviders.get(disk) != null) { + if (!level.isClientSide && drive.getDiskStack().isEmpty() && PlatformHelper.get().getMedia(disk) != null) { drive.setDiskStack(disk.split(1)); } return InteractionResult.sidedSuccess(level.isClientSide); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/MediaStack.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/MediaStack.java index 7a1390bc1..413921133 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/MediaStack.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/MediaStack.java @@ -5,7 +5,7 @@ package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.api.media.IMedia; -import dan200.computercraft.impl.MediaProviders; +import dan200.computercraft.shared.platform.PlatformHelper; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.item.ItemStack; import org.jspecify.annotations.Nullable; @@ -23,7 +23,7 @@ record MediaStack(ItemStack stack, @Nullable IMedia media) { if (stack.isEmpty()) return EMPTY; var freshStack = stack.copy(); - return new MediaStack(freshStack, MediaProviders.get(freshStack)); + return new MediaStack(freshStack, PlatformHelper.get().getMedia(freshStack)); } @Nullable diff --git a/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java b/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java index 156c16ff1..8882e9685 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.platform; import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.arguments.ArgumentType; +import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.config.ConfigFile; @@ -424,4 +425,13 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper default boolean canClickRunClientCommand() { return true; } + + /** + * Find a {@link IMedia} instance for an item stack. + * + * @param stack The stack to look up the media for. + * @return The media instance, or {@code null} if not found. + */ + @Nullable + IMedia getMedia(ItemStack stack); } diff --git a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java index 1589b235b..a2746842d 100644 --- a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java +++ b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java @@ -8,6 +8,8 @@ import com.google.auto.service.AutoService; import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.arguments.ArgumentType; +import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.api.media.MediaProvider; import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.impl.AbstractComputerCraftAPI; @@ -227,6 +229,11 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat throw new UnsupportedOperationException("Cannot interact with the world inside tests"); } + @Override + public @Nullable IMedia getMedia(ItemStack stack) { + return null; + } + @Override public ContainerTransfer.Slotted wrapContainer(Container container) { throw new UnsupportedOperationException("Cannot wrap container"); @@ -248,6 +255,11 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat throw new UnsupportedOperationException("Cannot interact with the world inside tests"); } + @Override + public void registerMediaProvider(MediaProvider provider) { + throw new UnsupportedOperationException("Cannot register media providers inside tests"); + } + @Override public String getInstalledVersion() { return "1.0"; diff --git a/projects/fabric-api/src/main/java/dan200/computercraft/api/media/MediaLookup.java b/projects/fabric-api/src/main/java/dan200/computercraft/api/media/MediaLookup.java new file mode 100644 index 000000000..0692744d9 --- /dev/null +++ b/projects/fabric-api/src/main/java/dan200/computercraft/api/media/MediaLookup.java @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.api.media; + +import dan200.computercraft.api.ComputerCraftAPI; +import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jspecify.annotations.Nullable; + +/** + * {@linkplain ItemApiLookup Item API lookup} for {@link IMedia}. + *

+ * The returned {@link IMedia} instance should be a singleton, and not reference the passed {@link ItemStack}. + *

+ * Registering a {@link MediaProvider} via {@link ComputerCraftAPI#registerMediaProvider(MediaProvider)} is equivalent + * to registering a {@linkplain ItemApiLookup#registerFallback(ItemApiLookup.ItemApiProvider) fallback provider}. + */ +public final class MediaLookup { + public static final ResourceLocation ID = new ResourceLocation(ComputerCraftAPI.MOD_ID, "media"); + + private static final ItemApiLookup lookup = ItemApiLookup.get(ID, IMedia.class, Void.class); + + private MediaLookup() { + } + + public static ItemApiLookup get() { + return lookup; + } +} diff --git a/projects/fabric/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java b/projects/fabric/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java index a14d95b76..5ca91d430 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java +++ b/projects/fabric/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java @@ -7,6 +7,8 @@ package dan200.computercraft.impl; import com.google.auto.service.AutoService; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.detail.DetailRegistry; +import dan200.computercraft.api.media.MediaLookup; +import dan200.computercraft.api.media.MediaProvider; import dan200.computercraft.impl.detail.DetailRegistryImpl; import dan200.computercraft.shared.details.FluidDetails; import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; @@ -41,4 +43,9 @@ public final class ComputerCraftAPIImpl extends AbstractComputerCraftAPI impleme public DetailRegistry> getFluidDetailRegistry() { return fluidDetails; } + + @Override + public void registerMediaProvider(MediaProvider provider) { + MediaLookup.get().registerFallback((stack, ctx) -> provider.getMedia(stack)); + } } diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java index 802b069cd..44348e609 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java @@ -10,6 +10,8 @@ import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.arguments.ArgumentType; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.api.media.MediaLookup; import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.node.wired.WiredElementLookup; import dan200.computercraft.api.peripheral.IPeripheral; @@ -317,6 +319,12 @@ public class PlatformHelperImpl implements PlatformHelper { return new UseOnResult.Continue(true, true); } + @Override + @SuppressWarnings("NullAway") // NullAway doesn't like the null here. + public @Nullable IMedia getMedia(ItemStack stack) { + return MediaLookup.get().find(stack, null); + } + private record RegistryWrapperImpl( ResourceLocation name, Registry registry ) implements RegistryWrappers.RegistryWrapper { diff --git a/projects/forge/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java b/projects/forge/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java index f493a52a0..e2905f089 100644 --- a/projects/forge/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java +++ b/projects/forge/src/main/java/dan200/computercraft/impl/ComputerCraftAPIImpl.java @@ -7,6 +7,7 @@ package dan200.computercraft.impl; import com.google.auto.service.AutoService; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.detail.DetailRegistry; +import dan200.computercraft.api.media.MediaProvider; import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.impl.detail.DetailRegistryImpl; @@ -56,4 +57,9 @@ public final class ComputerCraftAPIImpl extends AbstractComputerCraftAPI impleme public DetailRegistry getFluidStackDetailRegistry() { return fluidStackDetails; } + + @Override + public void registerMediaProvider(MediaProvider provider) { + MediaProviders.register(provider); + } } diff --git a/projects/common/src/main/java/dan200/computercraft/impl/MediaProviders.java b/projects/forge/src/main/java/dan200/computercraft/impl/MediaProviders.java similarity index 100% rename from projects/common/src/main/java/dan200/computercraft/impl/MediaProviders.java rename to projects/forge/src/main/java/dan200/computercraft/impl/MediaProviders.java diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java index e58d4a385..d76c2eb7c 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java @@ -10,8 +10,10 @@ import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.arguments.ArgumentType; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.network.wired.WiredElement; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.impl.MediaProviders; import dan200.computercraft.impl.Peripherals; import dan200.computercraft.shared.Capabilities; import dan200.computercraft.shared.config.ConfigFile; @@ -348,6 +350,11 @@ public class PlatformHelperImpl implements PlatformHelper { return false; } + @Override + public @Nullable IMedia getMedia(ItemStack stack) { + return MediaProviders.get(stack); + } + private record RegistryWrapperImpl( ResourceLocation name, ForgeRegistry registry ) implements RegistryWrappers.RegistryWrapper {