1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-07-17 17:32:55 +00:00

Remove IMedia implementations from our items

We now register these separately, rather than relying on the implicit
IMedia. This allows us to share a bit more logic between
PocketComputerItem and AbstractComputerItem. This doesn't make much
difference on 1.20.1, but does help a bit more on 1.21.1.
This commit is contained in:
Jonathan Coates 2025-02-16 20:29:20 +00:00
parent 01fe949b3e
commit 32f5c38485
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
11 changed files with 241 additions and 147 deletions

View File

@ -45,11 +45,9 @@ import dan200.computercraft.shared.details.ItemDetails;
import dan200.computercraft.shared.integration.PermissionRegistry; import dan200.computercraft.shared.integration.PermissionRegistry;
import dan200.computercraft.shared.lectern.CustomLecternBlock; import dan200.computercraft.shared.lectern.CustomLecternBlock;
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity; import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
import dan200.computercraft.shared.media.MountMedia;
import dan200.computercraft.shared.media.PrintoutMenu; import dan200.computercraft.shared.media.PrintoutMenu;
import dan200.computercraft.shared.media.items.DiskItem; import dan200.computercraft.shared.media.items.*;
import dan200.computercraft.shared.media.items.PrintoutItem;
import dan200.computercraft.shared.media.items.RecordMedia;
import dan200.computercraft.shared.media.items.TreasureDiskItem;
import dan200.computercraft.shared.media.recipes.DiskRecipe; import dan200.computercraft.shared.media.recipes.DiskRecipe;
import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.media.recipes.PrintoutRecipe;
import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ComputerContainerData;
@ -107,6 +105,7 @@ import net.minecraft.world.item.*;
import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -467,12 +466,6 @@ public final class ModRegistry {
// Register bundled power providers // Register bundled power providers
ComputerCraftAPI.registerBundledRedstoneProvider(new DefaultBundledRedstoneProvider()); ComputerCraftAPI.registerBundledRedstoneProvider(new DefaultBundledRedstoneProvider());
ComputerCraftAPI.registerRefuelHandler(new FurnaceRefuelHandler()); ComputerCraftAPI.registerRefuelHandler(new FurnaceRefuelHandler());
ComputerCraftAPI.registerMediaProvider(stack -> {
var item = stack.getItem();
if (item instanceof IMedia media) return media;
if (item instanceof RecordItem) return RecordMedia.INSTANCE;
return null;
});
ComputerCraftAPI.registerAPIFactory(computer -> { ComputerCraftAPI.registerAPIFactory(computer -> {
var turtle = computer.getComponent(ComputerComponents.TURTLE); var turtle = computer.getComponent(ComputerComponents.TURTLE);
@ -531,6 +524,26 @@ public final class ModRegistry {
wiredElements.registerForBlockEntity(ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getWiredElement); wiredElements.registerForBlockEntity(ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getWiredElement);
} }
/**
* Register our custom {@link IMedia} implementations.
*
* @param media The object to register our media capabilities/lookups with.
*/
public static void registerMedia(ItemComponent<IMedia> media) {
media.registerForItems((s, c) -> MountMedia.COMPUTER,
ModRegistry.Items.COMPUTER_NORMAL.get(), ModRegistry.Items.COMPUTER_ADVANCED.get(),
ModRegistry.Items.TURTLE_NORMAL.get(), ModRegistry.Items.TURTLE_ADVANCED.get(),
ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get()
);
media.registerForItems((s, c) -> MountMedia.DISK, ModRegistry.Items.DISK.get());
media.registerForItems((s, c) -> TreasureDiskMedia.INSTANCE, ModRegistry.Items.TREASURE_DISK.get());
media.registerFallback((stack, ctx) -> {
if (stack.getItem() instanceof IMedia m) return m;
if (stack.getItem() instanceof RecordItem) return RecordMedia.INSTANCE;
return null;
});
}
/** /**
* An abstraction for registering capabilities/block lookups for blocks and block entities. * An abstraction for registering capabilities/block lookups for blocks and block entities.
* *
@ -541,6 +554,17 @@ public final class ModRegistry {
<B extends BlockEntity> void registerForBlockEntity(BlockEntityType<B> blockEntityType, BiFunction<? super B, C, @Nullable T> provider); <B extends BlockEntity> void registerForBlockEntity(BlockEntityType<B> blockEntityType, BiFunction<? super B, C, @Nullable T> provider);
} }
/**
* An abstraction for registering capabilities/block lookups for items.
*
* @param <T> The type of the component.
*/
public interface ItemComponent<T> {
void registerForItems(BiFunction<ItemStack, @Nullable Void, @Nullable T> provider, ItemLike... items);
void registerFallback(BiFunction<ItemStack, @Nullable Void, @Nullable T> provider);
}
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) { private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
out.accept(turtle.create(-1, null, -1, null, null, 0, null)); out.accept(turtle.create(-1, null, -1, null, null, 0, null));
TurtleUpgrades.getVanillaUpgrades() TurtleUpgrades.getVanillaUpgrades()

View File

@ -4,14 +4,9 @@
package dan200.computercraft.shared.computer.items; package dan200.computercraft.shared.computer.items;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlock; import dan200.computercraft.shared.computer.blocks.AbstractComputerBlock;
import dan200.computercraft.shared.config.Config;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.TooltipFlag;
@ -20,7 +15,7 @@ import org.jspecify.annotations.Nullable;
import java.util.List; import java.util.List;
public abstract class AbstractComputerItem extends BlockItem implements IComputerItem, IMedia { public abstract class AbstractComputerItem extends BlockItem implements IComputerItem {
public AbstractComputerItem(AbstractComputerBlock<?> block, Properties settings) { public AbstractComputerItem(AbstractComputerBlock<?> block, Properties settings) {
super(block, settings); super(block, settings);
} }
@ -40,20 +35,4 @@ public abstract class AbstractComputerItem extends BlockItem implements ICompute
public @Nullable String getLabel(ItemStack stack) { public @Nullable String getLabel(ItemStack stack) {
return IComputerItem.super.getLabel(stack); return IComputerItem.super.getLabel(stack);
} }
@Override
public boolean setLabel(ItemStack stack, @Nullable String label) {
if (label != null) {
stack.setHoverName(Component.literal(label));
} else {
stack.resetHoverName();
}
return true;
}
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
var id = getComputerID(stack);
return id >= 0 ? ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id, Config.computerSpaceLimit) : null;
}
} }

View File

@ -4,10 +4,7 @@
package dan200.computercraft.shared.computer.items; package dan200.computercraft.shared.computer.items;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.shared.computer.blocks.ComputerBlock; import dan200.computercraft.shared.computer.blocks.ComputerBlock;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
@ -29,10 +26,4 @@ public class CommandComputerItem extends ComputerItem {
var player = context.getPlayer(); var player = context.getPlayer();
return player != null && !player.canUseGameMasterBlocks() ? null : super.getPlacementState(context); return player != null && !player.canUseGameMasterBlocks() ? null : super.getPlacementState(context);
} }
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
// Don't allow command computers to be mounted in disk drives.
return null;
}
} }

