From 4f07d2d024cfe533e9f0c791b7f07ce20bb7b052 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Thu, 22 Oct 2026 20:09:29 +0100 Subject: [PATCH] Handle upgrade items in data fixers This is not perfect, but I think as good as we're going to get it. Because ItemStack's data is not typed in older versions, we don't apply data fixers to upgrade items (aside from the componentisation fix). This means that any migration between 3564 and 3818.5 will be skipped. --- .../api/upgrades/UpgradeData.java | 4 +- .../computercraft/mixin/DataFixersMixin.java | 4 +- .../computercraft/mixin/V1460Mixin.java | 34 ++++---- .../datafix/ComponentizationFixers.java | 87 +++++++++++++++---- .../resources/computercraft.accesswidener | 3 + .../gametest/Pocket_Computer_Test.kt | 14 ++- .../computercraft/gametest/Recipe_Test.kt | 3 + .../computercraft/gametest/Turtle_Test.kt | 39 ++++++--- .../gametest/api/TestExtensions.kt | 9 +- .../pocket_computer_test.data_fixers.snbt | 2 +- .../structures/turtle_test.data_fixers.snbt | 2 +- .../resources/META-INF/accesstransformer.cfg | 3 + 12 files changed, 149 insertions(+), 55 deletions(-) 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 59d06e8ee..a3b0d4c0e 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 @@ -143,7 +143,7 @@ public final class UpgradeData { if (obj == this) return true; return obj instanceof UpgradeData that && upgrade == that.upgrade && data.equals(that.data) - && ((stack == null && that.stack == null) || ItemStack.isSameItemSameComponents(getStack(), that.getStack())); + && ((stack == null && that.stack == null) || ItemStack.matches(getStack(), that.getStack())); } @Override @@ -153,6 +153,6 @@ public final class UpgradeData { @Override public String toString() { - return "UpgradeData[upgrade=" + upgrade.key().location() + ", data=" + data + ", stack=" + stack + "]"; + return "UpgradeData[upgrade=" + upgrade.key().location() + ", data=" + data + ", stack=" + (stack == null ? "null" : stack.getItem().toString() + stack.getComponentsPatch()) + "]"; } } diff --git a/projects/common/src/main/java/dan200/computercraft/mixin/DataFixersMixin.java b/projects/common/src/main/java/dan200/computercraft/mixin/DataFixersMixin.java index 747800701..38ae8c2ad 100644 --- a/projects/common/src/main/java/dan200/computercraft/mixin/DataFixersMixin.java +++ b/projects/common/src/main/java/dan200/computercraft/mixin/DataFixersMixin.java @@ -5,9 +5,9 @@ package dan200.computercraft.mixin; import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.schemas.Schema; +import dan200.computercraft.shared.datafix.ComponentizationFixers; import dan200.computercraft.shared.datafix.TurtleUpgradeComponentizationFix; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; @@ -37,7 +37,7 @@ abstract class DataFixersMixin { ) @SuppressWarnings("UnusedMethod") private static Schema addComponentizationFixes(Schema schema, @Local DataFixerBuilder builder) { - assertSchemaVersion(schema, DataFixUtils.makeKey(3818, 5)); + assertSchemaVersion(schema, ComponentizationFixers.SCHEMA_VERSION); builder.addFixer(new TurtleUpgradeComponentizationFix(schema)); return schema; } diff --git a/projects/common/src/main/java/dan200/computercraft/mixin/V1460Mixin.java b/projects/common/src/main/java/dan200/computercraft/mixin/V1460Mixin.java index 67abbfe42..2b3940f12 100644 --- a/projects/common/src/main/java/dan200/computercraft/mixin/V1460Mixin.java +++ b/projects/common/src/main/java/dan200/computercraft/mixin/V1460Mixin.java @@ -7,6 +7,7 @@ package dan200.computercraft.mixin; import com.mojang.datafixers.DSL; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.templates.TypeTemplate; +import dan200.computercraft.shared.datafix.ComponentizationFixers; import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity; import dan200.computercraft.shared.peripheral.printer.PrinterBlockEntity; import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; @@ -24,7 +25,7 @@ import java.util.Map; import java.util.function.Supplier; /** - * Register our item-contianing block entities. + * Register our item-containing block entities. * * @see DiskDriveBlockEntity * @see PrinterBlockEntity @@ -48,24 +49,27 @@ abstract class V1460Mixin { )); } - private static TypeTemplate upgradeData(Schema schema) { - return DSL.or( - // Pre-1.20.5 we just use the upgrade ID. - DSL.constType(NamespacedSchema.namespacedString()), - // In newer versions this is represented as a component. - DSL.optionalFields( - "item", References.ITEM_STACK.in(schema), - "components", References.DATA_COMPONENTS.in(schema) - ) - ); + private static TypeTemplate upgradeData(Schema schema, ComponentizationFixers.UpgradeKeys keys) { + if (schema.getVersionKey() >= ComponentizationFixers.SCHEMA_VERSION) { + // In newer versions this is represented in one field. + return DSL.optional(DSL.field(keys.id(), ComponentizationFixers.upgradeDataType(schema))); + } else { + // Pre-1.20.5 we store the upgrade ID and item separately + return DSL.and( + DSL.optional(DSL.field(keys.id(), DSL.constType(NamespacedSchema.namespacedString()))), + DSL.optional(DSL.field(keys.item(), References.ITEM_STACK.in(schema))) + ); + } } @Unique private static void registerTurtle(Schema schema, Map> map, String name) { - schema.register(map, name, () -> DSL.optionalFields( - "LeftUpgrade", upgradeData(schema), - "RightUpgrade", upgradeData(schema), - "Items", DSL.list(References.ITEM_STACK.in(schema)) + schema.register(map, name, () -> DSL.and( + upgradeData(schema, ComponentizationFixers.TURTLE_UPGRADE_LEFT), + upgradeData(schema, ComponentizationFixers.TURTLE_UPGRADE_RIGHT), + DSL.optionalFields( + "Items", DSL.list(References.ITEM_STACK.in(schema)) + ) )); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/datafix/ComponentizationFixers.java b/projects/common/src/main/java/dan200/computercraft/shared/datafix/ComponentizationFixers.java index 52336ff5b..567154594 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/datafix/ComponentizationFixers.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/datafix/ComponentizationFixers.java @@ -5,6 +5,7 @@ package dan200.computercraft.shared.datafix; import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.Typed; import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.types.templates.TypeTemplate; @@ -17,6 +18,8 @@ import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.media.items.PrintoutData; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.References; +import net.minecraft.util.datafix.schemas.NamespacedSchema; +import net.minecraft.util.datafix.schemas.V3818_5; import java.util.ArrayList; import java.util.Arrays; @@ -26,12 +29,19 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.minecraft.Util.writeAndReadTypedOrThrow; + /** * Additional fixers to convert CC's item NBT to use components. * * @see ItemStackComponentizationFix */ public class ComponentizationFixers { + /** + * The version of the {@link V3818_5} schema where we apply our changes. + */ + public static final int SCHEMA_VERSION = DataFixUtils.makeKey(3818, 5); + private static final String TURTLE_NORMAL = "computercraft:turtle_normal"; private static final String TURTLE_ADVANCED = "computercraft:turtle_advanced"; @@ -51,6 +61,16 @@ public class ComponentizationFixers { Stream.of(DISK) ).collect(Collectors.toUnmodifiableSet()); + public static final UpgradeKeys POCKET_UPGRADE = new UpgradeKeys("Upgrade", "UpgradeInfo"); + public static final UpgradeKeys TURTLE_UPGRADE_LEFT = new UpgradeKeys("LeftUpgrade", "LeftUpgradeNbt"); + public static final UpgradeKeys TURTLE_UPGRADE_RIGHT = new UpgradeKeys("RightUpgrade", "RightUpgradeNbt"); + + public record UpgradeKeys(String id, String item, String data) { + private UpgradeKeys(String id, String data) { + this(id, id + "Item", data); + } + } + /** * Fix components in item stacks. * @@ -67,7 +87,7 @@ public class ComponentizationFixers { if (item.is(POCKET_COMPUTERS)) { item.moveTagToComponent("On", "computercraft:on"); - moveUpgradeToComponent(item, ops, "Upgrade", "UpgradeInfo", "computercraft:pocket_upgrade"); + moveUpgradeToComponent(item, ops, POCKET_UPGRADE, "computercraft:pocket_upgrade"); // Remove instance/session, so they don't end up in minecraft:custom_data. item.removeTag("InstanceId"); @@ -79,8 +99,8 @@ public class ComponentizationFixers { item.removeTag("Overlay").result().ifPresent(x -> item.setComponent("computercraft:overlay", fixOverlay(x))); - moveUpgradeToComponent(item, ops, "LeftUpgrade", "LeftUpgradeNbt", "computercraft:left_turtle_upgrade"); - moveUpgradeToComponent(item, ops, "RightUpgrade", "RightUpgradeNbt", "computercraft:right_turtle_upgrade"); + moveUpgradeToComponent(item, ops, TURTLE_UPGRADE_LEFT, "computercraft:left_turtle_upgrade"); + moveUpgradeToComponent(item, ops, TURTLE_UPGRADE_RIGHT, "computercraft:right_turtle_upgrade"); } if (item.is(DISK)) item.moveTagToComponent("DiskId", "computercraft:disk_id"); @@ -100,11 +120,11 @@ public class ComponentizationFixers { if (item.is(PRINTOUTS)) movePrintoutToComponent(item, ops); } - private static void moveUpgradeToComponent(ItemStackComponentizationFix.ItemStackData data, Dynamic ops, String key, String dataKey, String component) { - // Rewrite {Upgrade:"foo",UpgradeData:...} to {cc:upgrade:{id:"foo", components:...}} - var upgrade = data.removeTag(key).asString(null); + private static void moveUpgradeToComponent(ItemStackComponentizationFix.ItemStackData data, Dynamic ops, UpgradeKeys keys, String component) { + // Rewrite {Upgrade:"foo",UpgradeItem:...UpgradeData:...} to {cc:upgrade:{id:"foo", "item": ..., components:...}} + var upgrade = data.removeTag(keys.id()).asString(null); if (upgrade == null) return; - data.setComponent(component, createUpgradeData(ops, upgrade, data.removeTag(dataKey))); + data.setComponent(component, createUpgradeData(ops, upgrade, data.removeTag(keys.item()), true, data.removeTag(keys.data()))); } private static void moveColourToComponent(ItemStackComponentizationFix.ItemStackData item, Dynamic ops, String key) { @@ -154,20 +174,20 @@ public class ComponentizationFixers { var input = DSL.namedChoice(name, inputSchema.getChoiceType(References.BLOCK_ENTITY, name)); var output = outputSchema.getChoiceType(References.BLOCK_ENTITY, name); - return typed -> typed.updateTyped(input, output, typed2 -> typed2.update(DSL.remainderFinder(), x -> { - x = moveUpgradeData(x, "LeftUpgrade", "LeftUpgradeNbt"); - x = moveUpgradeData(x, "RightUpgrade", "RightUpgradeNbt"); + return beData -> beData.updateTyped(input, output, turtleData -> writeAndReadTypedOrThrow(turtleData, output, x -> { + x = moveUpgradeData(x, TURTLE_UPGRADE_LEFT); + x = moveUpgradeData(x, TURTLE_UPGRADE_RIGHT); x = x.update("Overlay", ComponentizationFixers::fixOverlay); return x; })); } - private static Dynamic moveUpgradeData(Dynamic ops, String key, String dataKey) { - // Rewrite {Upgrade:"foo",UpgradeData:...} to {Upgrade:{id:"foo", components:...}} - var upgradeId = ops.get(key).asString(null); + private static Dynamic moveUpgradeData(Dynamic ops, UpgradeKeys keys) { + // Rewrite {Upgrade:"foo",UpgradeItem:...,UpgradeData:...} to {Upgrade:{id:"foo", item: ..., components:...}} + var upgradeId = ops.get(keys.id()).asString(null); if (upgradeId == null) return ops; - return ops.set(key, createUpgradeData(ops, upgradeId, ops.get(dataKey))).remove(dataKey); + return ops.set(keys.id(), createUpgradeData(ops, upgradeId, ops.get(keys.item()), false, ops.get(keys.data()))).remove(keys.item()).remove(keys.data()); } private static Dynamic fixOverlay(Dynamic overlay) { @@ -189,12 +209,23 @@ public class ComponentizationFixers { * * @param ops A {@link Dynamic} instance, for creating new dynamic values. * @param upgradeId The upgrade ID + * @param upgradeItem The item for this upgrade. + * @param convertItem Whether to also apply item-stack fixes to the upgrade item. When converting an upgrade on + * an item, DFUs are *not* applied to the nested item (as the ItemStack info does not contain + * sufficient information). However, they *are* applied when converting an upgrade on a BE, so we + * need to avoid the double-conversion. * @param upgradeData Additional upgrade data * @return The newly created {@link UpgradeData}-compatible value. */ - private static Dynamic createUpgradeData(Dynamic ops, String upgradeId, OptionalDynamic upgradeData) { + private static Dynamic createUpgradeData(Dynamic ops, String upgradeId, OptionalDynamic upgradeItem, boolean convertItem, OptionalDynamic upgradeData) { var newUpgrade = ops.emptyMap().set("id", ops.createString(upgradeId)); + // Migrate upgrade item + var item = upgradeItem.result().orElse(null); + if (item != null) { + newUpgrade = newUpgrade.set("item", convertItem ? fixItem(item) : item); + } + var data = upgradeData.result().orElse(null); if (data != null && !data.equals(ops.emptyMap())) { // Migrate all existing data to minecraft:custom_data @@ -204,6 +235,15 @@ public class ComponentizationFixers { return newUpgrade; } + private static Dynamic fixItem(Dynamic dynamic) { + var parsedData = ItemStackComponentizationFix.ItemStackData.read(dynamic); + if (parsedData.isEmpty()) return dynamic; + + var data = parsedData.get(); + ItemStackComponentizationFix.fixItemStack(data, data.tag); + return data.write(); + } + /** * Add our custom data components to the datafixer system. * @@ -217,8 +257,7 @@ public class ComponentizationFixers { */ public static TypeTemplate addExtraTypes(TypeTemplate type, Schema schema) { // Create a codec for UpgradeData - var upgradeData = DSL.optionalFields("components", References.DATA_COMPONENTS.in(schema)); - + var upgradeData = upgradeDataType(schema); return extraOptionalFields(type, Pair.of("computercraft:pocket_upgrade", upgradeData), Pair.of("computercraft:left_turtle_upgrade", upgradeData), @@ -226,6 +265,20 @@ public class ComponentizationFixers { ); } + /** + * Get the {@link TypeTemplate} for our {@link UpgradeData}. + * + * @param schema The current schema + * @return The upgrade data. + */ + public static TypeTemplate upgradeDataType(Schema schema) { + return DSL.optionalFields( + "id", DSL.constType(NamespacedSchema.namespacedString()), + "item", References.ITEM_STACK.in(schema), + "components", References.DATA_COMPONENTS.in(schema) + ); + } + @SafeVarargs @SuppressWarnings("varargs") private static TypeTemplate extraOptionalFields(TypeTemplate base, Pair... fields) { diff --git a/projects/common/src/main/resources/computercraft.accesswidener b/projects/common/src/main/resources/computercraft.accesswidener index 081b21533..243dd3d01 100644 --- a/projects/common/src/main/resources/computercraft.accesswidener +++ b/projects/common/src/main/resources/computercraft.accesswidener @@ -33,4 +33,7 @@ accessible field net/minecraft/client/sounds/SoundEngine executor Lnet/minecraft # Turtle model accessible method net/minecraft/client/renderer/block/model/ItemOverrides ()V +# Data fixers +accessible method net/minecraft/util/datafix/fixes/ItemStackComponentizationFix fixItemStack (Lnet/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData;Lcom/mojang/serialization/Dynamic;)V accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData +accessible field net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData tag Lcom/mojang/serialization/Dynamic; diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt index f396a8599..0cf20c23f 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Pocket_Computer_Test.kt @@ -24,6 +24,7 @@ import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper import net.minecraft.gametest.framework.GameTestSequence import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.world.item.ItemStack import org.junit.jupiter.api.Assertions.assertEquals @@ -119,9 +120,13 @@ class Pocket_Computer_Test { @GameTest fun Data_fixers(helper: GameTestHelper) = helper.sequence { thenExecute { - val upgrade = helper.level.registryAccess().registryOrThrow(IPocketUpgrade.REGISTRY) - .getHolder(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "wireless_modem_normal")) - .orElseThrow() + val upgrade = UpgradeData.of( + helper.level.registryAccess().getOrThrow( + ResourceKey.create(IPocketUpgrade.REGISTRY, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "wireless_modem_advanced")), + ), + DataComponentUtil.createStack(ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get(), DataComponents.CUSTOM_NAME, Component.literal("My favourite modem")), + DataComponentPatch.EMPTY, + ) helper.assertContainerExactly( BlockPos(2, 2, 2), @@ -131,7 +136,8 @@ class Pocket_Computer_Test { it.applyComponents( DataComponentPatch.builder() .set(ModRegistry.DataComponents.COMPUTER_ID.get(), NonNegativeId(123)) - .set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), UpgradeData.ofDefault(upgrade)) + .set(ModRegistry.DataComponents.POCKET_UPGRADE.get(), upgrade) + .set(ModRegistry.DataComponents.ON.get(), false) .build(), ) }, diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt index 919b13bdd..327164c0a 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt @@ -67,6 +67,9 @@ class Recipe_Test { val pocketUpgrades = registries.lookupOrThrow(IPocketUpgrade.REGISTRY) val generator = UpgradeRecipeGenerator({ it }, registries) + println("Got packs => " + context.level.server.packRepository.selectedIds) + println("Got items => " + turtleUpgrades.listElementIds().toList()) + fun checkUsage(message: String, size: Int, item: ItemStack) { val recipes = generator.findRecipesWithInput(item) assertEquals(size, recipes.size, message) diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt index 1ca31b151..369849552 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt @@ -28,21 +28,26 @@ import dan200.computercraft.shared.turtle.TurtleOverlay import dan200.computercraft.shared.turtle.apis.TurtleAPI import dan200.computercraft.shared.turtle.core.TurtleCraftCommand import dan200.computercraft.shared.turtle.items.TurtleItem +import dan200.computercraft.shared.util.DataComponentUtil import dan200.computercraft.shared.util.WaterloggableHelpers import dan200.computercraft.test.core.assertArrayEquals import dan200.computercraft.test.core.computer.LuaTaskContext import dan200.computercraft.test.core.computer.getApi import dan200.computercraft.test.shared.ItemStackMatcher.isStack import net.minecraft.core.BlockPos +import net.minecraft.core.component.DataComponentPatch +import net.minecraft.core.component.DataComponents import net.minecraft.core.registries.Registries import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.item.PrimedTnt import net.minecraft.world.item.BlockItem import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items +import net.minecraft.world.item.component.ItemContainerContents import net.minecraft.world.item.enchantment.Enchantments import net.minecraft.world.level.block.BeehiveBlock import net.minecraft.world.level.block.Blocks @@ -324,8 +329,7 @@ class Turtle_Test { val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access val upgrade = turtle.getUpgrade(TurtleSide.LEFT) assertEquals( - helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY) - .get(ResourceLocation.fromNamespaceAndPath("cctest", "wooden_pickaxe")), + helper.level.registryAccess().getOrThrow(WOODEN_PICKAXE).value(), upgrade, "Upgrade is a wooden pickaxe", ) @@ -352,10 +356,7 @@ class Turtle_Test { helper.assertUpgradeItem( ItemStack(Items.WOODEN_PICKAXE), - UpgradeData.ofDefault( - helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY) - .getHolder(ResourceLocation.fromNamespaceAndPath("cctest", "wooden_pickaxe")).orElseThrow(), - ), + UpgradeData.ofDefault(helper.level.registryAccess().getOrThrow(WOODEN_PICKAXE)), ) } } @@ -773,16 +774,27 @@ class Turtle_Test { thenExecute { val overlay = helper.level.registryAccess().registryOrThrow(TurtleOverlay.REGISTRY) .get(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "trans_flag"))!! - val upgrade = helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY) - .get(ResourceLocation.withDefaultNamespace("diamond_pickaxe"))!! + + val pickaxeUpgrade = UpgradeData.ofDefault( + helper.level.registryAccess().getOrThrow(id(ResourceLocation.withDefaultNamespace("diamond_pickaxe"))), + ) + + val shulkerUpgrade = UpgradeData.of( + helper.level.registryAccess() + .getOrThrow(id(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "shulker"))), + DataComponentUtil.createStack(Items.SHULKER_BOX, DataComponents.CONTAINER, ItemContainerContents.fromItems(listOf(ItemStack(Items.DIRT)))), + DataComponentPatch.EMPTY, + ) val turtleBe = helper.getBlockEntity(BlockPos(1, 2, 1), ModRegistry.BlockEntities.TURTLE_NORMAL.get()) assertEquals(overlay, turtleBe.overlay) - assertEquals(upgrade, turtleBe.getUpgrade(TurtleSide.LEFT)) + assertEquals(pickaxeUpgrade, turtleBe.access.getUpgradeWithData(TurtleSide.LEFT)) + assertEquals(shulkerUpgrade, turtleBe.access.getUpgradeWithData(TurtleSide.RIGHT)) val turtleItem = turtleBe.getItem(0) assertEquals(overlay, TurtleItem.getOverlay(turtleItem)) - assertEquals(upgrade, TurtleItem.getUpgrade(turtleItem, TurtleSide.LEFT)) + assertEquals(pickaxeUpgrade, TurtleItem.getUpgradeWithData(turtleItem, TurtleSide.LEFT)) + assertEquals(shulkerUpgrade, TurtleItem.getUpgradeWithData(turtleItem, TurtleSide.RIGHT)) } } @@ -1070,6 +1082,13 @@ class Turtle_Test { thenExecute { helper.positionAtArmorStand() } thenScreenshot() } + + companion object { + private fun id(key: ResourceLocation): ResourceKey = + ResourceKey.create(ITurtleUpgrade.REGISTRY, key) + + private val WOODEN_PICKAXE = id(ResourceLocation.fromNamespaceAndPath("cctest", "wooden_pickaxe")) + } } private val LuaTaskContext.turtle get() = getApi() diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt index ecc70d6f8..54481f368 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt @@ -13,11 +13,10 @@ import dan200.computercraft.shared.util.RegistryHelper import dan200.computercraft.test.core.computer.LuaTaskContext import dan200.computercraft.test.shared.ItemStackMatcher.isStack import net.minecraft.commands.arguments.blocks.BlockInput -import net.minecraft.core.BlockPos -import net.minecraft.core.Direction -import net.minecraft.core.NonNullList +import net.minecraft.core.* import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.gametest.framework.* +import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.world.Container import net.minecraft.world.InteractionHand @@ -423,3 +422,7 @@ inline fun tryMultipleTimes(count: Int, action: () -> Unit) { } } } + +/** Find an entry in a registry provider. */ +fun HolderLookup.Provider.getOrThrow(key: ResourceKey): Holder.Reference = + lookupOrThrow(key.registryKey()).getOrThrow(key) diff --git a/projects/common/src/testMod/resources/data/cctest/structures/pocket_computer_test.data_fixers.snbt b/projects/common/src/testMod/resources/data/cctest/structures/pocket_computer_test.data_fixers.snbt index 55b386357..91a7f82a4 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/pocket_computer_test.data_fixers.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/pocket_computer_test.data_fixers.snbt @@ -27,7 +27,7 @@ {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 1, 2], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {Items: [{Count: 1b, Slot: 0b, id: "computercraft:pocket_computer_advanced", tag: {ComputerId: 123, Upgrade: "computercraft:wireless_modem_normal", display: {Name: '{"text":"Test"}'}}}], id: "minecraft:chest"}} + {pos: [2, 1, 2], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {Items: [{Count: 1b, Slot: 0b, id: "computercraft:pocket_computer_advanced", tag: {ComputerId: 123, InstanceId: [I; -1496601984, 1527793399, -1542736776, 2137516638], On: 0b, SessionId: 1591798634, Upgrade: "computercraft:wireless_modem_advanced", UpgradeItem: {Count: 1b, id: "computercraft:wireless_modem_advanced", tag: {RepairCost: 0, display: {Name: '{"text":"My favourite modem"}'}}}, display: {Name: '{"text":"Test"}'}}}], id: "minecraft:chest"}} ], entities: [], palette: [ diff --git a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.data_fixers.snbt b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.data_fixers.snbt index 49aae1e36..4c161a0a8 100644 --- a/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.data_fixers.snbt +++ b/projects/common/src/testMod/resources/data/cctest/structures/turtle_test.data_fixers.snbt @@ -11,7 +11,7 @@ {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 123, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:turtle_normal", tag: {ComputerId: 123, LeftUpgrade: "minecraft:diamond_pickaxe", Overlay: "computercraft:block/turtle_trans_overlay"}}], LeftUpgrade: "minecraft:diamond_pickaxe", LeftUpgradeNbt: {}, On: 0b, Overlay: "computercraft:block/turtle_trans_overlay", Owner: {LowerId: -4770154215762454977L, Name: "Player436", UpperId: 114963728012426084L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 123, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:turtle_normal", tag: {ComputerId: 123, LeftUpgrade: "minecraft:diamond_pickaxe", LeftUpgradeItem: {Count: 1b, id: "minecraft:diamond_pickaxe", tag: {Damage: 0}}, Overlay: "computercraft:block/turtle_trans_overlay", RightUpgrade: "computercraft:shulker", RightUpgradeItem: {Count: 1b, id: "minecraft:shulker_box", tag: {BlockEntityTag: {Items: [{Count: 1b, Slot: 0b, id: "minecraft:dirt"}], id: "minecraft:shulker_box"}}}}}], LeftUpgrade: "minecraft:diamond_pickaxe", LeftUpgradeItem: {Count: 1b, id: "minecraft:diamond_pickaxe", tag: {Damage: 0}}, On: 1b, Overlay: "computercraft:block/turtle_trans_overlay", Owner: {LowerId: -4770154215762454977L, Name: "Player436", UpperId: 114963728012426084L}, RightUpgrade: "computercraft:shulker", RightUpgradeItem: {Count: 1b, id: "minecraft:shulker_box", tag: {BlockEntityTag: {Items: [{Count: 1b, Slot: 0b, id: "minecraft:dirt"}], id: "minecraft:shulker_box"}}}, Slot: 0, id: "computercraft:turtle_normal"}} ], entities: [], palette: [ diff --git a/projects/forge/src/main/resources/META-INF/accesstransformer.cfg b/projects/forge/src/main/resources/META-INF/accesstransformer.cfg index dcfea532f..297bfe7ad 100644 --- a/projects/forge/src/main/resources/META-INF/accesstransformer.cfg +++ b/projects/forge/src/main/resources/META-INF/accesstransformer.cfg @@ -33,4 +33,7 @@ public net.minecraft.data.models.ItemModelGenerators generateFlatItem(Lnet/minec public net.minecraft.data.models.ItemModelGenerators generateFlatItem(Lnet/minecraft/world/item/Item;Ljava/lang/String;Lnet/minecraft/data/models/model/ModelTemplate;)V public net.minecraft.data.models.model.TextureSlot create(Ljava/lang/String;)Lnet/minecraft/data/models/model/TextureSlot; +# Data fixers +public net.minecraft.util.datafix.fixes.ItemStackComponentizationFix fixItemStack(Lnet/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData;Lcom/mojang/serialization/Dynamic;)V public net.minecraft.util.datafix.fixes.ItemStackComponentizationFix$ItemStackData +public net.minecraft.util.datafix.fixes.ItemStackComponentizationFix$ItemStackData tag