diff --git a/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModeller.java b/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModeller.java index a1c710876..52fad7258 100644 --- a/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModeller.java +++ b/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModeller.java @@ -8,10 +8,12 @@ import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.api.upgrades.UpgradeData; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.Nullable; import java.util.Collection; @@ -42,7 +44,7 @@ public interface TurtleUpgradeModeller { * * @param upgrade The upgrade that you're getting the model for. * @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models, unless - * {@link #getModel(ITurtleUpgrade, CompoundTag, TurtleSide)} is overridden. + * {@link #getModel(UpgradeData, TurtleSide)} is overridden. * @param side Which side of the turtle (left or right) the upgrade resides on. * @return The model that you wish to be used to render your upgrade. */ @@ -57,11 +59,25 @@ public interface TurtleUpgradeModeller { * @param data Upgrade data instance for current turtle side. * @param side Which side of the turtle (left or right) the upgrade resides on. * @return The model that you wish to be used to render your upgrade. + * @deprecated Prefer {@link #getModel(UpgradeData, TurtleSide)}. */ - default TransformedModel getModel(T upgrade, CompoundTag data, TurtleSide side) { + @Deprecated + default TransformedModel getModel(T upgrade, @Unmodifiable CompoundTag data, TurtleSide side) { return getModel(upgrade, (ITurtleAccess) null, side); } + /** + * Obtain the model to be used when rendering a turtle peripheral. + *

+ * This is used when rendering the turtle's item model, and so no {@link ITurtleAccess} is available. + * + * @param upgrade The upgrade that you're getting the model for. + * @param side Which side of the turtle (left or right) the upgrade resides on. + * @return The model that you wish to be used to render your upgrade. + */ + default TransformedModel getModel(UpgradeData upgrade, TurtleSide side) { + return getModel(upgrade.upgrade(), upgrade.data(), side); + } /** * Get a list of models that this turtle modeller depends on. diff --git a/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModellers.java b/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModellers.java index 343a996f7..d718715a8 100644 --- a/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModellers.java +++ b/projects/common-api/src/client/java/dan200/computercraft/api/client/turtle/TurtleUpgradeModellers.java @@ -9,6 +9,7 @@ import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.impl.client.ClientPlatformHelper; import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; @@ -41,10 +42,16 @@ final class TurtleUpgradeModellers { } @Override + @Deprecated public TransformedModel getModel(ITurtleUpgrade upgrade, CompoundTag data, TurtleSide side) { return getModel(upgrade.getUpgradeItem(data), side); } + @Override + public TransformedModel getModel(UpgradeData upgrade, TurtleSide side) { + return getModel(upgrade.getUpgradeItem(), side); + } + private TransformedModel getModel(ItemStack stack, TurtleSide side) { var model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(stack); if (stack.hasFoil()) model = ClientPlatformHelper.get().createdFoiledModel(model); diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/projects/common-api/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index c168bd946..47ccf59a3 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -5,8 +5,10 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.upgrades.UpgradeBase; +import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; /** @@ -18,11 +20,21 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade { private final ResourceLocation id; private final String adjective; private final ItemStack stack; + private final Ingredient ingredient; protected AbstractPocketUpgrade(ResourceLocation id, String adjective, ItemStack stack) { this.id = id; this.adjective = adjective; this.stack = stack; + this.ingredient = Ingredient.of(stack); + } + + protected AbstractPocketUpgrade(ResourceLocation id, String adjective, Ingredient ingredient) { + this.id = id; + this.adjective = adjective; + var items = ingredient.getItems(); + this.stack = items.length == 0 ? ItemStack.EMPTY : items[0]; + this.ingredient = ingredient; } protected AbstractPocketUpgrade(ResourceLocation id, ItemStack stack) { @@ -43,4 +55,26 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade { public final ItemStack getCraftingItem() { return stack; } + + @Override + public final Ingredient getCraftingIngredient() { + return ingredient; + } + + public abstract static class StackAware extends AbstractPocketUpgrade { + protected StackAware(ResourceLocation id, String adjective, Ingredient ingredient) { + super(id, adjective, ingredient); + } + + @Override + @Deprecated + public final CompoundTag getUpgradeData(ItemStack stack) { + return super.getUpgradeData(stack); + } + + @Override + public boolean isItemSuitable(ItemStack stack) { + return true; + } + } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/projects/common-api/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index d61ce5d35..f3b16f8ce 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -7,6 +7,7 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeData; +import dan200.computercraft.api.upgrades.UpgradeHandle; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -90,8 +91,9 @@ public interface IPocketAccess { * @see #getUpgradeNBTData() * @see #setUpgrade(UpgradeData) */ - @Nullable - UpgradeData getUpgrade(); + @Nullable UpgradeData getUpgrade(); + + @Nullable UpgradeHandle getUpgradeHandle(); /** * Set the upgrade for this pocket computer, also updating the item stack. @@ -113,15 +115,30 @@ public interface IPocketAccess { * @see UpgradeBase#getUpgradeItem(CompoundTag) * @see UpgradeBase#getUpgradeData(ItemStack) * @see #getUpgrade() + * @deprecated Use {@link #getUpgradeHandle()} and {@link UpgradeHandle#getData()}. */ - CompoundTag getUpgradeNBTData(); + @Deprecated + default CompoundTag getUpgradeNBTData() { + var handle = getUpgradeHandle(); + return handle == null ? new CompoundTag() : handle.getData(); + } /** * Mark the upgrade-specific NBT as dirty. * * @see #getUpgradeNBTData() + * @deprecated Use {@link #getUpgradeHandle()} and {@link UpgradeHandle#setChanged()}. */ - void updateUpgradeNBTData(); + @Deprecated + default void updateUpgradeNBTData() { + var handle = getUpgradeHandle(); + if (handle == null) return; + + // Legacy behaviour: overwrite the item with the version based on the upgrade data. + handle.setItem(handle.getUpgrade().getUpgradeItem(handle.getData())); + + handle.setChanged(); + } /** * Remove the current peripheral and create a new one. diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/pocket/PocketUpgradeSerialiser.java b/projects/common-api/src/main/java/dan200/computercraft/api/pocket/PocketUpgradeSerialiser.java index 40619c0df..a44a93f66 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/pocket/PocketUpgradeSerialiser.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/pocket/PocketUpgradeSerialiser.java @@ -7,12 +7,14 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.impl.ComputerCraftAPIService; +import dan200.computercraft.impl.upgrades.SerialiserWithCraftingIngredient; import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.impl.upgrades.SimpleSerialiser; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer; import java.util.function.BiFunction; @@ -76,4 +78,24 @@ public interface PocketUpgradeSerialiser extends Upgra return new Impl(factory); } + + + /** + * Create an upgrade serialiser for a simple upgrade whose crafting item can be specified. + * + * @param factory Generate a new upgrade with a specific ID and crafting item. The returned upgrade's + * {@link UpgradeBase#getCraftingIngredient()} MUST equal the provided item. + * @param The type of the generated upgrade. + * @return The serialiser for this upgrade. + * @see #simple(Function) For upgrades whose crafting stack should not vary. + */ + static PocketUpgradeSerialiser simpleWithCustomIngredient(BiFunction factory) { + final class Impl extends SerialiserWithCraftingIngredient implements PocketUpgradeSerialiser { + private Impl(BiFunction factory) { + super(factory); + } + } + + return new Impl(factory); + } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java index bede70fa3..a23d7621c 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java @@ -5,8 +5,10 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.api.upgrades.UpgradeBase; +import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; /** @@ -19,12 +21,23 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade { private final TurtleUpgradeType type; private final String adjective; private final ItemStack stack; + private final Ingredient ingredient; protected AbstractTurtleUpgrade(ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack) { this.id = id; this.type = type; this.adjective = adjective; this.stack = stack; + this.ingredient = Ingredient.of(stack); + } + + protected AbstractTurtleUpgrade(ResourceLocation id, TurtleUpgradeType type, String adjective, Ingredient ingredient) { + this.id = id; + this.type = type; + this.adjective = adjective; + var items = ingredient.getItems(); + this.stack = items.length == 0 ? ItemStack.EMPTY : items[0]; + this.ingredient = ingredient; } protected AbstractTurtleUpgrade(ResourceLocation id, TurtleUpgradeType type, ItemStack stack) { @@ -50,4 +63,26 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade { public final ItemStack getCraftingItem() { return stack; } + + @Override + public final Ingredient getCraftingIngredient() { + return ingredient; + } + + public abstract static class StackAware extends AbstractTurtleUpgrade { + protected StackAware(ResourceLocation id, TurtleUpgradeType type, String adjective, Ingredient ingredient) { + super(id, type, adjective, ingredient); + } + + @Override + @Deprecated + public final CompoundTag getUpgradeData(ItemStack stack) { + return super.getUpgradeData(stack); + } + + @Override + public boolean isItemSuitable(ItemStack stack) { + return true; + } + } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 97e1a2d59..a10da0c42 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -8,13 +8,12 @@ import com.mojang.authlib.GameProfile; import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeData; +import dan200.computercraft.api.upgrades.UpgradeHandle; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.Container; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.Nullable; @@ -242,10 +241,9 @@ public interface ITurtleAccess { * @see #getUpgradeWithData(TurtleSide) * @see #setUpgradeWithData(TurtleSide, UpgradeData) */ - default @Nullable UpgradeData getUpgradeWithData(TurtleSide side) { - var upgrade = getUpgrade(side); - return upgrade == null ? null : UpgradeData.of(upgrade, getUpgradeNBTData(side)); - } + @Nullable UpgradeData getUpgradeWithData(TurtleSide side); + + @Nullable UpgradeHandle getUpgradeHandle(TurtleSide side); /** * Set the upgrade for a given side, resetting peripherals and clearing upgrade specific data. @@ -275,8 +273,7 @@ public interface ITurtleAccess { * @param side The side to get the peripheral from. * @return The peripheral created by the upgrade on the specified side of the turtle, {@code null} if none exists. */ - @Nullable - IPeripheral getPeripheral(TurtleSide side); + @Nullable IPeripheral getPeripheral(TurtleSide side); /** * Get an upgrade-specific NBT compound, which can be used to store arbitrary data. @@ -286,11 +283,12 @@ public interface ITurtleAccess { * * @param side The side to get the upgrade data for. * @return The upgrade-specific data. - * @see #updateUpgradeNBTData(TurtleSide) - * @see UpgradeBase#getUpgradeItem(CompoundTag) - * @see UpgradeBase#getUpgradeData(ItemStack) + * @deprecated Use {@link #getUpgradeHandle(TurtleSide)} and {@link UpgradeHandle#getData()}. */ - CompoundTag getUpgradeNBTData(TurtleSide side); + default CompoundTag getUpgradeNBTData(TurtleSide side) { + var handle = getUpgradeHandle(side); + return handle == null ? new CompoundTag() : handle.getData(); + } /** * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the @@ -298,6 +296,16 @@ public interface ITurtleAccess { * * @param side The side to mark dirty. * @see #updateUpgradeNBTData(TurtleSide) + * @deprecated Use {@link #getUpgradeHandle(TurtleSide)} and {@link UpgradeHandle#setChanged()}. */ - void updateUpgradeNBTData(TurtleSide side); + @Deprecated + default void updateUpgradeNBTData(TurtleSide side) { + var handle = getUpgradeHandle(side); + if (handle == null) return; + + // Legacy behaviour: overwrite the item with the version based on the upgrade data. + handle.setItem(handle.getUpgrade().getUpgradeItem(handle.getData())); + + handle.setChanged(); + } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeSerialiser.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeSerialiser.java index 809cbf1ba..af99404c0 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeSerialiser.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeSerialiser.java @@ -7,12 +7,14 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.api.upgrades.UpgradeBase; import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.impl.ComputerCraftAPIService; +import dan200.computercraft.impl.upgrades.SerialiserWithCraftingIngredient; import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.impl.upgrades.SimpleSerialiser; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer; @@ -80,4 +82,23 @@ public interface TurtleUpgradeSerialiser extends Upgra return new Impl(factory); } + + /** + * Create an upgrade serialiser for a simple upgrade whose crafting item can be specified. + * + * @param factory Generate a new upgrade with a specific ID and crafting item. The returned upgrade's + * {@link UpgradeBase#getCraftingIngredient()} MUST equal the provided ingredient. + * @param The type of the generated upgrade. + * @return The serialiser for this upgrade. + * @see #simple(Function) For upgrades whose crafting stack should not vary. + */ + static TurtleUpgradeSerialiser simpleWithCustomIngredient(BiFunction factory) { + final class Impl extends SerialiserWithCraftingIngredient implements TurtleUpgradeSerialiser { + private Impl(BiFunction factory) { + super(factory); + } + } + + return new Impl(factory); + } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeBase.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeBase.java index e5e48fd4f..519a00f61 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeBase.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeBase.java @@ -14,6 +14,7 @@ import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import java.util.Objects; @@ -51,9 +52,15 @@ public interface UpgradeBase { * is called. * * @return The item stack to craft with, or {@link ItemStack#EMPTY} if it cannot be crafted. + * @deprecated Prefer {@link #getCraftingIngredient()}. */ + @Deprecated ItemStack getCraftingItem(); + default Ingredient getCraftingIngredient() { + return Ingredient.of(getCraftingItem()); + } + /** * Returns the item stack representing a currently equipped turtle upgrade. *

@@ -86,6 +93,7 @@ public interface UpgradeBase { * {@link #getCraftingItem()}. * @return The upgrade data that should be set on the turtle or pocket computer. */ + @Deprecated default CompoundTag getUpgradeData(ItemStack stack) { return new CompoundTag(); } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeData.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeData.java index f4038fba5..531580861 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeData.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeData.java @@ -9,19 +9,49 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.Nullable; +import java.util.Objects; + /** * An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data. *

* IMPORTANT: The {@link #data()} in an upgrade data is often a reference to the original upgrade data. * Be careful to take a {@linkplain #copy() defensive copy} if you plan to use the data in this upgrade. * - * @param upgrade The current upgrade. - * @param data The upgrade's data. - * @param The type of upgrade, either {@link ITurtleUpgrade} or {@link IPocketUpgrade}. + * @param The type of upgrade, either {@link ITurtleUpgrade} or {@link IPocketUpgrade}. */ -public record UpgradeData(T upgrade, CompoundTag data) { +public final class UpgradeData { + private final T upgrade; + private final CompoundTag data; + private final @Nullable ItemStack stack; + + private UpgradeData(T upgrade, CompoundTag data, @Nullable ItemStack stack) { + this.upgrade = upgrade; + this.data = data; + this.stack = stack; + + if (stack != null) { + if (stack.getCount() != 1) throw new IllegalArgumentException("Stack must be of size 1"); + if (!upgrade.getCraftingIngredient().test(stack) || !upgrade.isItemSuitable(stack)) { + throw new IllegalArgumentException("Item is not suitable for this upgrade"); + } + } + } + + /** + * Create a new {@link UpgradeData} with an item and upgrade data. + * + * @param upgrade The current upgrade. + * @param data The upgrade's data. + * @deprecated Use {@link UpgradeData#of(UpgradeBase, ItemStack, CompoundTag)}. + */ + @Deprecated + public UpgradeData(T upgrade, @Unmodifiable CompoundTag data) { + this(upgrade, data, null); + } + /** * A utility method to construct a new {@link UpgradeData} instance. * @@ -29,11 +59,25 @@ public record UpgradeData(T upgrade, CompoundTag data) { * @param data The upgrade's data. * @param The type of upgrade. * @return The new {@link UpgradeData} instance. + * @deprecated Use {@link #of(UpgradeBase, ItemStack, CompoundTag)} */ - public static UpgradeData of(T upgrade, CompoundTag data) { + @Deprecated + public static UpgradeData of(T upgrade, @Unmodifiable CompoundTag data) { return new UpgradeData<>(upgrade, data); } + /** + * A utility method to construct a new {@link UpgradeData} instance. + * + * @param The type of upgrade. + * @param upgrade An upgrade. + * @param data The upgrade's data. + * @return The new {@link UpgradeData} instance. + */ + public static UpgradeData of(T upgrade, @Unmodifiable ItemStack stack, @Unmodifiable CompoundTag data) { + return new UpgradeData<>(upgrade, data, stack); + } + /** * Create an {@link UpgradeData} containing the default {@linkplain #data() data} for an upgrade. * @@ -42,7 +86,7 @@ public record UpgradeData(T upgrade, CompoundTag data) { * @return The default upgrade data. */ public static UpgradeData ofDefault(T upgrade) { - return of(upgrade, upgrade.getUpgradeData(upgrade.getCraftingItem())); + return of(upgrade, upgrade.getCraftingItem(), upgrade.getUpgradeData(upgrade.getCraftingItem())); } /** @@ -57,16 +101,23 @@ public record UpgradeData(T upgrade, CompoundTag data) { return upgrade == null ? null : upgrade.copy(); } + public T upgrade() { + return upgrade; + } + + public @Unmodifiable CompoundTag data() { + return data; + } + /** * Get the {@linkplain UpgradeBase#getUpgradeItem(CompoundTag) upgrade item} for this upgrade. *

- * This returns a defensive copy of the item, to prevent accidental mutation of the upgrade data or original - * {@linkplain UpgradeBase#getCraftingItem() upgrade stack}. + * This returns a defensive copy of the item, to prevent accidental mutation of the stack. * * @return This upgrade's item. */ public ItemStack getUpgradeItem() { - return upgrade.getUpgradeItem(data).copy(); + return (stack == null ? upgrade.getUpgradeItem(data) : stack).copy(); } /** @@ -76,6 +127,34 @@ public record UpgradeData(T upgrade, CompoundTag data) { * @return A copy of the current instance. */ public UpgradeData copy() { - return new UpgradeData<>(upgrade(), data().copy()); + return new UpgradeData<>(upgrade(), data().copy(), stack == null ? null : stack.copy()); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + return obj instanceof UpgradeData that && upgrade == that.upgrade && data.equals(that.data) && areStacksEqual(stack, that.stack); + } + + private static boolean areStacksEqual(@Nullable ItemStack left, @Nullable ItemStack right) { + if (left == null) return right == null; + return right != null && ItemStack.isSameItemSameTags(left, right); + } + + @Override + public int hashCode() { + var result = upgrade.hashCode(); + result = 31 * result + data.hashCode(); + result = 31 * result + hashStack(stack); + return result; + } + + private static int hashStack(@Nullable ItemStack stack) { + return stack == null ? 0 : stack.getItem().hashCode() * 31 + Objects.hash(stack.getTag()); + } + + @Override + public String toString() { + return "UpgradeData[upgrade=" + upgrade + ", data=" + data + ", stack=" + stack + "]"; } } diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java index a62f21f9f..1dc7216d6 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java @@ -8,6 +8,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.impl.PlatformHelper; +import dan200.computercraft.impl.upgrades.SerialiserWithCraftingIngredient; import dan200.computercraft.impl.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.impl.upgrades.SimpleSerialiser; import net.minecraft.Util; @@ -19,6 +20,7 @@ import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; +import net.minecraft.world.item.crafting.Ingredient; import org.jspecify.annotations.Nullable; import java.util.*; @@ -75,6 +77,10 @@ public abstract class UpgradeDataProvider simpleWithCustomItem(ResourceLocation id, R serialiser, Item item) { + if (serialiser instanceof SerialiserWithCraftingIngredient) { + return simpleWithCustomItem(id, serialiser, Ingredient.of(item)); + } + if (!(serialiser instanceof SerialiserWithCraftingItem)) { throw new IllegalStateException(serialiser + " must be a simpleWithCustomItem() serialiser."); } @@ -84,11 +90,35 @@ public abstract class UpgradeDataProvider simpleWithCustomItem(ResourceLocation id, R serialiser, Ingredient item) { + if (!(serialiser instanceof SerialiserWithCraftingIngredient)) { + throw new IllegalStateException(serialiser + " must be a simpleWithCustomIngredient() serialiser."); + } + + return new Upgrade<>(id, serialiser, s -> { + var itemJson = item.toJson(); + if (itemJson instanceof JsonObject obj && obj.size() == 1 && obj.has("item")) { + // Preserve compatibility with our previous format. + s.add("item", obj.get("item")); + } else { + s.add("item", itemJson); + } + }); + } + /** * Add all turtle or pocket computer upgrades. * *

Example

- * {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body} + * {@snippet class = com.example.examplemod.data.TurtleDataProvider region = body} * * @param addUpgrade A callback used to register an upgrade. */ diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeHandle.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeHandle.java new file mode 100644 index 000000000..7883b9003 --- /dev/null +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeHandle.java @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.api.upgrades; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; + +public interface UpgradeHandle { + T getUpgrade(); + + default UpgradeData getUpgradeWithData() { + return UpgradeData.of(getUpgrade(), getItem(), getData()); + } + + ItemStack getItem(); + + void setItem(ItemStack item); + + CompoundTag getData(); + + void setComponents(CompoundTag data); + + void setChanged(); + + void clear(); +} diff --git a/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingIngredient.java b/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingIngredient.java new file mode 100644 index 000000000..643748575 --- /dev/null +++ b/projects/common-api/src/main/java/dan200/computercraft/impl/upgrades/SerialiserWithCraftingIngredient.java @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.impl.upgrades; + +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import dan200.computercraft.api.upgrades.UpgradeBase; +import dan200.computercraft.api.upgrades.UpgradeSerialiser; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.item.crafting.Ingredient; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.BiFunction; + +/** + * Simple serialiser which returns a constant upgrade with a custom crafting item. + *

+ * Do NOT directly reference this class. It exists for internal use by the API. + * + * @param The upgrade that this class can serialise and deserialise. + */ +@ApiStatus.Internal +public abstract class SerialiserWithCraftingIngredient implements UpgradeSerialiser { + private final BiFunction factory; + + protected SerialiserWithCraftingIngredient(BiFunction factory) { + this.factory = factory; + } + + @Override + public final T fromJson(ResourceLocation id, JsonObject object) { + return factory.apply(id, getIngredientOrItem(object, "item")); + } + + @Override + public final T fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { + return factory.apply(id, Ingredient.fromNetwork(buffer)); + } + + @Override + public final void toNetwork(FriendlyByteBuf buffer, T upgrade) { + upgrade.getCraftingIngredient().toNetwork(buffer); + } + + public static Ingredient getIngredientOrItem(JsonObject object, String key) { + return object.get(key) instanceof JsonPrimitive p && p.isString() + ? Ingredient.of(GsonHelper.getAsItem(object, key)) + : Ingredient.fromJson(GsonHelper.getAsJsonObject(object, key)); + } +} diff --git a/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java b/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java index 55016d398..6b30e31ec 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java +++ b/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java @@ -194,7 +194,7 @@ public final class ClientRegistry { var upgrade = item.getUpgradeWithData(stack, side); if (upgrade == null) return -1; - var model = TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side); + var model = TurtleUpgradeModellers.getModel(upgrade, side); return model.getTint((layer - 1) / 2); } diff --git a/projects/common/src/client/java/dan200/computercraft/client/model/turtle/TurtleModelParts.java b/projects/common/src/client/java/dan200/computercraft/client/model/turtle/TurtleModelParts.java index 0e6aae393..5b5ad3f1a 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/model/turtle/TurtleModelParts.java +++ b/projects/common/src/client/java/dan200/computercraft/client/model/turtle/TurtleModelParts.java @@ -147,7 +147,7 @@ public final class TurtleModelParts { private void addUpgrade(List parts, Transformation transformation, TurtleSide side, @Nullable UpgradeData upgrade) { if (upgrade == null) return; - var model = TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side); + var model = TurtleUpgradeModellers.getModel(upgrade, side); parts.add(transform(model.getModel(), transformation.compose(model.getMatrix()), side)); } diff --git a/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleModemModeller.java b/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleModemModeller.java index 1a9a1356d..da053e2c2 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleModemModeller.java +++ b/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleModemModeller.java @@ -41,17 +41,22 @@ public class TurtleModemModeller implements TurtleUpgradeModeller { @Override public TransformedModel getModel(TurtleModem upgrade, @Nullable ITurtleAccess turtle, TurtleSide side) { - var active = false; - if (turtle != null) { - var turtleNBT = turtle.getUpgradeNBTData(side); - active = turtleNBT.contains("active") && turtleNBT.getBoolean("active"); - } - + var active = isActive(turtle, side); return side == TurtleSide.LEFT ? TransformedModel.of(active ? leftOnModel : leftOffModel) : TransformedModel.of(active ? rightOnModel : rightOffModel); } + private static boolean isActive(@Nullable ITurtleAccess turtle, TurtleSide side) { + if (turtle == null) return false; + + var handle = turtle.getUpgradeHandle(side); + if (handle == null) return false; + + var data = handle.getData(); + return data.contains("active") && data.getBoolean("active"); + } + @Override public Collection getDependencies() { return List.of(leftOffModel, rightOffModel, leftOnModel, rightOnModel); diff --git a/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleUpgradeModellers.java b/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleUpgradeModellers.java index 7bff349a2..1186eb64f 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleUpgradeModellers.java +++ b/projects/common/src/client/java/dan200/computercraft/client/turtle/TurtleUpgradeModellers.java @@ -11,11 +11,11 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; +import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.impl.PlatformHelper; import dan200.computercraft.impl.TurtleUpgrades; import dan200.computercraft.impl.UpgradeManager; import net.minecraft.client.Minecraft; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,10 +70,10 @@ public final class TurtleUpgradeModellers { return modeller.getModel(upgrade, access, side); } - public static TransformedModel getModel(ITurtleUpgrade upgrade, CompoundTag data, TurtleSide side) { + public static TransformedModel getModel(UpgradeData upgrade, TurtleSide side) { @SuppressWarnings("unchecked") - var modeller = (TurtleUpgradeModeller) modelCache.computeIfAbsent(upgrade, TurtleUpgradeModellers::getModeller); - return modeller.getModel(upgrade, data, side); + var modeller = (TurtleUpgradeModeller) modelCache.computeIfAbsent(upgrade.upgrade(), TurtleUpgradeModellers::getModeller); + return modeller.getModel(upgrade, side); } private static TurtleUpgradeModeller getModeller(ITurtleUpgrade upgradeA) { diff --git a/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java b/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java index f30eef784..289782a93 100644 --- a/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java +++ b/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java @@ -19,8 +19,6 @@ import net.minecraft.DetectedVersion; import net.minecraft.client.renderer.texture.atlas.SpriteSource; import net.minecraft.client.renderer.texture.atlas.SpriteSources; import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.data.metadata.PackMetadataGenerator; @@ -29,10 +27,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.metadata.pack.PackMetadataSection; -import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.ShulkerBoxBlock; import java.util.Arrays; import java.util.List; @@ -99,20 +95,11 @@ public final class DataProviders { shulkerPack.add(out -> new TurtleUpgradeDataProvider(out) { @Override protected void addUpgrades(Consumer>> addUpgrade) { - for (var item : BuiltInRegistries.ITEM) { - if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof ShulkerBoxBlock) { - // Shuffle the name about, so blue_shulker_box becomes shulker/blue. This is a bit of a hack to - // ensure they're all grouped together in the creative tab. - var name = PlatformHelper.get().getRegistryKey(Registries.ITEM, item).getPath(); - if (name.endsWith("shulker_box")) { - name = name.substring(0, name.length() - "shulker_box".length()); - } - if (name.endsWith("_")) name = name.substring(0, name.length() - 1); - - var id = new ResourceLocation(ComputerCraftAPI.MOD_ID, name.isEmpty() ? "shulker" : "shulker/" + name); - simpleWithCustomItem(id, ModRegistry.TurtleSerialisers.STORAGE.get(), item).add(addUpgrade); - } - } + simpleWithCustomItem( + new ResourceLocation(ComputerCraftAPI.MOD_ID, "shulker"), + ModRegistry.TurtleSerialisers.STORAGE.get(), + PlatformHelper.get().getRecipeIngredients().shulkerBox() + ).add(addUpgrade); } }); } diff --git a/projects/common/src/datagen/java/dan200/computercraft/data/PocketUpgradeProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/PocketUpgradeProvider.java index d9c4f27ca..60a261827 100644 --- a/projects/common/src/datagen/java/dan200/computercraft/data/PocketUpgradeProvider.java +++ b/projects/common/src/datagen/java/dan200/computercraft/data/PocketUpgradeProvider.java @@ -22,7 +22,7 @@ class PocketUpgradeProvider extends PocketUpgradeDataProvider { @Override protected void addUpgrades(Consumer>> addUpgrade) { - addUpgrade.accept(simpleWithCustomItem(id("speaker"), PocketUpgradeSerialisers.SPEAKER.get(), Items.SPEAKER.get())); + simpleWithCustomItem(id("speaker"), PocketUpgradeSerialisers.SPEAKER.get(), Items.SPEAKER.get()).add(addUpgrade); simpleWithCustomItem(id("wireless_modem_normal"), PocketUpgradeSerialisers.WIRELESS_MODEM_NORMAL.get(), Items.WIRELESS_MODEM_NORMAL.get()).add(addUpgrade); simpleWithCustomItem(id("wireless_modem_advanced"), PocketUpgradeSerialisers.WIRELESS_MODEM_ADVANCED.get(), Items.WIRELESS_MODEM_ADVANCED.get()).add(addUpgrade); } diff --git a/projects/common/src/datagen/java/dan200/computercraft/data/RecipeProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/RecipeProvider.java index 5e8dbe7bb..5bb8749fc 100644 --- a/projects/common/src/datagen/java/dan200/computercraft/data/RecipeProvider.java +++ b/projects/common/src/datagen/java/dan200/computercraft/data/RecipeProvider.java @@ -114,9 +114,9 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { .group(name.toString()) .pattern("#T") .define('T', base.getItem()) - .define('#', upgrade.getCraftingItem().getItem()) + .define('#', upgrade.getCraftingIngredient()) .unlockedBy("has_items", - inventoryChange(base.getItem(), upgrade.getCraftingItem().getItem())) + inventoryChange(itemPredicate(base.getItem()), itemPredicate(upgrade.getCraftingIngredient()))) .save( RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPED.get(), add).withResultTag(result.getTag()), name.withSuffix(String.format("/%s/%s", upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath())) @@ -147,9 +147,9 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider { .pattern("#") .pattern("P") .define('P', base.getItem()) - .define('#', upgrade.getCraftingItem().getItem()) + .define('#', upgrade.getCraftingIngredient()) .unlockedBy("has_items", - inventoryChange(base.getItem(), upgrade.getCraftingItem().getItem())) + inventoryChange(itemPredicate(base.getItem()), itemPredicate(upgrade.getCraftingIngredient()))) .save( RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPED.get(), add).withResultTag(result.getTag()), name.withSuffix(String.format("/%s/%s", upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath())) diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json index b58414a84..ad66f26c1 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json @@ -4,6 +4,9 @@ "group": "computercraft:pocket_advanced", "key": {"#": {"item": "computercraft:speaker"}, "P": {"item": "computercraft:pocket_computer_advanced"}}, "pattern": ["#", "P"], - "result": {"item": "computercraft:pocket_computer_advanced", "nbt": "{Upgrade:\"computercraft:speaker\"}"}, + "result": { + "item": "computercraft:pocket_computer_advanced", + "nbt": "{Upgrade:\"computercraft:speaker\",UpgradeItem:{Count:1b,id:\"computercraft:speaker\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json index a5128aaf9..2135bc3d0 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -9,7 +9,7 @@ "pattern": ["#", "P"], "result": { "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" + "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\",UpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_advanced\"}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json index c8f5ab064..bc5a10462 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json @@ -9,7 +9,7 @@ "pattern": ["#", "P"], "result": { "item": "computercraft:pocket_computer_advanced", - "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" + "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\",UpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_normal\"}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json index 216e55664..bb71bc93e 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json @@ -4,6 +4,9 @@ "group": "computercraft:pocket_normal", "key": {"#": {"item": "computercraft:speaker"}, "P": {"item": "computercraft:pocket_computer_normal"}}, "pattern": ["#", "P"], - "result": {"item": "computercraft:pocket_computer_normal", "nbt": "{Upgrade:\"computercraft:speaker\"}"}, + "result": { + "item": "computercraft:pocket_computer_normal", + "nbt": "{Upgrade:\"computercraft:speaker\",UpgradeItem:{Count:1b,id:\"computercraft:speaker\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json index e4a8a2475..d61efc8cf 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json @@ -9,7 +9,7 @@ "pattern": ["#", "P"], "result": { "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\"}" + "nbt": "{Upgrade:\"computercraft:wireless_modem_advanced\",UpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_advanced\"}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json index 1f14fe111..c1bddae36 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json @@ -9,7 +9,7 @@ "pattern": ["#", "P"], "result": { "item": "computercraft:pocket_computer_normal", - "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\"}" + "nbt": "{Upgrade:\"computercraft:wireless_modem_normal\",UpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_normal\"}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json index c1c2ee567..8b3e8c9e7 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_advanced", "key": {"#": {"item": "computercraft:speaker"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_advanced", "nbt": "{RightUpgrade:\"computercraft:speaker\"}"}, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:speaker\",RightUpgradeItem:{Count:1b,id:\"computercraft:speaker\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json index c38f055cd..da2f3284c 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\",RightUpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_advanced\"}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json index 3a82c6f72..020f22f02 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_advanced", "key": {"#": {"item": "computercraft:wireless_modem_normal"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_advanced", "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}"}, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\",RightUpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_normal\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json index bbd4847be..c6823cf9d 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_advanced", "key": {"#": {"item": "minecraft:crafting_table"}, "T": {"item": "computercraft:turtle_advanced"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_advanced", "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}"}, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:crafting_table\",RightUpgradeItem:{Count:1b,id:\"minecraft:crafting_table\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json index e4198aa6f..6b6b4c003 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_axe\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_axe\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_axe\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json index b87716788..50ee8a0e7 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_hoe\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json index 1e9ce962a..e5bd5f14f 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_pickaxe\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json index 557c3b507..0d3f73b50 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_shovel\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json index d618d7e51..b0a1bf687 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_advanced", - "nbt": "{RightUpgrade:\"minecraft:diamond_sword\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_sword\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_sword\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json index bbb98011b..ac852cc49 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_normal", "key": {"#": {"item": "computercraft:speaker"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_normal", "nbt": "{RightUpgrade:\"computercraft:speaker\"}"}, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:speaker\",RightUpgradeItem:{Count:1b,id:\"computercraft:speaker\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json index d6479ae5a..11928b9b0 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_normal", "key": {"#": {"item": "computercraft:wireless_modem_advanced"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_normal", "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}"}, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\",RightUpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_advanced\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json index 2edbe58cf..bb1fa526a 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_normal", "key": {"#": {"item": "computercraft:wireless_modem_normal"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_normal", "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}"}, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\",RightUpgradeItem:{Count:1b,id:\"computercraft:wireless_modem_normal\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json index 1f6233d88..f161fd96c 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json @@ -4,6 +4,9 @@ "group": "computercraft:turtle_normal", "key": {"#": {"item": "minecraft:crafting_table"}, "T": {"item": "computercraft:turtle_normal"}}, "pattern": ["#T"], - "result": {"item": "computercraft:turtle_normal", "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}"}, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:crafting_table\",RightUpgradeItem:{Count:1b,id:\"minecraft:crafting_table\"}}" + }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json index bf6750a01..5f18e610f 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_axe\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_axe\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_axe\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json index b55ceca7c..324f398ae 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_hoe\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json index bf8a729a4..9fa998d2d 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_pickaxe\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json index 15913ef34..46ba6916a 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_shovel\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json index b4862e713..3a59a5b11 100644 --- a/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json +++ b/projects/common/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json @@ -6,7 +6,7 @@ "pattern": ["#T"], "result": { "item": "computercraft:turtle_normal", - "nbt": "{RightUpgrade:\"minecraft:diamond_sword\",RightUpgradeNbt:{Tag:{Damage:0}}}" + "nbt": "{RightUpgrade:\"minecraft:diamond_sword\",RightUpgradeItem:{Count:1b,id:\"minecraft:diamond_sword\",tag:{Damage:0}}}" }, "show_notification": true } diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json deleted file mode 100644 index 2d95f57bb..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/black.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/black.json deleted file mode 100644 index ea07b7de3..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/black.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:black_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/blue.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/blue.json deleted file mode 100644 index 32a890ace..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/blue.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:blue_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/brown.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/brown.json deleted file mode 100644 index a62301e8e..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/brown.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:brown_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/cyan.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/cyan.json deleted file mode 100644 index e50943631..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/cyan.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:cyan_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/gray.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/gray.json deleted file mode 100644 index 05554fd1f..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/gray.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:gray_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/green.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/green.json deleted file mode 100644 index fc9e771ae..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/green.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:green_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/light_blue.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/light_blue.json deleted file mode 100644 index f8a1f0790..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/light_blue.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:light_blue_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/light_gray.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/light_gray.json deleted file mode 100644 index 072ea571a..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/light_gray.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:light_gray_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/lime.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/lime.json deleted file mode 100644 index a00c0d055..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/lime.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:lime_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/magenta.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/magenta.json deleted file mode 100644 index f580376e8..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/magenta.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:magenta_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/orange.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/orange.json deleted file mode 100644 index 4a98c6a6d..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/orange.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:orange_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/pink.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/pink.json deleted file mode 100644 index ffdf550b4..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/pink.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:pink_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/purple.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/purple.json deleted file mode 100644 index 0186ff969..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/purple.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:purple_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/red.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/red.json deleted file mode 100644 index b769fb59c..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/red.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:red_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/white.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/white.json deleted file mode 100644 index 7797fee27..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/white.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:white_shulker_box"} diff --git a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/yellow.json b/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/yellow.json deleted file mode 100644 index 0387f8529..000000000 --- a/projects/common/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker/yellow.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "computercraft:storage", "item": "minecraft:yellow_shulker_box"} diff --git a/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java b/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java index 6853b3de0..c8e3b1088 100644 --- a/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java +++ b/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java @@ -11,6 +11,8 @@ import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.shared.platform.PlatformHelper; import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; @@ -36,7 +38,7 @@ import java.util.stream.Collectors; * @see TurtleUpgrades * @see PocketUpgrades */ -public class UpgradeManager, T extends UpgradeBase> extends SimpleJsonResourceReloadListener { +public final class UpgradeManager, T extends UpgradeBase> extends SimpleJsonResourceReloadListener { private static final Logger LOG = LoggerFactory.getLogger(UpgradeManager.class); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); @@ -79,9 +81,9 @@ public class UpgradeManager, T extends if (stack.isEmpty()) return null; for (var wrapper : current.values()) { - var craftingStack = wrapper.upgrade().getCraftingItem(); - if (!craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade().isItemSuitable(stack)) { - return UpgradeData.of(wrapper.upgrade, wrapper.upgrade.getUpgradeData(stack)); + var upgrade = wrapper.upgrade; + if (upgrade.getCraftingIngredient().test(stack) && upgrade.isItemSuitable(stack)) { + return UpgradeData.of(wrapper.upgrade, stack, wrapper.upgrade.getUpgradeData(stack)); } } @@ -96,6 +98,39 @@ public class UpgradeManager, T extends return current; } + public record UpgradeKey(String id, String item, String data) { + public UpgradeKey(String id, String data) { + this(id, id + "Item", data); + } + } + + public @Nullable UpgradeData readUpgrade(CompoundTag tag, UpgradeKey key) { + if (!tag.contains(key.id(), Tag.TAG_STRING)) return null; + + var upgrade = get(tag.getString(key.id())); + if (upgrade == null) return null; + + var data = tag.getCompound(key.data()); + var item = tag.contains(key.item(), Tag.TAG_COMPOUND) ? ItemStack.of(tag.getCompound(key.item())) : upgrade.getUpgradeItem(data); + return UpgradeData.of(upgrade, item, data); + } + + public static void writeUpgrade(CompoundTag tag, UpgradeKey key, @Nullable UpgradeData upgrade) { + if (upgrade == null) { + tag.remove(key.id()); + tag.remove(key.data()); + tag.remove(key.item()); + } else { + tag.putString(key.id(), upgrade.upgrade().getUpgradeID().toString()); + tag.put(key.item(), upgrade.getUpgradeItem().save(new CompoundTag())); + if (upgrade.data().isEmpty()) { + tag.remove(key.data()); + } else { + tag.put(key.data(), upgrade.data().copy()); + } + } + } + @Override protected void apply(Map upgrades, ResourceManager manager, ProfilerFiller profiler) { Map> newUpgrades = new HashMap<>(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java index ce1cae72a..9920bcb48 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java @@ -296,15 +296,15 @@ public final class ModRegistry { static final RegistrationHelper> REGISTRY = PlatformHelper.get().createRegistrationHelper(TurtleUpgradeSerialiser.registryId()); public static final RegistryEntry> SPEAKER = - REGISTRY.register("speaker", () -> TurtleUpgradeSerialiser.simpleWithCustomItem(TurtleSpeaker::new)); + REGISTRY.register("speaker", () -> TurtleUpgradeSerialiser.simpleWithCustomIngredient(TurtleSpeaker::new)); public static final RegistryEntry> WORKBENCH = - REGISTRY.register("workbench", () -> TurtleUpgradeSerialiser.simpleWithCustomItem(TurtleCraftingTable::new)); + REGISTRY.register("workbench", () -> TurtleUpgradeSerialiser.simpleWithCustomIngredient(TurtleCraftingTable::new)); public static final RegistryEntry> WIRELESS_MODEM_NORMAL = - REGISTRY.register("wireless_modem_normal", () -> TurtleUpgradeSerialiser.simpleWithCustomItem((id, item) -> new TurtleModem(id, item, false))); + REGISTRY.register("wireless_modem_normal", () -> TurtleUpgradeSerialiser.simpleWithCustomIngredient((id, item) -> new TurtleModem(id, item, false))); public static final RegistryEntry> WIRELESS_MODEM_ADVANCED = - REGISTRY.register("wireless_modem_advanced", () -> TurtleUpgradeSerialiser.simpleWithCustomItem((id, item) -> new TurtleModem(id, item, true))); + REGISTRY.register("wireless_modem_advanced", () -> TurtleUpgradeSerialiser.simpleWithCustomIngredient((id, item) -> new TurtleModem(id, item, true))); public static final RegistryEntry> STORAGE = - REGISTRY.register("storage", () -> TurtleUpgradeSerialiser.simpleWithCustomItem(TurtleStorage::new)); + REGISTRY.register("storage", () -> TurtleUpgradeSerialiser.simpleWithCustomIngredient(TurtleStorage::new)); public static final RegistryEntry> TOOL = REGISTRY.register("tool", () -> TurtleToolSerialiser.INSTANCE); } @@ -313,11 +313,11 @@ public final class ModRegistry { static final RegistrationHelper> REGISTRY = PlatformHelper.get().createRegistrationHelper(PocketUpgradeSerialiser.registryId()); public static final RegistryEntry> SPEAKER = - REGISTRY.register("speaker", () -> PocketUpgradeSerialiser.simpleWithCustomItem(PocketSpeaker::new)); + REGISTRY.register("speaker", () -> PocketUpgradeSerialiser.simpleWithCustomIngredient(PocketSpeaker::new)); public static final RegistryEntry> WIRELESS_MODEM_NORMAL = - REGISTRY.register("wireless_modem_normal", () -> PocketUpgradeSerialiser.simpleWithCustomItem((id, item) -> new PocketModem(id, item, false))); + REGISTRY.register("wireless_modem_normal", () -> PocketUpgradeSerialiser.simpleWithCustomIngredient((id, item) -> new PocketModem(id, item, false))); public static final RegistryEntry> WIRELESS_MODEM_ADVANCED = - REGISTRY.register("wireless_modem_advanced", () -> PocketUpgradeSerialiser.simpleWithCustomItem((id, item) -> new PocketModem(id, item, true))); + REGISTRY.register("wireless_modem_advanced", () -> PocketUpgradeSerialiser.simpleWithCustomIngredient((id, item) -> new PocketModem(id, item, true))); } public static class Menus { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/platform/RecipeIngredients.java b/projects/common/src/main/java/dan200/computercraft/shared/platform/RecipeIngredients.java index ac984c5d4..ec211aa9c 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/platform/RecipeIngredients.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/platform/RecipeIngredients.java @@ -22,6 +22,7 @@ import net.minecraft.world.item.crafting.Ingredient; * @param dye All dye items. * @param enderPearl All {@link Items#ENDER_PEARL} items. * @param woodenChest All wooden chests (both normal and trapped chests). + * @param shulkerBox All shulker boxes. */ public record RecipeIngredients( Ingredient redstone, @@ -35,6 +36,7 @@ public record RecipeIngredients( Ingredient head, Ingredient dye, Ingredient enderPearl, - Ingredient woodenChest + Ingredient woodenChest, + Ingredient shulkerBox ) { } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketBrain.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketBrain.java index 59ff5f0fd..c3898ab59 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketBrain.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketBrain.java @@ -8,6 +8,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.upgrades.UpgradeData; +import dan200.computercraft.api.upgrades.UpgradeHandle; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ServerComputer; @@ -147,6 +148,11 @@ public final class PocketBrain implements IPocketAccess { return upgrade == null ? new CompoundTag() : upgrade.data(); } + @Override + public @Nullable UpgradeHandle getUpgradeHandle() { + throw new UnsupportedOperationException(); // TODO + } + @Override public void updateUpgradeNBTData() { dirty = true; diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java index 71d0cb826..67bd8a452 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java @@ -10,6 +10,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.impl.PocketUpgrades; +import dan200.computercraft.impl.UpgradeManager; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -26,7 +27,6 @@ import dan200.computercraft.shared.pocket.core.PocketHolder; import dan200.computercraft.shared.pocket.core.PocketServerComputer; import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.util.InventoryUtil; -import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -49,8 +49,7 @@ import java.util.Objects; import java.util.UUID; public class PocketComputerItem extends Item implements IComputerItem, IColouredItem { - private static final String NBT_UPGRADE = "Upgrade"; - private static final String NBT_UPGRADE_INFO = "UpgradeInfo"; + private static final UpgradeManager.UpgradeKey NBT_UPGRADE = new UpgradeManager.UpgradeKey("Upgrade", "UpgradeInfo"); public static final String NBT_ON = "On"; private static final String NBT_INSTANCE = "InstanceId"; @@ -67,10 +66,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IColoured var result = new ItemStack(this); if (id >= 0) result.getOrCreateTag().putInt(NBT_ID, id); if (label != null) result.setHoverName(Component.literal(label)); - if (upgrade != null) { - result.getOrCreateTag().putString(NBT_UPGRADE, upgrade.upgrade().getUpgradeID().toString()); - if (!upgrade.data().isEmpty()) result.getOrCreateTag().put(NBT_UPGRADE_INFO, upgrade.data().copy()); - } + if (upgrade != null) UpgradeManager.writeUpgrade(result.getOrCreateTag(), NBT_UPGRADE, upgrade); if (colour != -1) result.getOrCreateTag().putInt(NBT_COLOUR, colour); return result; } @@ -365,31 +361,16 @@ public class PocketComputerItem extends Item implements IComputerItem, IColoured } public static @Nullable IPocketUpgrade getUpgrade(ItemStack stack) { - var compound = stack.getTag(); - if (compound == null || !compound.contains(NBT_UPGRADE)) return null; - return PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE)); + var upgrade = getUpgradeWithData(stack); + return upgrade == null ? null : upgrade.upgrade(); } public static @Nullable UpgradeData getUpgradeWithData(ItemStack stack) { - var compound = stack.getTag(); - if (compound == null || !compound.contains(NBT_UPGRADE)) return null; - var upgrade = PocketUpgrades.instance().get(compound.getString(NBT_UPGRADE)); - return upgrade == null ? null : UpgradeData.of(upgrade, NBTUtil.getCompoundOrEmpty(compound, NBT_UPGRADE_INFO)); + var tag = stack.getTag(); + return tag == null ? null : PocketUpgrades.instance().readUpgrade(tag, NBT_UPGRADE); } public static void setUpgrade(ItemStack stack, @Nullable UpgradeData upgrade) { - var compound = stack.getOrCreateTag(); - - if (upgrade == null) { - compound.remove(NBT_UPGRADE); - compound.remove(NBT_UPGRADE_INFO); - } else { - compound.putString(NBT_UPGRADE, upgrade.upgrade().getUpgradeID().toString()); - if (upgrade.data().isEmpty()) { - compound.remove(NBT_UPGRADE_INFO); - } else { - compound.put(NBT_UPGRADE_INFO, upgrade.data().copy()); - } - } + UpgradeManager.writeUpgrade(stack.getOrCreateTag(), NBT_UPGRADE, upgrade); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index feff1ba78..239610bfc 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -9,14 +9,14 @@ import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import org.jspecify.annotations.Nullable; -public class PocketModem extends AbstractPocketUpgrade { +public class PocketModem extends AbstractPocketUpgrade.StackAware { private final boolean advanced; - public PocketModem(ResourceLocation id, ItemStack stack, boolean advanced) { - super(id, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, stack); + public PocketModem(ResourceLocation id, Ingredient item, boolean advanced) { + super(id, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, item); this.advanced = advanced; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index c863b9a47..373348bef 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -9,11 +9,11 @@ import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import org.jspecify.annotations.Nullable; -public class PocketSpeaker extends AbstractPocketUpgrade { - public PocketSpeaker(ResourceLocation id, ItemStack item) { +public class PocketSpeaker extends AbstractPocketUpgrade.StackAware { + public PocketSpeaker(ResourceLocation id, Ingredient item) { super(id, UpgradeSpeakerPeripheral.ADJECTIVE, item); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlock.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlock.java index 72b5792ac..f276394c5 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlock.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlock.java @@ -203,7 +203,7 @@ public class TurtleBlock extends AbstractComputerBlock implem } private static @Nullable UpgradeData withPersistedData(@Nullable UpgradeData upgrade) { - return upgrade == null ? null : UpgradeData.of(upgrade.upgrade(), upgrade.upgrade().getPersistedData(upgrade.data())); + return upgrade == null ? null : UpgradeData.of(upgrade.upgrade(), upgrade.getUpgradeItem(), upgrade.upgrade().getPersistedData(upgrade.data())); } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index ba8ec3438..448dfd01d 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -13,9 +13,11 @@ import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommand; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.upgrades.UpgradeData; +import dan200.computercraft.api.upgrades.UpgradeHandle; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.util.PeripheralHelpers; import dan200.computercraft.impl.TurtleUpgrades; +import dan200.computercraft.impl.UpgradeManager; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.config.Config; @@ -48,10 +50,8 @@ import static dan200.computercraft.shared.common.IColouredItem.NBT_COLOUR; import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED; public class TurtleBrain implements TurtleAccessInternal { - public static final String NBT_RIGHT_UPGRADE = "RightUpgrade"; - public static final String NBT_RIGHT_UPGRADE_DATA = "RightUpgradeNbt"; - public static final String NBT_LEFT_UPGRADE = "LeftUpgrade"; - public static final String NBT_LEFT_UPGRADE_DATA = "LeftUpgradeNbt"; + public static final UpgradeManager.UpgradeKey NBT_RIGHT_UPGRADE = new UpgradeManager.UpgradeKey("RightUpgrade", "RightUpgradeNbt"); + public static final UpgradeManager.UpgradeKey NBT_LEFT_UPGRADE = new UpgradeManager.UpgradeKey("LeftUpgrade", "LeftUpgradeNbt"); public static final String NBT_FUEL = "Fuel"; public static final String NBT_OVERLAY = "Overlay"; @@ -137,16 +137,8 @@ public class TurtleBrain implements TurtleAccessInternal { overlay = nbt.contains(NBT_OVERLAY) ? new ResourceLocation(nbt.getString(NBT_OVERLAY)) : null; // Read upgrades - setUpgradeDirect(TurtleSide.LEFT, readUpgrade(nbt, NBT_LEFT_UPGRADE, NBT_LEFT_UPGRADE_DATA)); - setUpgradeDirect(TurtleSide.RIGHT, readUpgrade(nbt, NBT_RIGHT_UPGRADE, NBT_RIGHT_UPGRADE_DATA)); - } - - private @Nullable UpgradeData readUpgrade(CompoundTag tag, String upgradeKey, String dataKey) { - if (!tag.contains(upgradeKey)) return null; - var upgrade = TurtleUpgrades.instance().get(tag.getString(upgradeKey)); - if (upgrade == null) return null; - - return UpgradeData.of(upgrade, tag.getCompound(dataKey)); + setUpgradeDirect(TurtleSide.LEFT, TurtleUpgrades.instance().readUpgrade(nbt, NBT_LEFT_UPGRADE)); + setUpgradeDirect(TurtleSide.RIGHT, TurtleUpgrades.instance().readUpgrade(nbt, NBT_RIGHT_UPGRADE)); } private void writeCommon(CompoundTag nbt) { @@ -155,18 +147,8 @@ public class TurtleBrain implements TurtleAccessInternal { if (overlay != null) nbt.putString(NBT_OVERLAY, overlay.toString()); // Write upgrades - var leftUpgradeId = getUpgradeId(getUpgrade(TurtleSide.LEFT)); - if (leftUpgradeId != null) nbt.putString(NBT_LEFT_UPGRADE, leftUpgradeId); - var rightUpgradeId = getUpgradeId(getUpgrade(TurtleSide.RIGHT)); - if (rightUpgradeId != null) nbt.putString(NBT_RIGHT_UPGRADE, rightUpgradeId); - - // Write upgrade NBT - if (upgradeNBTData.containsKey(TurtleSide.LEFT)) { - nbt.put(NBT_LEFT_UPGRADE_DATA, getUpgradeNBTData(TurtleSide.LEFT).copy()); - } - if (upgradeNBTData.containsKey(TurtleSide.RIGHT)) { - nbt.put(NBT_RIGHT_UPGRADE_DATA, getUpgradeNBTData(TurtleSide.RIGHT).copy()); - } + UpgradeManager.writeUpgrade(nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT)); + UpgradeManager.writeUpgrade(nbt, NBT_RIGHT_UPGRADE, getUpgradeWithData(TurtleSide.RIGHT)); } public void readFromNBT(CompoundTag nbt) { @@ -206,10 +188,6 @@ public class TurtleBrain implements TurtleAccessInternal { return nbt; } - private static @Nullable String getUpgradeId(@Nullable ITurtleUpgrade upgrade) { - return upgrade != null ? upgrade.getUpgradeID().toString() : null; - } - public void readDescription(CompoundTag nbt) { readCommon(nbt); @@ -522,6 +500,16 @@ public class TurtleBrain implements TurtleAccessInternal { return peripherals.get(side); } + @Override + public @Nullable UpgradeData getUpgradeWithData(TurtleSide side) { + throw new UnsupportedOperationException(); // TODO + } + + @Override + public @Nullable UpgradeHandle getUpgradeHandle(TurtleSide side) { + throw new UnsupportedOperationException(); // TODO + } + @Override public CompoundTag getUpgradeNBTData(TurtleSide side) { var nbt = upgradeNBTData.get(side); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItem.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItem.java index 261236216..c182180a6 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItem.java @@ -10,10 +10,10 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.impl.TurtleUpgrades; +import dan200.computercraft.impl.UpgradeManager; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.items.AbstractComputerItem; import dan200.computercraft.shared.turtle.blocks.TurtleBlock; -import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.core.cauldron.CauldronInteraction; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -43,17 +43,8 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem { if (fuelLevel > 0) stack.getOrCreateTag().putInt(NBT_FUEL, fuelLevel); if (overlay != null) stack.getOrCreateTag().putString(NBT_OVERLAY, overlay.toString()); - if (leftUpgrade != null) { - var tag = stack.getOrCreateTag(); - tag.putString(NBT_LEFT_UPGRADE, leftUpgrade.upgrade().getUpgradeID().toString()); - if (!leftUpgrade.data().isEmpty()) tag.put(NBT_LEFT_UPGRADE_DATA, leftUpgrade.data().copy()); - } - - if (rightUpgrade != null) { - var tag = stack.getOrCreateTag(); - tag.putString(NBT_RIGHT_UPGRADE, rightUpgrade.upgrade().getUpgradeID().toString()); - if (!rightUpgrade.data().isEmpty()) tag.put(NBT_RIGHT_UPGRADE_DATA, rightUpgrade.data().copy()); - } + if (leftUpgrade != null) UpgradeManager.writeUpgrade(stack.getOrCreateTag(), NBT_LEFT_UPGRADE, leftUpgrade); + if (rightUpgrade != null) UpgradeManager.writeUpgrade(stack.getOrCreateTag(), NBT_RIGHT_UPGRADE, rightUpgrade); return stack; } @@ -113,24 +104,15 @@ public class TurtleItem extends AbstractComputerItem implements IColouredItem { } public @Nullable ITurtleUpgrade getUpgrade(ItemStack stack, TurtleSide side) { - var tag = stack.getTag(); - if (tag == null) return null; - - var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE; - if (!tag.contains(key)) return null; - return TurtleUpgrades.instance().get(tag.getString(key)); + var upgrade = getUpgradeWithData(stack, side); + return upgrade == null ? null : upgrade.upgrade(); } public @Nullable UpgradeData getUpgradeWithData(ItemStack stack, TurtleSide side) { var tag = stack.getTag(); - if (tag == null) return null; - - var key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE; - if (!tag.contains(key)) return null; - var upgrade = TurtleUpgrades.instance().get(tag.getString(key)); - if (upgrade == null) return null; - var dataKey = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE_DATA : NBT_RIGHT_UPGRADE_DATA; - return UpgradeData.of(upgrade, NBTUtil.getCompoundOrEmpty(tag, dataKey)); + return tag == null ? null : TurtleUpgrades.instance().readUpgrade( + tag, side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE + ); } public @Nullable ResourceLocation getOverlay(ItemStack stack) { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 83ce27f32..c107d89de 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -10,12 +10,12 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; -public class TurtleCraftingTable extends AbstractTurtleUpgrade { - public TurtleCraftingTable(ResourceLocation id, ItemStack stack) { - super(id, TurtleUpgradeType.PERIPHERAL, "upgrade.minecraft.crafting_table.adjective", stack); +public class TurtleCraftingTable extends AbstractTurtleUpgrade.StackAware { + public TurtleCraftingTable(ResourceLocation id, Ingredient item) { + super(id, TurtleUpgradeType.PERIPHERAL, "upgrade.minecraft.crafting_table.adjective", item); } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 968c4e68a..05ac13aef 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -11,12 +11,12 @@ import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeriph import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.Nullable; -public class TurtleModem extends AbstractTurtleUpgrade { +public class TurtleModem extends AbstractTurtleUpgrade.StackAware { private static class Peripheral extends WirelessModemPeripheral { private final ITurtleAccess turtle; @@ -48,8 +48,8 @@ public class TurtleModem extends AbstractTurtleUpgrade { private final boolean advanced; - public TurtleModem(ResourceLocation id, ItemStack stack, boolean advanced) { - super(id, TurtleUpgradeType.PERIPHERAL, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, stack); + public TurtleModem(ResourceLocation id, Ingredient item, boolean advanced) { + super(id, TurtleUpgradeType.PERIPHERAL, advanced ? WirelessModemPeripheral.ADVANCED_ADJECTIVE : WirelessModemPeripheral.NORMAL_ADJECTIVE, item); this.advanced = advanced; } @@ -66,15 +66,16 @@ public class TurtleModem extends AbstractTurtleUpgrade { @Override public void update(ITurtleAccess turtle, TurtleSide side) { // Advance the modem - if (!turtle.getLevel().isClientSide) { - var peripheral = turtle.getPeripheral(side); - if (peripheral instanceof Peripheral modem) { - var state = modem.getModemState(); - if (state.pollChanged()) { - turtle.getUpgradeNBTData(side).putBoolean("active", state.isOpen()); - turtle.updateUpgradeNBTData(side); - } - } + if (turtle.getLevel().isClientSide) return; + + var peripheral = turtle.getPeripheral(side); + var handle = turtle.getUpgradeHandle(side); + if (!(peripheral instanceof Peripheral modem) || handle == null) return; + + var state = modem.getModemState(); + if (state.pollChanged()) { + handle.getData().putBoolean("active", state.isOpen()); + handle.setChanged(); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 3df02429b..a2d892ff1 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -12,11 +12,11 @@ import dan200.computercraft.api.turtle.TurtleUpgradeType; import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.Nullable; -public class TurtleSpeaker extends AbstractTurtleUpgrade { +public class TurtleSpeaker extends AbstractTurtleUpgrade.StackAware { private static class Peripheral extends UpgradeSpeakerPeripheral { final ITurtleAccess turtle; @@ -35,7 +35,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade { } } - public TurtleSpeaker(ResourceLocation id, ItemStack item) { + public TurtleSpeaker(ResourceLocation id, Ingredient item) { super(id, TurtleUpgradeType.PERIPHERAL, UpgradeSpeakerPeripheral.ADJECTIVE, item); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleStorage.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleStorage.java index fd0ff5498..c72ab2108 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleStorage.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleStorage.java @@ -7,16 +7,15 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.turtle.AbstractTurtleUpgrade; -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.api.turtle.TurtleUpgradeType; +import dan200.computercraft.api.turtle.*; +import dan200.computercraft.api.upgrades.UpgradeHandle; import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods; import dan200.computercraft.shared.platform.ItemContainer; import dan200.computercraft.shared.platform.PlatformHelper; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import org.jspecify.annotations.Nullable; import java.util.Map; @@ -27,26 +26,15 @@ import static net.minecraft.nbt.Tag.TAG_COMPOUND; /** * Turtle storage upgrade. */ -public final class TurtleStorage extends AbstractTurtleUpgrade { +public final class TurtleStorage extends AbstractTurtleUpgrade.StackAware { private static final String TAG_ITEM_TAG = "Tag"; public static final String ADJECTIVE = "upgrade.computercraft.storage.adjective"; public static final String DATA_PACK_NAME = "turtle_storage"; public static final String DATA_PACK_TRANSLATION = "dataPack." + DATA_PACK_NAME + ".description"; - public TurtleStorage(ResourceLocation id, ItemStack stack) { - super(id, TurtleUpgradeType.PERIPHERAL, ADJECTIVE, stack); - } - - @Override - public CompoundTag getUpgradeData(ItemStack stack) { - var upgradeData = super.getUpgradeData(stack); - - // Store the item's current tag. - var itemTag = stack.getTag(); - if (itemTag != null) upgradeData.put(TAG_ITEM_TAG, itemTag); - - return upgradeData; + public TurtleStorage(ResourceLocation id, Ingredient item) { + super(id, TurtleUpgradeType.PERIPHERAL, ADJECTIVE, item); } @Override @@ -87,12 +75,16 @@ public final class TurtleStorage extends AbstractTurtleUpgrade { this.side = side; } - private ItemStack getStack() throws LuaException { - var upgrade = turtle.getUpgradeWithData(side); - if (upgrade == null || !(upgrade.upgrade() instanceof TurtleStorage)) { + private UpgradeHandle getHandle() throws LuaException { + var upgrade = turtle.getUpgradeHandle(side); + if (upgrade == null || !(upgrade.getUpgrade() instanceof TurtleStorage)) { throw new LuaException("Upgrade is not equipped"); } - return upgrade.getUpgradeItem(); + return upgrade; + } + + private ItemStack getStack() throws LuaException { + return getHandle().getItem(); } private static ItemContainer getContainer(ItemStack stack) throws LuaException { @@ -157,8 +149,9 @@ public final class TurtleStorage extends AbstractTurtleUpgrade { */ @LuaFunction(mainThread = true) public int pushItems(int fromSlot, Optional limit, Optional toSlot) throws LuaException { - var stack = getStack(); - return moveAndUpdate(stack, getContainer(stack), fromSlot, turtleInventory, toSlot, limit); + var handle = getHandle(); + var stack = handle.getItem(); + return moveAndUpdate(handle, stack, getContainer(stack), fromSlot, turtleInventory, toSlot, limit); } /** @@ -172,16 +165,14 @@ public final class TurtleStorage extends AbstractTurtleUpgrade { */ @LuaFunction(mainThread = true) public int pullItems(Optional fromSlot, Optional limit, Optional toSlot) throws LuaException { - var stack = getStack(); - return moveAndUpdate(stack, turtleInventory, fromSlot.orElse(turtle.getSelectedSlot() + 1), getContainer(stack), toSlot, limit); + var handle = getHandle(); + var stack = handle.getItem(); + return moveAndUpdate(handle, stack, turtleInventory, fromSlot.orElse(turtle.getSelectedSlot() + 1), getContainer(stack), toSlot, limit); } - private int moveAndUpdate(ItemStack stack, ItemContainer from, int fromSlot, ItemContainer to, Optional toSlot, Optional limit) throws LuaException { + private int moveAndUpdate(UpgradeHandle handle, ItemStack stack, ItemContainer from, int fromSlot, ItemContainer to, Optional toSlot, Optional limit) throws LuaException { var moved = AbstractInventoryMethods.move(from, fromSlot, to, toSlot, limit); - if (moved > 0) { - turtle.getUpgradeNBTData(side).put(TAG_ITEM_TAG, stack.getOrCreateTag()); - turtle.updateUpgradeNBTData(side); - } + if (moved > 0) handle.setItem(stack); return moved; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index cc0e5d4a2..32e91006b 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.ComputerCraftTags; import dan200.computercraft.api.turtle.*; +import dan200.computercraft.api.upgrades.UpgradeHandle; import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.turtle.TurtleUtil; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; @@ -27,9 +28,9 @@ import net.minecraft.world.entity.MobType; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -39,30 +40,27 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.EntityHitResult; import org.jspecify.annotations.Nullable; -import java.util.Objects; import java.util.function.Function; import static net.minecraft.nbt.Tag.TAG_COMPOUND; import static net.minecraft.nbt.Tag.TAG_LIST; -public class TurtleTool extends AbstractTurtleUpgrade { +public class TurtleTool extends AbstractTurtleUpgrade.StackAware { private static final TurtleCommandResult UNBREAKABLE = TurtleCommandResult.failure("Cannot break unbreakable block"); private static final TurtleCommandResult INEFFECTIVE = TurtleCommandResult.failure("Cannot break block with this tool"); private static final String TAG_ITEM_TAG = "Tag"; - final ItemStack item; final float damageMultiplier; final boolean allowEnchantments; final TurtleToolDurability consumeDurability; final @Nullable TagKey breakable; public TurtleTool( - ResourceLocation id, String adjective, Item craftItem, ItemStack toolItem, float damageMultiplier, + ResourceLocation id, String adjective, Ingredient item, float damageMultiplier, boolean allowEnchantments, TurtleToolDurability consumeDurability, @Nullable TagKey breakable ) { - super(id, TurtleUpgradeType.TOOL, adjective, new ItemStack(craftItem)); - item = toolItem; + super(id, TurtleUpgradeType.TOOL, adjective, item); this.damageMultiplier = damageMultiplier; this.allowEnchantments = allowEnchantments; this.consumeDurability = consumeDurability; @@ -86,17 +84,6 @@ public class TurtleTool extends AbstractTurtleUpgrade { || (tag.contains("AttributeModifiers", TAG_LIST) && !tag.getList("AttributeModifiers", TAG_COMPOUND).isEmpty()); } - @Override - public CompoundTag getUpgradeData(ItemStack stack) { - var upgradeData = super.getUpgradeData(stack); - - // Store the item's current tag. - var itemTag = stack.getTag(); - if (itemTag != null) upgradeData.put(TAG_ITEM_TAG, itemTag); - - return upgradeData; - } - @Override public ItemStack getUpgradeItem(CompoundTag upgradeData) { // Copy upgrade data back to the item. @@ -105,51 +92,37 @@ public class TurtleTool extends AbstractTurtleUpgrade { return item; } - private ItemStack getToolStack(ITurtleAccess turtle, TurtleSide side) { - return getUpgradeItem(turtle.getUpgradeNBTData(side)).copy(); - } - - private void setToolStack(ITurtleAccess turtle, TurtleSide side, ItemStack stack) { - var upgradeData = turtle.getUpgradeNBTData(side); - + private void setToolStack(UpgradeHandle upgrade, ItemStack stack) { + var oldStack = upgrade.getItem(); var useDurability = switch (consumeDurability) { case NEVER -> false; - case WHEN_ENCHANTED -> - upgradeData.contains(TAG_ITEM_TAG, TAG_COMPOUND) && isEnchanted(upgradeData.getCompound(TAG_ITEM_TAG)); + case WHEN_ENCHANTED -> isEnchanted(oldStack); case ALWAYS -> true; }; if (!useDurability) return; // If the tool has broken, remove the upgrade! if (stack.isEmpty()) { - turtle.setUpgradeWithData(side, null); + upgrade.clear(); return; } // If the tool has changed, no clue what's going on. - if (stack.getItem() != item.getItem()) return; - - var itemTag = stack.getTag(); + if (!getCraftingIngredient().test(stack) || !isItemSuitable(stack)) return; // Early return if the item hasn't changed to avoid redundant syncs with the client. - if (Objects.equals(itemTag, upgradeData.get(TAG_ITEM_TAG))) return; + if (ItemStack.isSameItemSameTags(stack, oldStack)) return; - if (itemTag == null) { - upgradeData.remove(TAG_ITEM_TAG); - } else { - upgradeData.put(TAG_ITEM_TAG, itemTag); - } - - turtle.updateUpgradeNBTData(side); + upgrade.setItem(stack); } - private T withEquippedItem(ITurtleAccess turtle, TurtleSide side, Direction direction, Function action) { + private T withEquippedItem(ITurtleAccess turtle, UpgradeHandle upgrade, Direction direction, Function action) { var turtlePlayer = TurtlePlayer.getWithPosition(turtle, turtle.getPosition(), direction); - turtlePlayer.loadInventory(getToolStack(turtle, side)); + turtlePlayer.loadInventory(upgrade.getItem()); var result = action.apply(turtlePlayer); - setToolStack(turtle, side, turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND)); + setToolStack(upgrade, turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND)); turtlePlayer.player().getInventory().clearContent(); return result; @@ -157,9 +130,12 @@ public class TurtleTool extends AbstractTurtleUpgrade { @Override public TurtleCommandResult useTool(ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, Direction direction) { + var handle = turtle.getUpgradeHandle(side); + if (handle == null) return TurtleCommandResult.failure("Upgrade is not equipped"); + return switch (verb) { - case ATTACK -> attack(turtle, side, direction); - case DIG -> dig(turtle, side, direction); + case ATTACK -> attack(turtle, handle, direction); + case DIG -> dig(turtle, handle, direction); }; } @@ -177,11 +153,10 @@ public class TurtleTool extends AbstractTurtleUpgrade { * Attack an entity. * * @param turtle The current turtle. - * @param side The side the tool is on. * @param direction The direction we're attacking in. * @return Whether an attack occurred. */ - private TurtleCommandResult attack(ITurtleAccess turtle, TurtleSide side, Direction direction) { + private TurtleCommandResult attack(ITurtleAccess turtle, UpgradeHandle upgrade, Direction direction) { // Create a fake player, and orient it appropriately var world = turtle.getLevel(); var position = turtle.getPosition(); @@ -196,8 +171,7 @@ public class TurtleTool extends AbstractTurtleUpgrade { var attacked = false; if (hit instanceof EntityHitResult entityHit) { // Load up the turtle's inventory - var stack = getToolStack(turtle, side); - turtlePlayer.loadInventory(stack); + turtlePlayer.loadInventory(upgrade.getItem()); var hitEntity = entityHit.getEntity(); @@ -216,7 +190,7 @@ public class TurtleTool extends AbstractTurtleUpgrade { TurtleUtil.stopConsuming(turtle); // Put everything we collected into the turtles inventory. - setToolStack(turtle, side, player.getItemInHand(InteractionHand.MAIN_HAND)); + setToolStack(upgrade, player.getItemInHand(InteractionHand.MAIN_HAND)); player.getInventory().clearContent(); } @@ -292,10 +266,10 @@ public class TurtleTool extends AbstractTurtleUpgrade { return true; } - private TurtleCommandResult dig(ITurtleAccess turtle, TurtleSide side, Direction direction) { + private TurtleCommandResult dig(ITurtleAccess turtle, UpgradeHandle upgrade, Direction direction) { var level = (ServerLevel) turtle.getLevel(); - return withEquippedItem(turtle, side, direction, turtlePlayer -> { + return withEquippedItem(turtle, upgrade, direction, turtlePlayer -> { var stack = turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND); // Right-click the block when using a shovel/hoe. Important that we do this before checking the block is diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiser.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiser.java index c150f6900..8813eeb40 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiser.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiser.java @@ -8,17 +8,15 @@ import com.google.gson.JsonObject; import dan200.computercraft.api.turtle.TurtleToolDurability; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.upgrades.UpgradeBase; -import dan200.computercraft.shared.platform.RegistryWrappers; +import dan200.computercraft.impl.upgrades.SerialiserWithCraftingIngredient; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.block.Block; -import java.util.Objects; - public final class TurtleToolSerialiser implements TurtleUpgradeSerialiser { public static final TurtleToolSerialiser INSTANCE = new TurtleToolSerialiser(); @@ -28,8 +26,8 @@ public final class TurtleToolSerialiser implements TurtleUpgradeSerialiser TagKey.create(Registries.BLOCK, b.readResourceLocation())); - return new TurtleTool(id, adjective, craftingItem, toolItem, damageMultiplier, allowsEnchantments, consumesDurability, breakable); + return new TurtleTool(id, adjective, item, damageMultiplier, allowsEnchantments, consumesDurability, breakable); } @Override public void toNetwork(FriendlyByteBuf buffer, TurtleTool upgrade) { buffer.writeUtf(upgrade.getUnlocalisedAdjective()); - buffer.writeId(RegistryWrappers.ITEMS, upgrade.getCraftingItem().getItem()); - buffer.writeItem(upgrade.item); + upgrade.getCraftingIngredient().toNetwork(buffer); buffer.writeFloat(upgrade.damageMultiplier); buffer.writeBoolean(upgrade.allowEnchantments); buffer.writeEnum(upgrade.consumeDurability); diff --git a/projects/common/src/test/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiserTest.java b/projects/common/src/test/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiserTest.java index 065c0b37b..86582ae85 100644 --- a/projects/common/src/test/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiserTest.java +++ b/projects/common/src/test/java/dan200/computercraft/shared/turtle/upgrades/TurtleToolSerialiserTest.java @@ -44,8 +44,7 @@ class TurtleToolSerialiserTest { return Combinators.combine( MinecraftArbitraries.resourceLocation(), Arbitraries.strings().ofMaxLength(100), - MinecraftArbitraries.item(), - MinecraftArbitraries.itemStack(), + MinecraftArbitraries.ingredient(), Arbitraries.floats(), Arbitraries.of(true, false), Arbitraries.of(TurtleToolDurability.values()), @@ -55,8 +54,7 @@ class TurtleToolSerialiserTest { private static final StructuralEquality equality = StructuralEquality.all( StructuralEquality.at("id", ITurtleUpgrade::getUpgradeID), - StructuralEquality.at("craftingItem", ITurtleUpgrade::getCraftingItem, MinecraftEqualities.itemStack), - StructuralEquality.at("tool", x -> x.item, MinecraftEqualities.itemStack), + StructuralEquality.at("craftingItem", ITurtleUpgrade::getCraftingIngredient, MinecraftEqualities.ingredient), StructuralEquality.at("damageMultiplier", x -> x.damageMultiplier), StructuralEquality.at("allowEnchantments", x -> x.allowEnchantments), StructuralEquality.at("consumeDurability", x -> x.consumeDurability), diff --git a/projects/fabric/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json b/projects/fabric/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json new file mode 100644 index 000000000..ccf43b3fe --- /dev/null +++ b/projects/fabric/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json @@ -0,0 +1 @@ +{"type": "computercraft:storage", "item": {"tag": "c:shulker_boxes"}} 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 c454edcfc..1a5811e4d 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 @@ -246,7 +246,8 @@ public class PlatformHelperImpl implements PlatformHelper { Ingredient.of(MoreConventionalTags.SKULLS), Ingredient.of(ConventionalItemTags.DYES), Ingredient.of(Items.ENDER_PEARL), - Ingredient.of(MoreConventionalTags.WOODEN_CHESTS) + Ingredient.of(MoreConventionalTags.WOODEN_CHESTS), + Ingredient.of(ConventionalItemTags.SHULKER_BOXES) ); } diff --git a/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeConventionalTagsProvider.java b/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeConventionalTagsProvider.java new file mode 100644 index 000000000..8cbce401a --- /dev/null +++ b/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeConventionalTagsProvider.java @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.data; + +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.platform.ForgeConventionalTags; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.PackOutput; +import net.minecraft.data.tags.ItemTagsProvider; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.common.data.ExistingFileHelper; + +import java.util.concurrent.CompletableFuture; + +public class ForgeConventionalTagsProvider extends ItemTagsProvider { + public ForgeConventionalTagsProvider(PackOutput output, CompletableFuture lookupProvider, CompletableFuture> blockTags, ExistingFileHelper existingFileHelper) { + super(output, lookupProvider, blockTags, ComputerCraftAPI.MOD_ID, existingFileHelper); + } + + @Override + protected void addTags(HolderLookup.Provider provider) { + tag(ForgeConventionalTags.SHULKER_BOX).add( + Items.SHULKER_BOX, + Items.WHITE_SHULKER_BOX, + Items.ORANGE_SHULKER_BOX, + Items.MAGENTA_SHULKER_BOX, + Items.LIGHT_BLUE_SHULKER_BOX, + Items.YELLOW_SHULKER_BOX, + Items.LIME_SHULKER_BOX, + Items.PINK_SHULKER_BOX, + Items.GRAY_SHULKER_BOX, + Items.LIGHT_GRAY_SHULKER_BOX, + Items.CYAN_SHULKER_BOX, + Items.PURPLE_SHULKER_BOX, + Items.BLUE_SHULKER_BOX, + Items.BROWN_SHULKER_BOX, + Items.GREEN_SHULKER_BOX, + Items.RED_SHULKER_BOX, + Items.BLACK_SHULKER_BOX + ); + } + + @Override + public String getName() { + return "Forge Conventional Item Tags"; + } +} diff --git a/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeDataProviders.java b/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeDataProviders.java index bfc57fa2b..1bc33646d 100644 --- a/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeDataProviders.java +++ b/projects/forge/src/datagen/java/dan200/computercraft/data/ForgeDataProviders.java @@ -36,7 +36,11 @@ public class ForgeDataProviders { @SubscribeEvent public static void gather(GatherDataEvent event) { var generator = event.getGenerator(); - DataProviders.add(new GeneratorFactoryImpl(generator, generator.getVanillaPack(true), event.getExistingFileHelper(), event.getLookupProvider())); + var pack = generator.getVanillaPack(true); + DataProviders.add(new GeneratorFactoryImpl(generator, pack, event.getExistingFileHelper(), event.getLookupProvider())); + pack.addProvider(o -> new ForgeConventionalTagsProvider( + o, event.getLookupProvider(), CompletableFuture.completedFuture(TagsProvider.TagLookup.empty()), event.getExistingFileHelper() + )); } private record GeneratorFactoryImpl( diff --git a/projects/forge/src/generated/resources/data/c/tags/items/shulker_box.json b/projects/forge/src/generated/resources/data/c/tags/items/shulker_box.json new file mode 100644 index 000000000..8ffa83c15 --- /dev/null +++ b/projects/forge/src/generated/resources/data/c/tags/items/shulker_box.json @@ -0,0 +1,21 @@ +{ + "values": [ + "minecraft:shulker_box", + "minecraft:white_shulker_box", + "minecraft:orange_shulker_box", + "minecraft:magenta_shulker_box", + "minecraft:light_blue_shulker_box", + "minecraft:yellow_shulker_box", + "minecraft:lime_shulker_box", + "minecraft:pink_shulker_box", + "minecraft:gray_shulker_box", + "minecraft:light_gray_shulker_box", + "minecraft:cyan_shulker_box", + "minecraft:purple_shulker_box", + "minecraft:blue_shulker_box", + "minecraft:brown_shulker_box", + "minecraft:green_shulker_box", + "minecraft:red_shulker_box", + "minecraft:black_shulker_box" + ] +} \ No newline at end of file diff --git a/projects/forge/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json b/projects/forge/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json new file mode 100644 index 000000000..1cb392abd --- /dev/null +++ b/projects/forge/src/generated/resources/resourcepacks/turtle_storage/data/computercraft/computercraft/turtle_upgrades/shulker.json @@ -0,0 +1 @@ +{"type": "computercraft:storage", "item": {"tag": "c:shulker_box"}} diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeConventionalTags.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeConventionalTags.java new file mode 100644 index 000000000..e136adca8 --- /dev/null +++ b/projects/forge/src/main/java/dan200/computercraft/shared/platform/ForgeConventionalTags.java @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.platform; + +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; + +/** + * {@code ConventionalItemTags} for Forge for cases where there's no existing one. + */ +public class ForgeConventionalTags { + public static final TagKey SHULKER_BOX = item("shulker_box"); + + private static TagKey item(String name) { + return TagKey.create(Registries.ITEM, new ResourceLocation("c", name)); + } +} 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 0872d2587..389f74ae9 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 @@ -250,7 +250,8 @@ public class PlatformHelperImpl implements PlatformHelper { Ingredient.of(Tags.Items.HEADS), Ingredient.of(Tags.Items.DYES), Ingredient.of(Tags.Items.ENDER_PEARLS), - Ingredient.of(Tags.Items.CHESTS_WOODEN) + Ingredient.of(Tags.Items.CHESTS_WOODEN), + Ingredient.of(ForgeConventionalTags.SHULKER_BOX) ); }