View File

@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.media;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
import dan200.computercraft.shared.computer.items.IComputerItem;
import dan200.computercraft.shared.config.ConfigSpec;
import dan200.computercraft.shared.media.items.DiskItem;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nullable;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
/**
* Media that provides a {@link Mount}.
*/
public final class MountMedia implements IMedia {
/**
* A {@link MountMedia} implementation for {@linkplain AbstractComputerItem computers}.
*/
public static final IMedia COMPUTER = new MountMedia(
"computer", s -> ((IComputerItem) s.getItem()).getComputerID(s), null, ConfigSpec.computerSpaceLimit
);
/**
* A {@link MountMedia} implementation for {@linkplain DiskItem disks}.
*/
public static final IMedia DISK = new MountMedia("disk", DiskItem::getDiskID, DiskItem::setDiskID, ConfigSpec.floppySpaceLimit);
private final String subPath;
private final ToIntFunction<ItemStack> getId;
private final @Nullable IdSetter setId;
private final Supplier<Integer> defaultCapacity;
/**
* Create a new {@link MountMedia}.
*
* @param subPath The sub-path to expose the mount under, for instance {@code "computer"}.
* @param getId A function to get the item's ID.
* @param setId A function to set the item's ID. If not present, then mounts will not be created when the
* item is placed in a drive.
* @param defaultCapacity A function to get the default capacity of the stack.
*/
public MountMedia(
String subPath,
ToIntFunction<ItemStack> getId,
@Nullable IdSetter setId,
Supplier<Integer> defaultCapacity
) {
this.subPath = subPath;
this.getId = getId;
this.setId = setId;
this.defaultCapacity = defaultCapacity;
}
@Override
public @Nullable String getLabel(ItemStack stack) {
return stack.hasCustomHoverName() ? stack.getHoverName().getString() : null;
}
@Override
public boolean setLabel(ItemStack stack, @Nullable String label) {
if (label != null) {
stack.setHoverName(Component.literal(label));
} else {
stack.resetHoverName();
}
return true;
}
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
var id = getId.applyAsInt(stack);
if (id < 0) {
if (setId == null) return null;
id = ComputerCraftAPI.createUniqueNumberedSaveDir(level.getServer(), subPath);
setId.set(stack, id);
}
return ComputerCraftAPI.createSaveDirMount(level.getServer(), subPath + "/" + id, defaultCapacity.get());
}
public interface IdSetter {
void set(ItemStack stack, int id);
}
}

View File

@ -5,17 +5,12 @@
package dan200.computercraft.shared.media.items; package dan200.computercraft.shared.media.items;
import dan200.computercraft.annotations.ForgeOverride; import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.core.util.Colour; import dan200.computercraft.core.util.Colour;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.config.Config;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -26,7 +21,7 @@ import org.jspecify.annotations.Nullable;
import java.util.List; import java.util.List;
public class DiskItem extends Item implements IMedia, IColouredItem { public class DiskItem extends Item implements IColouredItem {
private static final String NBT_ID = "DiskId"; private static final String NBT_ID = "DiskId";
public DiskItem(Properties settings) { public DiskItem(Properties settings) {
@ -36,7 +31,7 @@ public class DiskItem extends Item implements IMedia, IColouredItem {
public static ItemStack createFromIDAndColour(int id, @Nullable String label, int colour) { public static ItemStack createFromIDAndColour(int id, @Nullable String label, int colour) {
var stack = new ItemStack(ModRegistry.Items.DISK.get()); var stack = new ItemStack(ModRegistry.Items.DISK.get());
setDiskID(stack, id); setDiskID(stack, id);
ModRegistry.Items.DISK.get().setLabel(stack, label); if (label != null) stack.setHoverName(Component.literal(label));
IColouredItem.setColourBasic(stack, colour); IColouredItem.setColourBasic(stack, colour);
return stack; return stack;
} }
@ -57,37 +52,12 @@ public class DiskItem extends Item implements IMedia, IColouredItem {
return true; return true;
} }
@Override
public @Nullable String getLabel(ItemStack stack) {
return stack.hasCustomHoverName() ? stack.getHoverName().getString() : null;
}
@Override
public boolean setLabel(ItemStack stack, @Nullable String label) {
if (label != null) {
stack.setHoverName(Component.literal(label));
} else {
stack.resetHoverName();
}
return true;
}
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
var diskID = getDiskID(stack);
if (diskID < 0) {
diskID = ComputerCraftAPI.createUniqueNumberedSaveDir(level.getServer(), "disk");
setDiskID(stack, diskID);
}
return ComputerCraftAPI.createSaveDirMount(level.getServer(), "disk/" + diskID, Config.floppySpaceLimit);
}
public static int getDiskID(ItemStack stack) { public static int getDiskID(ItemStack stack) {
var nbt = stack.getTag(); var nbt = stack.getTag();
return nbt != null && nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1; return nbt != null && nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
} }
private static void setDiskID(ItemStack stack, int id) { public static void setDiskID(ItemStack stack, int id) {
if (id >= 0) stack.getOrCreateTag().putInt(NBT_ID, id); if (id >= 0) stack.getOrCreateTag().putInt(NBT_ID, id);
} }

View File

@ -5,15 +5,10 @@
package dan200.computercraft.shared.media.items; package dan200.computercraft.shared.media.items;
import dan200.computercraft.annotations.ForgeOverride; import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.core.filesystem.SubMount;
import dan200.computercraft.core.util.Colour; import dan200.computercraft.core.util.Colour;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -22,10 +17,9 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LevelReader;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.io.IOException;
import java.util.List; import java.util.List;
public class TreasureDiskItem extends Item implements IMedia { public class TreasureDiskItem extends Item {
private static final String NBT_TITLE = "Title"; private static final String NBT_TITLE = "Title";
private static final String NBT_COLOUR = "Colour"; private static final String NBT_COLOUR = "Colour";
private static final String NBT_SUB_PATH = "SubPath"; private static final String NBT_SUB_PATH = "SubPath";
@ -45,30 +39,6 @@ public class TreasureDiskItem extends Item implements IMedia {
return true; return true;
} }
@Override
public String getLabel(ItemStack stack) {
return getTitle(stack);
}
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
var rootTreasure = ComputerCraftAPI.createResourceMount(level.getServer(), "computercraft", "lua/treasure");
if (rootTreasure == null) return null;
var subPath = getSubPath(stack);
try {
if (rootTreasure.exists(subPath)) {
return new SubMount(rootTreasure, subPath);
} else if (rootTreasure.exists("deprecated/" + subPath)) {
return new SubMount(rootTreasure, "deprecated/" + subPath);
} else {
return null;
}
} catch (IOException e) {
return null;
}
}
public static ItemStack create(String subPath, int colourIndex) { public static ItemStack create(String subPath, int colourIndex) {
var result = new ItemStack(ModRegistry.Items.TREASURE_DISK.get()); var result = new ItemStack(ModRegistry.Items.TREASURE_DISK.get());
var nbt = result.getOrCreateTag(); var nbt = result.getOrCreateTag();
@ -87,12 +57,12 @@ public class TreasureDiskItem extends Item implements IMedia {
return result; return result;
} }
private static String getTitle(ItemStack stack) { static String getTitle(ItemStack stack) {
var nbt = stack.getTag(); var nbt = stack.getTag();
return nbt != null && nbt.contains(NBT_TITLE) ? nbt.getString(NBT_TITLE) : "'missingno' by how did you get this anyway?"; return nbt != null && nbt.contains(NBT_TITLE) ? nbt.getString(NBT_TITLE) : "'missingno' by how did you get this anyway?";
} }
private static String getSubPath(ItemStack stack) { static String getSubPath(ItemStack stack) {
var nbt = stack.getTag(); var nbt = stack.getTag();
return nbt != null && nbt.contains(NBT_SUB_PATH) ? nbt.getString(NBT_SUB_PATH) : "dan200/alongtimeago"; return nbt != null && nbt.contains(NBT_SUB_PATH) ? nbt.getString(NBT_SUB_PATH) : "dan200/alongtimeago";
} }

View File

@ -0,0 +1,49 @@
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
//
// SPDX-License-Identifier: LicenseRef-CCPL
package dan200.computercraft.shared.media.items;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.core.filesystem.SubMount;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nullable;
import java.io.IOException;
/**
* An {@link IMedia} instance for {@linkplain TreasureDiskItem treasure disks}.
*/
public final class TreasureDiskMedia implements IMedia {
public static final IMedia INSTANCE = new TreasureDiskMedia();
private TreasureDiskMedia() {
}
@Override
public String getLabel(ItemStack stack) {
return TreasureDiskItem.getTitle(stack);
}
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
var rootTreasure = ComputerCraftAPI.createResourceMount(level.getServer(), "computercraft", "lua/treasure");
if (rootTreasure == null) return null;
var subPath = TreasureDiskItem.getSubPath(stack);
try {
if (rootTreasure.exists(subPath)) {
return new SubMount(rootTreasure, subPath);
} else if (rootTreasure.exists("deprecated/" + subPath)) {
return new SubMount(rootTreasure, "deprecated/" + subPath);
} else {
return null;
}
} catch (IOException e) {
return null;
}
}
}

View File

@ -6,8 +6,6 @@ package dan200.computercraft.shared.pocket.items;
import dan200.computercraft.annotations.ForgeOverride; import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.api.upgrades.UpgradeData;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
@ -20,7 +18,6 @@ import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
import dan200.computercraft.shared.computer.core.ServerContext; import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.computer.items.IComputerItem;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.lectern.CustomLecternBlock; import dan200.computercraft.shared.lectern.CustomLecternBlock;
import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ComputerContainerData;
import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.platform.PlatformHelper;
@ -53,7 +50,7 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class PocketComputerItem extends Item implements IComputerItem, IMedia, IColouredItem { public class PocketComputerItem extends Item implements IComputerItem, IColouredItem {
private static final String NBT_UPGRADE = "Upgrade"; private static final String NBT_UPGRADE = "Upgrade";
private static final String NBT_UPGRADE_INFO = "UpgradeInfo"; private static final String NBT_UPGRADE_INFO = "UpgradeInfo";
public static final String NBT_ON = "On"; public static final String NBT_ON = "On";
@ -127,7 +124,11 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
var label = computer.getLabel(); var label = computer.getLabel();
if (!Objects.equals(label, getLabel(stack))) { if (!Objects.equals(label, getLabel(stack))) {
changed = true; changed = true;
setLabel(stack, label); if (label != null) {
stack.setHoverName(Component.literal(label));
} else {
stack.resetHoverName();
}
} }
var on = computer.isOn(); var on = computer.isOn();
@ -342,27 +343,6 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
) : ItemStack.EMPTY; ) : ItemStack.EMPTY;
} }
// IMedia
@Override
public boolean setLabel(ItemStack stack, @Nullable String label) {
if (label != null) {
stack.setHoverName(Component.literal(label));
} else {
stack.resetHoverName();
}
return true;
}
@Override
public @Nullable Mount createDataMount(ItemStack stack, ServerLevel level) {
var id = getComputerID(stack);
if (id >= 0) {
return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + id, Config.computerSpaceLimit);
}
return null;
}
public static @Nullable UUID getInstanceID(ItemStack stack) { public static @Nullable UUID getInstanceID(ItemStack stack) {
var nbt = stack.getTag(); var nbt = stack.getTag();
return nbt != null && nbt.hasUUID(NBT_INSTANCE) ? nbt.getUUID(NBT_INSTANCE) : null; return nbt != null && nbt.hasUUID(NBT_INSTANCE) ? nbt.getUUID(NBT_INSTANCE) : null;

View File

@ -6,6 +6,7 @@ package dan200.computercraft.shared;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.detail.FabricDetailRegistries; import dan200.computercraft.api.detail.FabricDetailRegistries;
import dan200.computercraft.api.media.MediaLookup;
import dan200.computercraft.api.node.wired.WiredElementLookup; import dan200.computercraft.api.node.wired.WiredElementLookup;
import dan200.computercraft.api.peripheral.PeripheralLookup; import dan200.computercraft.api.peripheral.PeripheralLookup;
import dan200.computercraft.impl.Peripherals; import dan200.computercraft.impl.Peripherals;
@ -27,6 +28,7 @@ import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup;
import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup;
import net.fabricmc.fabric.api.loot.v2.LootTableEvents; import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
@ -38,6 +40,8 @@ import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.LevelResource;
@ -62,6 +66,7 @@ public class ComputerCraft {
ModRegistry.registerPeripherals(new BlockComponentImpl<>(PeripheralLookup.get())); ModRegistry.registerPeripherals(new BlockComponentImpl<>(PeripheralLookup.get()));
ModRegistry.registerWiredElements(new BlockComponentImpl<>(WiredElementLookup.get())); ModRegistry.registerWiredElements(new BlockComponentImpl<>(WiredElementLookup.get()));
ModRegistry.registerMedia(new ItemComponentImpl<>(MediaLookup.get()));
// Register commands // Register commands
CommandRegistrationCallback.EVENT.register((dispatcher, context, environment) -> CommandComputerCraft.register(dispatcher)); CommandRegistrationCallback.EVENT.register((dispatcher, context, environment) -> CommandComputerCraft.register(dispatcher));
@ -127,4 +132,18 @@ public class ComputerCraft {
lookup.registerForBlockEntity(provider, blockEntityType); lookup.registerForBlockEntity(provider, blockEntityType);
} }
} }
private record ItemComponentImpl<T>(
ItemApiLookup<T, @Nullable Void> lookup
) implements ModRegistry.ItemComponent<T> {
@Override
public void registerForItems(BiFunction<ItemStack, @Nullable Void, @Nullable T> provider, ItemLike... items) {
lookup().registerForItems(provider::apply, items);
}
@Override
public void registerFallback(BiFunction<ItemStack, @Nullable Void, @Nullable T> provider) {
lookup().registerFallback(provider::apply);
}
}
} }

View File

@ -12,6 +12,7 @@ import dan200.computercraft.api.network.wired.WiredElement;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser; import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.impl.MediaProviders;
import dan200.computercraft.shared.CommonHooks; import dan200.computercraft.shared.CommonHooks;
import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.config.ConfigSpec;
@ -79,6 +80,8 @@ public final class ComputerCraft {
ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill); ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill);
MediaProviders.registerDefault();
if (ModList.get().isLoaded(CreateIntegration.ID)) event.enqueueWork(CreateIntegration::setup); if (ModList.get().isLoaded(CreateIntegration.ID)) event.enqueueWork(CreateIntegration::setup);
if (ModList.get().isLoaded(MoreRedIntegration.MOD_ID)) MoreRedIntegration.setup(); if (ModList.get().isLoaded(MoreRedIntegration.MOD_ID)) MoreRedIntegration.setup();
} }

View File

@ -6,18 +6,17 @@ package dan200.computercraft.impl;
import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.MediaProvider; import dan200.computercraft.api.media.MediaProvider;
import dan200.computercraft.shared.ModRegistry;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedHashSet; import java.util.*;
import java.util.Objects; import java.util.function.BiFunction;
import java.util.Set;
public final class MediaProviders { public final class MediaProviders {
private static final Logger LOG = LoggerFactory.getLogger(MediaProviders.class); private static final Map<Item, MediaProvider> itemProviders = new HashMap<>();
private static final Set<MediaProvider> providers = new LinkedHashSet<>(); private static final Set<MediaProvider> providers = new LinkedHashSet<>();
private MediaProviders() { private MediaProviders() {
@ -31,16 +30,33 @@ public final class MediaProviders {
public static @Nullable IMedia get(ItemStack stack) { public static @Nullable IMedia get(ItemStack stack) {
if (stack.isEmpty()) return null; if (stack.isEmpty()) return null;
// Try the per-item provider first.
var itemProvider = itemProviders.get(stack.getItem());
if (itemProvider != null) {
var media = itemProvider.getMedia(stack);
if (media != null) return media;
}
// Try the handlers in order: // Try the handlers in order:
for (var mediaProvider : providers) { for (var mediaProvider : providers) {
try {
var media = mediaProvider.getMedia(stack); var media = mediaProvider.getMedia(stack);
if (media != null) return media; if (media != null) return media;
} catch (Exception e) {
// Mod misbehaved, ignore it
LOG.error("Media provider " + mediaProvider + " errored.", e);
}
} }
return null; return null;
} }
public static synchronized void registerDefault() {
ModRegistry.registerMedia(new ModRegistry.ItemComponent<>() {
@Override
public void registerForItems(BiFunction<ItemStack, @Nullable Void, @Nullable IMedia> provider, ItemLike... items) {
MediaProvider wrappedProvider = s -> provider.apply(s, null);
for (var item : items) itemProviders.put(item.asItem(), wrappedProvider);
}
@Override
public void registerFallback(BiFunction<ItemStack, @Nullable Void, @Nullable IMedia> provider) {
register(s -> provider.apply(s, null));
}
});
}
} }